void MidiAlsaDevice::close() { snd_seq_port_subscribe_t* subs; // Allocated on stack, no need to call snd_seq_port_subscribe_free() later. snd_seq_port_subscribe_alloca(&subs); // Changed by T356. This function appears to be called only by MidiPort::setMidiDevice(), // which closes then opens the device. // Because the open flags are set BEFORE setMidiDevice() is called, we must ignore the flags. // // NOTE: Tested: The read unsubscribe works ok but not the write. // As viewed in say, qjackctl, the connection is clearly lost, // but strangely the events are still accepted, ie, playback notes // are still heard etc. Tried an alsa midi device AND external fluidsynth inst. // // Also, jack running and with jack midi disabled, we get messages like // MidiAlsaDevice::0x84512c0 putEvent(): midi write error: No such device // dst 16:0 // only sometimes (not when playing notes), but with jack midi turned on, // we don't get the messages. With jack stopped we get the messages // no matter if jack midi is turned on or not. //if (_openFlags & 1) { //if (!(_openFlags & 1)) { snd_seq_port_subscribe_set_sender(subs, &losPort); snd_seq_port_subscribe_set_dest(subs, &adr); // Already subscribed? Then unsubscribe. if (!snd_seq_get_port_subscription(alsaSeq, subs)) { if (!snd_seq_unsubscribe_port(alsaSeq, subs)) _writeEnable = false; else printf("MidiAlsaDevice::close Error unsubscribing alsa midi port for writing\n"); } else _writeEnable = false; } //if (_openFlags & 2) { //if (!(_openFlags & 2)) { snd_seq_port_subscribe_set_dest(subs, &losPort); snd_seq_port_subscribe_set_sender(subs, &adr); // Already subscribed? Then unsubscribe. if (!snd_seq_get_port_subscription(alsaSeq, subs)) { if (!snd_seq_unsubscribe_port(alsaSeq, subs)) _readEnable = false; else printf("MidiAlsaDevice::close Error unsubscribing alsa midi port for reading\n"); } else _readEnable = false; } }
/* * remove all (exported) connections */ static void remove_connection(snd_seq_t *seq, snd_seq_client_info_t *cinfo, snd_seq_port_info_t *pinfo, int count) { snd_seq_query_subscribe_t *query; snd_seq_query_subscribe_alloca(&query); snd_seq_query_subscribe_set_root(query, snd_seq_port_info_get_addr(pinfo)); snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_READ); snd_seq_query_subscribe_set_index(query, 0); for (; snd_seq_query_port_subscribers(seq, query) >= 0; snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1)) { snd_seq_port_info_t *port; snd_seq_port_subscribe_t *subs; const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_root(query); const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_addr(query); snd_seq_port_info_alloca(&port); if (snd_seq_get_any_port_info(seq, dest->client, dest->port, port) < 0) continue; if (!(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_WRITE)) continue; if (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT) continue; snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query)); snd_seq_port_subscribe_set_sender(subs, sender); snd_seq_port_subscribe_set_dest(subs, dest); snd_seq_unsubscribe_port(seq, subs); } snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_WRITE); snd_seq_query_subscribe_set_index(query, 0); for (; snd_seq_query_port_subscribers(seq, query) >= 0; snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1)) { snd_seq_port_info_t *port; snd_seq_port_subscribe_t *subs; const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_root(query); const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_addr(query); snd_seq_port_info_alloca(&port); if (snd_seq_get_any_port_info(seq, sender->client, sender->port, port) < 0) continue; if (!(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_READ)) continue; if (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT) continue; snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query)); snd_seq_port_subscribe_set_sender(subs, sender); snd_seq_port_subscribe_set_dest(subs, dest); snd_seq_unsubscribe_port(seq, subs); } }
QString MidiAlsaDevice::open() { _openFlags &= _rwFlags; // restrict to available bits snd_seq_port_subscribe_t* subs; // Allocated on stack, no need to call snd_seq_port_subscribe_free() later. snd_seq_port_subscribe_alloca(&subs); QString estr; int wer = 0; int rer = 0; // subscribe for writing if (_openFlags & 1) { snd_seq_port_subscribe_set_sender(subs, &losPort); snd_seq_port_subscribe_set_dest(subs, &adr); // Not already subscribed (or error)? Then try subscribing. if (snd_seq_get_port_subscription(alsaSeq, subs) < 0) { wer = snd_seq_subscribe_port(alsaSeq, subs); if (wer < 0) estr += (QString("Play: ") + QString(snd_strerror(wer)) + QString(" ")); } if (!wer) _writeEnable = true; } // subscribe for reading if (_openFlags & 2) { snd_seq_port_subscribe_set_dest(subs, &losPort); snd_seq_port_subscribe_set_sender(subs, &adr); // Not already subscribed (or error)? Then try subscribing. if (snd_seq_get_port_subscription(alsaSeq, subs) < 0) { //int error = snd_seq_subscribe_port(alsaSeq, subs); rer = snd_seq_subscribe_port(alsaSeq, subs); if (rer < 0) estr += (QString("Rec: ") + QString(snd_strerror(rer))); } if (!rer) _readEnable = true; } if (wer < 0 || rer < 0) return estr; return QString("OK"); }
/* Remote device name is saved after first call (or rather the pointer to it, * so the actual string must not be deallocated); subsequent calls may use * NULL as the remote_device. */ int midi_connect(int port, const char *remote_device) { snd_seq_port_subscribe_t *sub; snd_seq_addr_t my_addr; snd_seq_addr_t remote_addr; static const char *saved_remote_device[MAX_PORTS] = { 0 }; if (port >= MAX_PORTS) return -1; if (remote_device) saved_remote_device[port] = remote_device; else if (!saved_remote_device[port]) /* Set to "" if first call does not intitialize it to remote_device */ saved_remote_device[port] = ""; dprintf("Client address %d:%d\n", client, port); snd_seq_port_subscribe_alloca(&sub); /* My address */ my_addr.client = client; my_addr.port = ports[port]; /* Other devices address */ if (snd_seq_parse_address(seq, &remote_addr, saved_remote_device[port]) < 0) { dprintf("Can't locate destination device %s\n", saved_remote_device[port]); return -1; } /* We always attempt to set up subscription in both directions, regardless * of which error occurs when setting up the first direction. */ /* Set up sender and destination in subscription. */ snd_seq_port_subscribe_set_sender(sub, &my_addr); snd_seq_port_subscribe_set_dest(sub, &remote_addr); int res = subscribe(sub); /* And now, connection in other direction. */ snd_seq_port_subscribe_set_sender(sub, &remote_addr); snd_seq_port_subscribe_set_dest(sub, &my_addr); int res2 = subscribe(sub); if (res == 0) res = res2; /* if first subscribe() had no error */ return res; }
bool midibus::deinit_in( ) { /* temp return */ int ret; snd_seq_port_subscribe_t *subs; snd_seq_port_subscribe_alloca(&subs); snd_seq_addr_t sender, dest; /* the destinatino port is actually our local port */ sender.client = m_dest_addr_client; sender.port = m_dest_addr_port; dest.client = m_local_addr_client; dest.port = m_local_addr_port; /* set in and out ports */ snd_seq_port_subscribe_set_sender(subs, &sender); snd_seq_port_subscribe_set_dest(subs, &dest); /* use the master queue, and get ticks */ snd_seq_port_subscribe_set_queue(subs, m_queue); snd_seq_port_subscribe_set_time_update(subs, 1); /* subscribe */ ret = snd_seq_unsubscribe_port(m_seq, subs); if ( ret < 0 ){ printf( "snd_seq_unsubscribe_port(%d:%d) error\n", m_dest_addr_client, m_dest_addr_port); return false; } return true; }
static int a2j_alsa_connect_from (alsa_midi_driver_t * driver, int client, int port) { snd_seq_port_subscribe_t* sub; snd_seq_addr_t seq_addr; int err; snd_seq_port_subscribe_alloca (&sub); seq_addr.client = client; seq_addr.port = port; snd_seq_port_subscribe_set_sender (sub, &seq_addr); seq_addr.client = driver->client_id; seq_addr.port = driver->port_id; snd_seq_port_subscribe_set_dest (sub, &seq_addr); snd_seq_port_subscribe_set_time_update (sub, 1); snd_seq_port_subscribe_set_queue (sub, driver->queue); snd_seq_port_subscribe_set_time_real (sub, 1); if ((err = snd_seq_subscribe_port (driver->seq, sub))) { a2j_error ("can't subscribe to %d:%d - %s", client, port, snd_strerror(err)); } return err; }
bool midibus::deinit_in () { #ifdef SEQ64_HAVE_LIBASOUND snd_seq_port_subscribe_t * subs; snd_seq_port_subscribe_alloca(&subs); snd_seq_addr_t sender; /* output */ sender.client = m_dest_addr_client; sender.port = m_dest_addr_port; snd_seq_port_subscribe_set_sender(subs, &sender); snd_seq_addr_t dest; /* input */ dest.client = m_local_addr_client; dest.port = m_local_addr_port; snd_seq_port_subscribe_set_dest(subs, &dest); snd_seq_port_subscribe_set_queue(subs, m_queue); /* master queue */ snd_seq_port_subscribe_set_time_update(subs, 1); /* get ticks */ int result = snd_seq_unsubscribe_port(m_seq, subs); /* subscribe */ if (result < 0) { fprintf ( stderr, "snd_seq_unsubscribe_port(%d:%d) error\n", m_dest_addr_client, m_dest_addr_port ); return false; } #endif // SEQ64_HAVE_LIBASOUND return true; }
bool midibus::init_in () { #ifdef HAVE_LIBASOUND int result = snd_seq_create_simple_port /* create ports */ ( m_seq, "seq24 in", SND_SEQ_PORT_CAP_NO_EXPORT | SND_SEQ_PORT_CAP_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION ); m_local_addr_port = result; if (result < 0) { errprint("snd_seq_create_simple_port(read) error"); return false; } snd_seq_port_subscribe_t * subs; snd_seq_port_subscribe_alloca(&subs); snd_seq_addr_t sender; snd_seq_addr_t dest; /* the destination port is actually our local port */ sender.client = m_dest_addr_client; sender.port = m_dest_addr_port; dest.client = m_local_addr_client; dest.port = m_local_addr_port; /* set in and out ports */ snd_seq_port_subscribe_set_sender(subs, &sender); snd_seq_port_subscribe_set_dest(subs, &dest); /* use the master queue, and get ticks */ snd_seq_port_subscribe_set_queue(subs, m_queue); snd_seq_port_subscribe_set_time_update(subs, 1); /* subscribe */ result = snd_seq_subscribe_port(m_seq, subs); if (result < 0) { fprintf ( stderr, "snd_seq_connect_from(%d:%d) error\n", m_dest_addr_client, m_dest_addr_port ); return false; } #endif // HAVE_LIBASOUND return true; }
void MIDIOut::unsubscribeDevice(MIDIDevice* device) { snd_seq_port_subscribe_t* sub = NULL; Q_ASSERT(device != NULL); Q_ASSERT(m_address != NULL); snd_seq_port_subscribe_alloca(&sub); snd_seq_port_subscribe_set_sender(sub, m_address); snd_seq_port_subscribe_set_dest(sub, device->address()); snd_seq_unsubscribe_port(m_alsa, sub); }
void AlsaMidiInputThread::unsubscribeDevice(AlsaMidiInputDevice* device) { qDebug() << Q_FUNC_INFO; Q_ASSERT(device != NULL); /* Unsubscribe events from the device */ snd_seq_port_subscribe_t* sub = NULL; snd_seq_port_subscribe_alloca(&sub); snd_seq_port_subscribe_set_sender(sub, device->address()); snd_seq_port_subscribe_set_dest(sub, m_destinationAddress); snd_seq_unsubscribe_port(m_alsa, sub); }
void AlsaMidiInputThread::subscribeDevice(AlsaMidiInputDevice* device) { qDebug() << Q_FUNC_INFO; Q_ASSERT(device != NULL); /* Subscribe events coming from the the device's MIDI port to get patched to the plugin's own MIDI port */ snd_seq_port_subscribe_t* sub = NULL; snd_seq_port_subscribe_alloca(&sub); snd_seq_port_subscribe_set_sender(sub, device->address()); snd_seq_port_subscribe_set_dest(sub, m_destinationAddress); snd_seq_subscribe_port(m_alsa, sub); }
void AlsaMidiOutputDevice::close() { qDebug() << Q_FUNC_INFO; m_open = false; Q_ASSERT(m_sender_address != NULL); Q_ASSERT(m_receiver_address != NULL); /* Unsubscribe QLC+ ALSA client to the MIDI device */ snd_seq_port_subscribe_t* sub = NULL; snd_seq_port_subscribe_alloca(&sub); snd_seq_port_subscribe_set_sender(sub, m_sender_address); snd_seq_port_subscribe_set_dest(sub, m_receiver_address); snd_seq_unsubscribe_port(m_alsa, sub); }
void Alsa::openPort(unsigned int portNumber_) { if ( _connected ) { this->closePort(); } unsigned int nSrc = this->getPortCount(); if (nSrc < 1) { std::cerr << "error: CxxMidi::Output::Alsa::openPort: no MIDI output sources found" << std::endl; } snd_seq_port_info_t *pinfo; snd_seq_port_info_alloca( &pinfo ); std::ostringstream ost; if ( portInfo( _apiData->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber_ ) == 0 ) { std::cerr << "error: CxxMidi::Output::Alsa::openPort: port " << portNumber_ << " is invalid" << std::endl; } snd_seq_addr_t sender, receiver; receiver.client = snd_seq_port_info_get_client( pinfo ); receiver.port = snd_seq_port_info_get_port( pinfo ); sender.client = snd_seq_client_id( _apiData->seq ); if ( _apiData->vport < 0 ) { _apiData->vport = snd_seq_create_simple_port( _apiData->seq, "CxxMidi (RtMidi) output", SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION ); if ( _apiData->vport < 0 ) { std::cerr << "error: CxxMidi::Output::Alsa::openPort: error creating output port" << std::endl; } } sender.port = _apiData->vport; // Make subscription snd_seq_port_subscribe_malloc( &_apiData->subscription ); snd_seq_port_subscribe_set_sender(_apiData->subscription, &sender); snd_seq_port_subscribe_set_dest(_apiData->subscription, &receiver); snd_seq_port_subscribe_set_time_update(_apiData->subscription, 1); snd_seq_port_subscribe_set_time_real(_apiData->subscription, 1); if ( snd_seq_subscribe_port(_apiData->seq, _apiData->subscription) ) { std::cerr << "error: CxxMidi::Output::Alsa::openPort: error making port connection" << std::endl; } _connected = true; }
bool AlsaMidiOutputDevice::open() { qDebug() << Q_FUNC_INFO; m_open = true; Q_ASSERT(m_sender_address != NULL); Q_ASSERT(m_receiver_address != NULL); /* Subscribe QLC+ ALSA client to the MIDI device */ snd_seq_port_subscribe_t* sub = NULL; snd_seq_port_subscribe_alloca(&sub); snd_seq_port_subscribe_set_sender(sub, m_sender_address); snd_seq_port_subscribe_set_dest(sub, m_receiver_address); snd_seq_subscribe_port(m_alsa, sub); return true; }
void MidiAlsaSeq::subscribeWritablePort( MidiPort * _port, const QString & _dest, bool _subscribe ) { if( !m_portIDs.contains( _port ) ) { return; } const int pid = m_portIDs[_port][1] < 0 ? m_portIDs[_port][0] : m_portIDs[_port][1]; if( pid < 0 ) { return; } m_seqMutex.lock(); snd_seq_addr_t dest; if( snd_seq_parse_address( m_seqHandle, &dest, _dest.section( ' ', 0, 0 ).toLatin1().constData() ) ) { fprintf( stderr, "error parsing dest-address!\n" ); m_seqMutex.unlock(); return; } snd_seq_port_info_t * port_info; snd_seq_port_info_malloc( &port_info ); snd_seq_get_port_info( m_seqHandle, pid, port_info ); const snd_seq_addr_t * sender = snd_seq_port_info_get_addr( port_info ); snd_seq_port_subscribe_t * subs; snd_seq_port_subscribe_malloc( &subs ); snd_seq_port_subscribe_set_sender( subs, sender ); snd_seq_port_subscribe_set_dest( subs, &dest ); if( _subscribe ) { snd_seq_subscribe_port( m_seqHandle, subs ); } else { snd_seq_unsubscribe_port( m_seqHandle, subs ); } snd_seq_port_subscribe_free( subs ); snd_seq_port_info_free( port_info ); m_seqMutex.unlock(); }
/* TODO Make sample rate, buffer, gain and polyphony set from CL interface*/ void connect2MidiThroughPort(snd_seq_t *seq_handle) { snd_seq_addr_t sender, dest; snd_seq_port_subscribe_t *subs; int myID; myID=snd_seq_client_id(seq_handle); fprintf(stderr,"MyID=%d",myID); sender.client = 14; sender.port = 0; dest.client = myID; dest.port = 0; snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_sender(subs, &sender); snd_seq_port_subscribe_set_dest(subs, &dest); snd_seq_port_subscribe_set_queue(subs, 1); snd_seq_port_subscribe_set_time_update(subs, 1); snd_seq_port_subscribe_set_time_real(subs, 1); snd_seq_subscribe_port(seq_handle, subs); }
/** * Connects this Alsa midi input device with an Alsa MIDI source. * * @param Client - Alsa sequencer client and port ID of a MIDI source * (e.g. "64:0") * @throws MidiInputException if connection cannot be established */ void MidiInputDeviceAlsa::MidiInputPortAlsa::ConnectToAlsaMidiSource(const char* MidiSource) { snd_seq_addr_t sender, dest; snd_seq_port_subscribe_t* subs; int hExtClient, hExtPort; sscanf(MidiSource, "%d:%d", &hExtClient, &hExtPort); sender.client = (char) hExtClient; sender.port = (char) hExtPort; dest.client = (char) pDevice->hAlsaSeqClient; dest.port = (char) portNumber; snd_seq_port_subscribe_malloc(&subs); snd_seq_port_subscribe_set_sender(subs, &sender); snd_seq_port_subscribe_set_dest(subs, &dest); snd_seq_port_subscribe_set_queue(subs, 1); snd_seq_port_subscribe_set_time_update(subs, 1); snd_seq_port_subscribe_set_time_real(subs, 1); if (snd_seq_subscribe_port(pDevice->hAlsaSeq, subs) < 0) { snd_seq_port_subscribe_free(subs); throw MidiInputException(String("Unable to connect to Alsa seq client \'") + MidiSource + "\' (" + snd_strerror(errno) + ")"); } subscriptions.push_back(subs); }
static int alsa_connect_from(alsa_seqmidi_t *self, int client, int port) { snd_seq_port_subscribe_t* sub; snd_seq_addr_t seq_addr; int err; snd_seq_port_subscribe_alloca(&sub); seq_addr.client = client; seq_addr.port = port; snd_seq_port_subscribe_set_sender(sub, &seq_addr); seq_addr.client = self->client_id; seq_addr.port = self->port_id; snd_seq_port_subscribe_set_dest(sub, &seq_addr); snd_seq_port_subscribe_set_time_update(sub, 1); snd_seq_port_subscribe_set_queue(sub, self->queue); snd_seq_port_subscribe_set_time_real(sub, 1); if ((err=snd_seq_subscribe_port(self->seq, sub))) error_log("can't subscribe to %d:%d - %s", client, port, snd_strerror(err)); return err; }
// Disconnection primitive. bool qjackctlAlsaConnect::disconnectPorts ( qjackctlPortItem *pOPort, qjackctlPortItem *pIPort ) { #ifdef CONFIG_ALSA_SEQ qjackctlMainForm *pMainForm = qjackctlMainForm::getInstance(); if (pMainForm == NULL) return false; snd_seq_t *pAlsaSeq = pMainForm->alsaSeq(); if (pAlsaSeq == NULL) return false; qjackctlAlsaPort *pOAlsa = static_cast<qjackctlAlsaPort *> (pOPort); qjackctlAlsaPort *pIAlsa = static_cast<qjackctlAlsaPort *> (pIPort); snd_seq_port_subscribe_t *pAlsaSubs; snd_seq_addr_t seq_addr; snd_seq_port_subscribe_alloca(&pAlsaSubs); seq_addr.client = pOAlsa->alsaClient(); seq_addr.port = pOAlsa->alsaPort(); snd_seq_port_subscribe_set_sender(pAlsaSubs, &seq_addr); seq_addr.client = pIAlsa->alsaClient(); seq_addr.port = pIAlsa->alsaPort(); snd_seq_port_subscribe_set_dest(pAlsaSubs, &seq_addr); return (snd_seq_unsubscribe_port(pAlsaSeq, pAlsaSubs) >= 0); #else return false; #endif // CONFIG_ALSA_SEQ }
bool midi_init() { snd_seq_addr_t sender, receiver; snd_seq_port_info_t *pinfo; snd_seq_client_info_t *cinfo; bool found = false; if (snd_seq_open(&s_midi, "default", SND_SEQ_OPEN_OUTPUT, 0) < 0) { Error("Failed to initialize MIDI\n"); s_midi = NULL; return false; } snd_seq_set_client_name(s_midi, s_midiCaption); /* Create a port to work on */ s_midiPort = snd_seq_create_simple_port(s_midi, s_midiCaption, SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC); if (s_midiPort < 0) { Error("Failed to initialize MIDI\n"); snd_seq_close(s_midi); s_midi = NULL; return false; } /* Try to find a MIDI out */ snd_seq_port_info_alloca(&pinfo); snd_seq_client_info_alloca(&cinfo); snd_seq_client_info_set_client(cinfo, -1); /* Walk all clients and ports, and see if one matches our demands */ while (snd_seq_query_next_client(s_midi, cinfo) >= 0 && !found) { int client; client = snd_seq_client_info_get_client(cinfo); if (client == 0) continue; snd_seq_port_info_set_client(pinfo, client); snd_seq_port_info_set_port(pinfo, -1); while (snd_seq_query_next_port(s_midi, pinfo) >= 0) { if ((snd_seq_port_info_get_capability(pinfo) & (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)) != (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)) continue; /* Most linux installations come with a Midi Through Port. * This is 'hardware' support that mostly ends up on your serial, which * you most likely do not have connected. So we skip it by default. */ if (strncmp("Midi Through Port", snd_seq_port_info_get_name(pinfo), 17) == 0) continue; found = true; break; } } if (!found) { Error("No valid MIDI output ports.\n Please install and start Timidity++ like: timidity -iA\n"); snd_seq_delete_port(s_midi, s_midiPort); snd_seq_close(s_midi); s_midi = NULL; return false; } /* Subscribe ourself to the port */ receiver.client = snd_seq_port_info_get_client(pinfo); receiver.port = snd_seq_port_info_get_port(pinfo); sender.client = snd_seq_client_id(s_midi); sender.port = s_midiPort; snd_seq_port_subscribe_malloc(&s_midiSubscription); snd_seq_port_subscribe_set_sender(s_midiSubscription, &sender); snd_seq_port_subscribe_set_dest(s_midiSubscription, &receiver); snd_seq_port_subscribe_set_time_update(s_midiSubscription, 1); snd_seq_port_subscribe_set_time_real(s_midiSubscription, 1); if (snd_seq_subscribe_port(s_midi, s_midiSubscription) < 0) { Error("Failed to subscript to MIDI output\n"); snd_seq_delete_port(s_midi, s_midiPort); snd_seq_close(s_midi); s_midi = NULL; return false; } /* Start the MIDI decoder */ if (snd_midi_event_new(4, &s_midiCoder) < 0) { Error("Failed to initialize MIDI decoder\n"); snd_seq_delete_port(s_midi, s_midiPort); snd_seq_close(s_midi); s_midi = NULL; return false; } snd_midi_event_init(s_midiCoder); return true; }
// MIDI Input(readable) / Output(writable) device connects. bool qxgeditMidiDevice::connectDeviceList ( bool bReadable, const QStringList& list ) const { if (m_pAlsaSeq == NULL) return false; if (list.isEmpty()) return false; snd_seq_addr_t seq_addr; snd_seq_port_subscribe_t *pPortSubs; snd_seq_port_subscribe_alloca(&pPortSubs); snd_seq_client_info_t *pClientInfo; snd_seq_port_info_t *pPortInfo; snd_seq_client_info_alloca(&pClientInfo); snd_seq_port_info_alloca(&pPortInfo); unsigned int uiPortFlags; if (bReadable) uiPortFlags = SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; else uiPortFlags = SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; int iConnects = 0; while (snd_seq_query_next_client(m_pAlsaSeq, pClientInfo) >= 0) { int iAlsaClient = snd_seq_client_info_get_client(pClientInfo); if (iAlsaClient > 0 && iAlsaClient != m_iAlsaClient) { QString sClientName = snd_seq_client_info_get_name(pClientInfo); snd_seq_port_info_set_client(pPortInfo, iAlsaClient); snd_seq_port_info_set_port(pPortInfo, -1); while (snd_seq_query_next_port(m_pAlsaSeq, pPortInfo) >= 0) { unsigned int uiPortCapability = snd_seq_port_info_get_capability(pPortInfo); if (((uiPortCapability & uiPortFlags) == uiPortFlags) && ((uiPortCapability & SND_SEQ_PORT_CAP_NO_EXPORT) == 0)) { int iAlsaPort = snd_seq_port_info_get_port(pPortInfo); QString sPortName = snd_seq_port_info_get_name(pPortInfo); QStringListIterator iter(list); while (iter.hasNext()) { const QString& sItem = iter.next(); const QString& sClientItem = sItem.section(c_pszItemSep, 0, 0); const QString& sPortItem = sItem.section(c_pszItemSep, 1, 1); if (sClientName != sClientItem.section(':', 1, 1)) continue; if (sPortName != sPortItem .section(':', 1, 1)) continue; if (bReadable) { seq_addr.client = iAlsaClient; seq_addr.port = iAlsaPort; snd_seq_port_subscribe_set_sender(pPortSubs, &seq_addr); seq_addr.client = m_iAlsaClient; seq_addr.port = m_iAlsaPort; snd_seq_port_subscribe_set_dest(pPortSubs, &seq_addr); } else { seq_addr.client = m_iAlsaClient; seq_addr.port = m_iAlsaPort; snd_seq_port_subscribe_set_sender(pPortSubs, &seq_addr); seq_addr.client = iAlsaClient; seq_addr.port = iAlsaPort; snd_seq_port_subscribe_set_dest(pPortSubs, &seq_addr); } if (snd_seq_subscribe_port(m_pAlsaSeq, pPortSubs) == 0) iConnects++; } } } } } return (iConnects > 0); }
void event_decoder(snd_seq_t *handle, int argc, char *argv[]) { snd_seq_event_t *ev; snd_seq_port_info_t *pinfo; snd_seq_port_subscribe_t *sub; snd_seq_addr_t addr; int client, port, queue, max, err, v1, v2; char *ptr; struct pollfd *pfds; if ((client = snd_seq_client_id(handle))<0) { fprintf(stderr, "Cannot determine client number: %s\n", snd_strerror(client)); return; } printf("Client ID = %i\n", client); if ((queue = snd_seq_alloc_queue(handle))<0) { fprintf(stderr, "Cannot allocate queue: %s\n", snd_strerror(queue)); return; } printf("Queue ID = %i\n", queue); if ((err = snd_seq_nonblock(handle, 1))<0) fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err)); snd_seq_port_info_alloca(&pinfo); snd_seq_port_info_set_name(pinfo, "Input"); snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC); snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_WRITE); /* Enable timestamping for events sent by external subscribers. */ snd_seq_port_info_set_timestamping(pinfo, 1); snd_seq_port_info_set_timestamp_real(pinfo, 1); snd_seq_port_info_set_timestamp_queue(pinfo, queue); if ((err = snd_seq_create_port(handle, pinfo)) < 0) { fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err)); return; } port = snd_seq_port_info_get_port(pinfo); event_decoder_start_timer(handle, queue, client, port); snd_seq_port_subscribe_alloca(&sub); addr.client = SND_SEQ_CLIENT_SYSTEM; addr.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE; snd_seq_port_subscribe_set_sender(sub, &addr); addr.client = client; addr.port = port; snd_seq_port_subscribe_set_dest(sub, &addr); snd_seq_port_subscribe_set_queue(sub, queue); snd_seq_port_subscribe_set_time_update(sub, 1); snd_seq_port_subscribe_set_time_real(sub, 1); if ((err = snd_seq_subscribe_port(handle, sub))<0) { fprintf(stderr, "Cannot subscribe announce port: %s\n", snd_strerror(err)); return; } addr.client = SND_SEQ_CLIENT_SYSTEM; addr.port = SND_SEQ_PORT_SYSTEM_TIMER; snd_seq_port_subscribe_set_sender(sub, &addr); if ((err = snd_seq_subscribe_port(handle, sub))<0) { fprintf(stderr, "Cannot subscribe timer port: %s\n", snd_strerror(err)); return; } for (max = 0; max < argc; max++) { ptr = argv[max]; if (!ptr) continue; snd_seq_port_subscribe_set_time_real(sub, 0); if (tolower(*ptr) == 'r') { snd_seq_port_subscribe_set_time_real(sub, 1); ptr++; } if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) { fprintf(stderr, "Wrong argument '%s'...\n", argv[max]); return; } addr.client = v1; addr.port = v2; snd_seq_port_subscribe_set_sender(sub, &addr); if ((err = snd_seq_subscribe_port(handle, sub))<0) { fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err)); return; } } max = snd_seq_poll_descriptors_count(handle, POLLIN); pfds = alloca(sizeof(*pfds) * max); while (1) { snd_seq_poll_descriptors(handle, pfds, max, POLLIN); if (poll(pfds, max, -1) < 0) break; do { if ((err = snd_seq_event_input(handle, &ev))<0) break; if (!ev) continue; decode_event(ev); snd_seq_free_event(ev); } while (err > 0); } }
int main(int argc, char **argv) { int c; snd_seq_t *seq; int queue = 0, convert_time = 0, convert_real = 0, exclusive = 0; int command = SUBSCRIBE; int list_perm = 0; int client; int list_subs = 0; snd_seq_port_subscribe_t *subs; snd_seq_addr_t sender, dest; #ifdef ENABLE_NLS setlocale(LC_ALL, ""); textdomain(PACKAGE); #endif while ((c = getopt_long(argc, argv, "dior:t:elx", long_option, NULL)) != -1) { switch (c) { case 'd': command = UNSUBSCRIBE; break; case 'i': command = LIST; list_perm |= LIST_INPUT; break; case 'o': command = LIST; list_perm |= LIST_OUTPUT; break; case 'e': exclusive = 1; break; case 'r': queue = atoi(optarg); convert_time = 1; convert_real = 1; break; case 't': queue = atoi(optarg); convert_time = 1; convert_real = 0; break; case 'l': list_subs = 1; break; case 'x': command = REMOVE_ALL; break; default: usage(); exit(1); } } if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { fprintf(stderr, _("can't open sequencer\n")); return 1; } snd_lib_error_set_handler(error_handler); switch (command) { case LIST: do_search_port(seq, list_perm, list_subs ? print_port_and_subs : print_port); snd_seq_close(seq); return 0; case REMOVE_ALL: remove_all_connections(seq); snd_seq_close(seq); return 0; } /* connection or disconnection */ if (optind + 2 > argc) { snd_seq_close(seq); usage(); exit(1); } if ((client = snd_seq_client_id(seq)) < 0) { snd_seq_close(seq); fprintf(stderr, _("can't get client id\n")); return 1; } /* set client info */ if (snd_seq_set_client_name(seq, "ALSA Connector") < 0) { snd_seq_close(seq); fprintf(stderr, _("can't set client info\n")); return 1; } /* set subscription */ if (snd_seq_parse_address(seq, &sender, argv[optind]) < 0) { snd_seq_close(seq); fprintf(stderr, _("invalid sender address %s\n"), argv[optind]); return 1; } if (snd_seq_parse_address(seq, &dest, argv[optind + 1]) < 0) { snd_seq_close(seq); fprintf(stderr, _("invalid destination address %s\n"), argv[optind + 1]); return 1; } snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_sender(subs, &sender); snd_seq_port_subscribe_set_dest(subs, &dest); snd_seq_port_subscribe_set_queue(subs, queue); snd_seq_port_subscribe_set_exclusive(subs, exclusive); snd_seq_port_subscribe_set_time_update(subs, convert_time); snd_seq_port_subscribe_set_time_real(subs, convert_real); if (command == UNSUBSCRIBE) { if (snd_seq_get_port_subscription(seq, subs) < 0) { snd_seq_close(seq); fprintf(stderr, _("No subscription is found\n")); return 1; } if (snd_seq_unsubscribe_port(seq, subs) < 0) { snd_seq_close(seq); fprintf(stderr, _("Disconnection failed (%s)\n"), snd_strerror(errno)); return 1; } } else { if (snd_seq_get_port_subscription(seq, subs) == 0) { snd_seq_close(seq); fprintf(stderr, _("Connection is already subscribed\n")); return 1; } if (snd_seq_subscribe_port(seq, subs) < 0) { snd_seq_close(seq); fprintf(stderr, _("Connection failed (%s)\n"), snd_strerror(errno)); return 1; } } snd_seq_close(seq); return 0; }