Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  emux_seq.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  Midi Sequencer interface routines.
 *
 *  Copyright (C) 1999 Steve Ratcliffe
 *  Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de>
 */


#include "emux_voice.h"
#include <linux/slab.h>
#include <linux/module.h>

/* Prototypes for static functions */
static void free_port(void *private);
static void snd_emux_init_port(struct snd_emux_port *p);
static int snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info);
static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info);

/*
 * MIDI emulation operators
 */

static const struct snd_midi_op emux_ops = {
 .note_on = snd_emux_note_on,
 .note_off = snd_emux_note_off,
 .key_press = snd_emux_key_press,
 .note_terminate = snd_emux_terminate_note,
 .control = snd_emux_control,
 .nrpn = snd_emux_nrpn,
 .sysex = snd_emux_sysex,
};


/*
 * number of MIDI channels
 */

#define MIDI_CHANNELS  16

/*
 * type flags for MIDI sequencer port
 */

#define DEFAULT_MIDI_TYPE (SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |\
     SNDRV_SEQ_PORT_TYPE_MIDI_GM |\
     SNDRV_SEQ_PORT_TYPE_MIDI_GS |\
     SNDRV_SEQ_PORT_TYPE_MIDI_XG |\
     SNDRV_SEQ_PORT_TYPE_HARDWARE |\
     SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)

/*
 * Initialise the EMUX Synth by creating a client and registering
 * a series of ports.
 * Each of the ports will contain the 16 midi channels.  Applications
 * can connect to these ports to play midi data.
 */

int
snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index)
{
 int  i;
 struct snd_seq_port_callback pinfo;
 char tmpname[64];

 emu->client = snd_seq_create_kernel_client(card, index,
         "%s WaveTable", emu->name);
 if (emu->client < 0) {
  dev_err(card->dev, "can't create client\n");
  return -ENODEV;
 }

 if (emu->num_ports <= 0) {
  dev_warn(card->dev, "seqports must be greater than zero\n");
  emu->num_ports = 1;
 } else if (emu->num_ports > SNDRV_EMUX_MAX_PORTS) {
  dev_warn(card->dev,
    "too many ports. limited max. ports %d\n",
    SNDRV_EMUX_MAX_PORTS);
  emu->num_ports = SNDRV_EMUX_MAX_PORTS;
 }

 memset(&pinfo, 0, sizeof(pinfo));
 pinfo.owner = THIS_MODULE;
 pinfo.use = snd_emux_use;
 pinfo.unuse = snd_emux_unuse;
 pinfo.event_input = snd_emux_event_input;

 for (i = 0; i < emu->num_ports; i++) {
  struct snd_emux_port *p;

  sprintf(tmpname, "%s Port %d", emu->name, i);
  p = snd_emux_create_port(emu, tmpname, MIDI_CHANNELS,
      0, &pinfo);
  if (!p) {
   dev_err(card->dev, "can't create port\n");
   return -ENOMEM;
  }

  p->port_mode =  SNDRV_EMUX_PORT_MODE_MIDI;
  snd_emux_init_port(p);
  emu->ports[i] = p->chset.port;
  emu->portptrs[i] = p;
 }

 return 0;
}


/*
 * Detach from the ports that were set up for this synthesizer and
 * destroy the kernel client.
 */

void
snd_emux_detach_seq(struct snd_emux *emu)
{
 if (emu->voices)
  snd_emux_terminate_all(emu);
  
 if (emu->client >= 0) {
  snd_seq_delete_kernel_client(emu->client);
  emu->client = -1;
 }
}


/*
 * create a sequencer port and channel_set
 */


struct snd_emux_port *
snd_emux_create_port(struct snd_emux *emu, char *name,
       int max_channels, int oss_port,
       struct snd_seq_port_callback *callback)
{
 struct snd_emux_port *p;
 int i, type, cap;

 /* Allocate structures for this channel */
 p = kzalloc(sizeof(*p), GFP_KERNEL);
 if (!p)
  return NULL;

 p->chset.channels = kcalloc(max_channels, sizeof(*p->chset.channels),
        GFP_KERNEL);
 if (!p->chset.channels) {
  kfree(p);
  return NULL;
 }
 for (i = 0; i < max_channels; i++)
  p->chset.channels[i].number = i;
 p->chset.private_data = p;
 p->chset.max_channels = max_channels;
 p->emu = emu;
 p->chset.client = emu->client;
#ifdef SNDRV_EMUX_USE_RAW_EFFECT
 snd_emux_create_effect(p);
#endif
 callback->private_free = free_port;
 callback->private_data = p;

 cap = SNDRV_SEQ_PORT_CAP_WRITE;
 if (oss_port) {
  type = SNDRV_SEQ_PORT_TYPE_SPECIFIC;
 } else {
  type = DEFAULT_MIDI_TYPE;
  cap |= SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
 }

 p->chset.port = snd_seq_event_port_attach(emu->client, callback,
        cap, type, max_channels,
        emu->max_voices, name);

 return p;
}


/*
 * release memory block for port
 */

static void
free_port(void *private_data)
{
 struct snd_emux_port *p;

 p = private_data;
 if (p) {
#ifdef SNDRV_EMUX_USE_RAW_EFFECT
  snd_emux_delete_effect(p);
#endif
  kfree(p->chset.channels);
  kfree(p);
 }
}


#define DEFAULT_DRUM_FLAGS (1<<9)

/*
 * initialize the port specific parameters
 */

static void
snd_emux_init_port(struct snd_emux_port *p)
{
 p->drum_flags = DEFAULT_DRUM_FLAGS;
 p->volume_atten = 0;

 snd_emux_reset_port(p);
}


/*
 * reset port
 */

void
snd_emux_reset_port(struct snd_emux_port *port)
{
 int i;

 /* stop all sounds */
 snd_emux_sounds_off_all(port);

 snd_midi_channel_set_clear(&port->chset);

#ifdef SNDRV_EMUX_USE_RAW_EFFECT
 snd_emux_clear_effect(port);
#endif

 /* set port specific control parameters */
 port->ctrls[EMUX_MD_DEF_BANK] = 0;
 port->ctrls[EMUX_MD_DEF_DRUM] = 0;
 port->ctrls[EMUX_MD_REALTIME_PAN] = 1;

 for (i = 0; i < port->chset.max_channels; i++) {
  struct snd_midi_channel *chan = port->chset.channels + i;
  chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0;
 }
}


/*
 * input sequencer event
 */

int
snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data,
       int atomic, int hop)
{
 struct snd_emux_port *port;

 port = private_data;
 if (snd_BUG_ON(!port || !ev))
  return -EINVAL;

 snd_midi_process_event(&emux_ops, ev, &port->chset);

 return 0;
}


/*
 * increment usage count
 */

static int
__snd_emux_inc_count(struct snd_emux *emu)
{
 emu->used++;
 if (!try_module_get(emu->ops.owner))
  goto __error;
 if (!try_module_get(emu->card->module)) {
  module_put(emu->ops.owner);
       __error:
  emu->used--;
  return 0;
 }
 return 1;
}

int snd_emux_inc_count(struct snd_emux *emu)
{
 int ret;

 mutex_lock(&emu->register_mutex);
 ret = __snd_emux_inc_count(emu);
 mutex_unlock(&emu->register_mutex);
 return ret;
}

/*
 * decrease usage count
 */

static void
__snd_emux_dec_count(struct snd_emux *emu)
{
 module_put(emu->card->module);
 emu->used--;
 if (emu->used <= 0)
  snd_emux_terminate_all(emu);
 module_put(emu->ops.owner);
}

void snd_emux_dec_count(struct snd_emux *emu)
{
 mutex_lock(&emu->register_mutex);
 __snd_emux_dec_count(emu);
 mutex_unlock(&emu->register_mutex);
}

/*
 * Routine that is called upon a first use of a particular port
 */

static int
snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info)
{
 struct snd_emux_port *p;
 struct snd_emux *emu;

 p = private_data;
 if (snd_BUG_ON(!p))
  return -EINVAL;
 emu = p->emu;
 if (snd_BUG_ON(!emu))
  return -EINVAL;

 mutex_lock(&emu->register_mutex);
 snd_emux_init_port(p);
 __snd_emux_inc_count(emu);
 mutex_unlock(&emu->register_mutex);
 return 0;
}

/*
 * Routine that is called upon the last unuse() of a particular port.
 */

static int
snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info)
{
 struct snd_emux_port *p;
 struct snd_emux *emu;

 p = private_data;
 if (snd_BUG_ON(!p))
  return -EINVAL;
 emu = p->emu;
 if (snd_BUG_ON(!emu))
  return -EINVAL;

 mutex_lock(&emu->register_mutex);
 snd_emux_sounds_off_all(p);
 __snd_emux_dec_count(emu);
 mutex_unlock(&emu->register_mutex);
 return 0;
}


/*
 * attach virtual rawmidi devices
 */

int snd_emux_init_virmidi(struct snd_emux *emu, struct snd_card *card)
{
 int i;

 emu->vmidi = NULL;
 if (emu->midi_ports <= 0)
  return 0;

 emu->vmidi = kcalloc(emu->midi_ports, sizeof(*emu->vmidi), GFP_KERNEL);
 if (!emu->vmidi)
  return -ENOMEM;

 for (i = 0; i < emu->midi_ports; i++) {
  struct snd_rawmidi *rmidi;
  struct snd_virmidi_dev *rdev;
  if (snd_virmidi_new(card, emu->midi_devidx + i, &rmidi) < 0)
   goto __error;
  rdev = rmidi->private_data;
  sprintf(rmidi->name, "%s Synth MIDI", emu->name);
  rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH;
  rdev->client = emu->client;
  rdev->port = emu->ports[i];
  if (snd_device_register(card, rmidi) < 0) {
   snd_device_free(card, rmidi);
   goto __error;
  }
  emu->vmidi[i] = rmidi;
 }
 return 0;

__error:
 snd_emux_delete_virmidi(emu);
 return -ENOMEM;
}

int snd_emux_delete_virmidi(struct snd_emux *emu)
{
 int i;

 if (!emu->vmidi)
  return 0;

 for (i = 0; i < emu->midi_ports; i++) {
  if (emu->vmidi[i])
   snd_device_free(emu->card, emu->vmidi[i]);
 }
 kfree(emu->vmidi);
 emu->vmidi = NULL;
 return 0;
}

Messung V0.5
C=92 H=97 G=94

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge