void midibus::continue_from( long a_tick ) { /* tell the device that we are going to start at a certain position */ long pp16th = (c_ppqn / 4); long leftover = ( a_tick % pp16th ); long beats = ( a_tick / pp16th ); long starting_tick = a_tick - leftover; /* was there anything left?, then wait for next beat (16th note) to start clocking */ if ( leftover > 0) { starting_tick += pp16th; } //printf ( "continue_from leftover[%ld] starting_tick[%ld]\n", leftover, starting_tick ); m_lasttick = starting_tick - 1; if ( m_clock_type != e_clock_off ) { //printf( "control value %ld\n", beats); snd_seq_event_t evc; snd_seq_event_t ev; ev.type = SND_SEQ_EVENT_CONTINUE; evc.type = SND_SEQ_EVENT_SONGPOS; evc.data.control.value = beats; snd_seq_ev_set_fixed( &ev ); snd_seq_ev_set_fixed( &evc ); snd_seq_ev_set_priority( &ev, 1 ); snd_seq_ev_set_priority( &evc, 1 ); /* set source */ snd_seq_ev_set_source(&evc, m_local_addr_port ); snd_seq_ev_set_subs(&evc); snd_seq_ev_set_source(&ev, m_local_addr_port ); snd_seq_ev_set_subs(&ev); // its immediate snd_seq_ev_set_direct( &ev ); snd_seq_ev_set_direct( &evc ); /* pump it into the queue */ snd_seq_event_output(m_seq, &evc); flush(); snd_seq_event_output(m_seq, &ev); } }
void midibus::stop() { m_lasttick = -1; if ( m_clock_type != e_clock_off ){ snd_seq_event_t ev; ev.type = SND_SEQ_EVENT_STOP; snd_seq_ev_set_fixed( &ev ); snd_seq_ev_set_priority( &ev, 1 ); /* set source */ snd_seq_ev_set_source(&ev, m_local_addr_port ); snd_seq_ev_set_subs(&ev); // its immediate snd_seq_ev_set_direct( &ev ); /* pump it into the queue */ snd_seq_event_output(m_seq, &ev); } }
void midibus::clock (midipulse tick) { #ifdef SEQ64_HAVE_LIBASOUND automutex locker(m_mutex); if (m_clock_type != e_clock_off) { bool done = m_lasttick >= tick; int ct = clock_ticks_from_ppqn(m_ppqn); /* ppqn / 24 */ while (! done) { ++m_lasttick; done = m_lasttick >= tick; if ((m_lasttick % ct) == 0) /* tick time? */ { /* * Set the event tag to 127 so the sequences won't remove it. */ snd_seq_event_t ev; ev.type = SND_SEQ_EVENT_CLOCK; ev.tag = 127; snd_seq_ev_set_fixed(&ev); snd_seq_ev_set_priority(&ev, 1); snd_seq_ev_set_source(&ev, m_local_addr_port); /* set source */ snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); /* it's immediate */ snd_seq_event_output(m_seq, &ev); /* pump it into queue */ } } flush(); /* and send out */ } #endif // SEQ64_HAVE_LIBASOUND }
// Decoder. bool dequeue ( snd_seq_event_t *ev ) { qxgeditMidiRpn::Event event; if (!qxgeditMidiRpn::dequeue(event)) return false; snd_seq_ev_clear(ev); snd_seq_ev_schedule_tick(ev, 0, 0, event.time); snd_seq_ev_set_dest(ev, 0, event.port); snd_seq_ev_set_fixed(ev); switch (qxgeditMidiRpn::Type(event.status & 0x70)) { case qxgeditMidiRpn::CC: // 0x10 ev->type = SND_SEQ_EVENT_CONTROLLER; break; case qxgeditMidiRpn::RPN: // 0x20 ev->type = SND_SEQ_EVENT_REGPARAM; break; case qxgeditMidiRpn::NRPN: // 0x30 ev->type = SND_SEQ_EVENT_NONREGPARAM; break; case qxgeditMidiRpn::CC14: // 0x40 ev->type = SND_SEQ_EVENT_CONTROL14; break; default: return false; } ev->data.control.channel = event.status & 0x0f; ev->data.control.param = event.param; ev->data.control.value = event.value; return true; }
void midibus::continue_from (midipulse tick) { #ifdef SEQ64_HAVE_LIBASOUND /* * Tell the device that we are going to start at a certain position. */ midipulse pp16th = m_ppqn / 4; midipulse leftover = tick % pp16th; long beats = tick / pp16th; midipulse starting_tick = tick - leftover; /* * Was there anything left? Then wait for next beat (16th note) to * start clocking. */ if (leftover > 0) starting_tick += pp16th; m_lasttick = starting_tick - 1; if (m_clock_type != e_clock_off) { snd_seq_event_t ev; ev.type = SND_SEQ_EVENT_CONTINUE; snd_seq_event_t evc; evc.type = SND_SEQ_EVENT_SONGPOS; evc.data.control.value = beats; snd_seq_ev_set_fixed(&ev); snd_seq_ev_set_fixed(&evc); snd_seq_ev_set_priority(&ev, 1); snd_seq_ev_set_priority(&evc, 1); snd_seq_ev_set_source(&evc, m_local_addr_port); /* set the source */ snd_seq_ev_set_subs(&evc); snd_seq_ev_set_source(&ev, m_local_addr_port); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); /* it's immediate */ snd_seq_ev_set_direct(&evc); snd_seq_event_output(m_seq, &evc); /* pump into queue */ flush(); snd_seq_event_output(m_seq, &ev); } #endif // SEQ64_HAVE_LIBASOUND }
// generates midi clock void midibus::clock( long a_tick ) { lock(); if ( m_clock_type != e_clock_off ){ bool done = false; long uptotick = a_tick; if ( m_lasttick >= uptotick ) done = true; while ( !done ){ m_lasttick++; if ( m_lasttick >= uptotick ) done = true; /* tick time? */ if ( m_lasttick % ( c_ppqn / 24 ) == 0 ){ snd_seq_event_t ev; ev.type = SND_SEQ_EVENT_CLOCK; /* set tag to 127 so the sequences wont remove it */ ev.tag = 127; snd_seq_ev_set_fixed( &ev ); snd_seq_ev_set_priority( &ev, 1 ); /* set source */ snd_seq_ev_set_source(&ev, m_local_addr_port ); snd_seq_ev_set_subs(&ev); // its immediate snd_seq_ev_set_direct( &ev ); /* pump it into the queue */ snd_seq_event_output(m_seq, &ev); } } /* and send out */ flush(); } unlock(); }
// FUNCTIONS void JVlibForm::send_data(char * buf,int data_size) { snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_direct(&ev); ev.queue = SND_SEQ_QUEUE_DIRECT; ev.type = SND_SEQ_EVENT_CONTROLLER; ev.dest = ports[0]; ev.data.control.channel = buf[0]; if (data_size>1) ev.data.control.param = buf[1]; if (data_size==3) ev.data.control.value = buf[2]; snd_seq_ev_set_fixed(&ev); snd_seq_ev_set_direct(&ev); snd_seq_event_output_direct(seq, &ev); snd_seq_drain_output(seq); } // end send_data
void midibus::stop () { #ifdef SEQ64_HAVE_LIBASOUND m_lasttick = -1; if (m_clock_type != e_clock_off) { snd_seq_event_t ev; ev.type = SND_SEQ_EVENT_STOP; snd_seq_ev_set_fixed(&ev); snd_seq_ev_set_priority(&ev, 1); snd_seq_ev_set_source(&ev, m_local_addr_port); /* set the source */ snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); /* it's immediate */ snd_seq_event_output(m_seq, &ev); /* pump into queue */ } #endif // SEQ64_HAVE_LIBASOUND }
int send_note(int port, int on, int ch, int note, int vel) { snd_seq_event_t ev; snd_seq_ev_clear(&ev); ev.dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS; ev.source.client = snd_seq_client_id(handle); ev.source.port = port; snd_seq_ev_set_direct(&ev); ev.type = on ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF; snd_seq_ev_set_fixed(&ev); ev.data.note.channel = ch; ev.data.note.note = note; ev.data.note.velocity = vel; snd_seq_event_output(handle, &ev); snd_seq_drain_output(handle); return 1; }
void midibus::clock (long a_tick) { #ifdef HAVE_LIBASOUND automutex locker(m_mutex); if (m_clock_type != e_clock_off) { bool done = false; if (m_lasttick >= a_tick) done = true; while (!done) { m_lasttick++; if (m_lasttick >= a_tick) done = true; if (m_lasttick % (c_ppqn / 24) == 0) /* tick time? */ { /* * Set the event tag to 127 so the sequences won't remove it. */ snd_seq_event_t ev; ev.type = SND_SEQ_EVENT_CLOCK; ev.tag = 127; snd_seq_ev_set_fixed(&ev); snd_seq_ev_set_priority(&ev, 1); snd_seq_ev_set_source(&ev, m_local_addr_port); /* set source */ snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); /* it's immediate */ snd_seq_event_output(m_seq, &ev); /* pump it into queue */ } } flush(); /* and send out */ } #endif // HAVE_LIBASOUND }
int midi_eventout(midi_info_t *mi, snd_seq_event_t *ev) { int64_t stamp, length; int status, data; int tempo; int err; void *buf; if (_data_left(mi) == 0) return EDATA; snd_seq_ev_clear(ev); snd_seq_ev_set_fixed(ev); // We know at this point that the entire event // is within the packet, since it's illegal // to span packet boundries for events. // this makes our lives _so_ much easier. stamp = _read_var_value(mi); if (stamp < 0) return EEVENT; mi->time += stamp; snd_seq_ev_schedule_tick(ev, mi->q, 0, mi->time); status = _read_byte(mi); if (status < 0) return EEVENT; switch (status & 0xF0) { case 0x80: ev->type = SND_SEQ_EVENT_NOTEOFF; ev->data.note.channel = status & 0x0F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.note.note = data & 0x7F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.note.velocity = data & 0x7F; break; case 0x90: ev->type = SND_SEQ_EVENT_NOTEON; ev->data.note.channel = status & 0x0F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.note.note = data & 0x7F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.note.velocity = data & 0x7F; break; case 0xA0: ev->type = SND_SEQ_EVENT_KEYPRESS; ev->data.note.channel = status & 0x0F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.note.note = data & 0x7F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.note.velocity = data & 0x7F; break; case 0xB0: ev->type = SND_SEQ_EVENT_CONTROLLER; ev->data.control.channel = status & 0x0F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.control.param = data & 0x7F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.control.value = data & 0x7F; break; case 0xC0: ev->type = SND_SEQ_EVENT_PGMCHANGE; ev->data.control.channel = status & 0x0F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.control.value = data & 0x7F; break; case 0xD0: ev->type = SND_SEQ_EVENT_CHANPRESS; ev->data.control.channel = status & 0x0F; data = _read_byte(mi); if (data < 0 ) return EEVENT; ev->data.control.value = data & 0x7F; break; case 0xE0: ev->type = SND_SEQ_EVENT_PITCHBEND; ev->data.control.channel = status & 0x0F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.control.param = data & 0x7F; data = _read_byte(mi); if (data < 0) return EEVENT; ev->data.control.value = data & 0x7F; break; case 0xF0: // these events are special // we should not send only the tempo changes // and sysex events switch (status & 0xFF) { case 0xF0: ev->type = SND_SEQ_EVENT_SYSEX; length = _read_var_value(mi); if (length < 1) return EEVENT; if (_data_left(mi) < length) return EEVENT; ev->data.ext.len = length; buf = (void *)malloc(length); if (buf == NULL) return EMALLOC; memcpy(buf, &mi->data[mi->pos], length); snd_seq_ev_set_variable(ev, length, buf); mi->pos += length; break; case 0xFF: data = _read_byte(mi); if (data < 0) return EEVENT; if (data == 0x51) { length = _read_var_value(mi); if (length != 3) return EEVENT; if (_data_left(mi) < length) return EEVENT; ev->type = SND_SEQ_EVENT_TEMPO; ev->data.queue.queue = mi->q; ev->data.queue.param.value = (mi->data[mi->pos] << 16) | (mi->data[mi->pos+1] << 8) | (mi->data[mi->pos+2]); mi->pos += length; } else { snd_seq_ev_clear(ev); // skip this event length = _read_var_value(mi); if (length < 0) return EEVENT; if (_data_left(mi) < length) return EEVENT; mi->pos += length; } break; default: return EEVENT; } break; default: return EEVENT; } return 0; }
void sys_alsa_putmidimess(int portno, int a, int b, int c) { if (portno >= 0 && portno < alsa_nmidiout) { snd_seq_event_t ev; snd_seq_ev_clear(&ev); int status = a & 0xf0; int channel = a & 0x0f; status = (status >= MIDI_SYSEX) ? status : (status & 0xf0); switch (status) { case MIDI_NOTEON: snd_seq_ev_set_noteon(&ev, channel, b, c); break; case MIDI_NOTEOFF: snd_seq_ev_set_noteoff(&ev, channel, b, c); break; case MIDI_POLYAFTERTOUCH: snd_seq_ev_set_chanpress(&ev, channel, b); break; case MIDI_CONTROLCHANGE: snd_seq_ev_set_controller(&ev, channel, b, c); break; case MIDI_PROGRAMCHANGE: snd_seq_ev_set_pgmchange(&ev, channel, b); break; case MIDI_AFTERTOUCH: snd_seq_ev_set_chanpress(&ev, channel, b); break; case MIDI_PITCHBEND: /* b and c are already correct but alsa needs to recalculate them */ snd_seq_ev_set_pitchbend(&ev, channel, (((c<<7)|b)-8192)); break; case MIDI_TIMECODE: ev.type = SND_SEQ_EVENT_QFRAME; snd_seq_ev_set_fixed(&ev); ev.data.raw8.d[0] = a & 0xff; /* status */ ev.data.raw8.d[1] = b & 0x7f; /* data */ break; case MIDI_SONGPOS: ev.type = SND_SEQ_EVENT_SONGPOS; snd_seq_ev_set_fixed(&ev); ev.data.raw8.d[0] = a & 0xff; /* status */ ev.data.raw8.d[1] = b & 0x7f; /* data */ ev.data.raw8.d[2] = c & 0x7f; /* data */ break; case MIDI_SONGSELECT: ev.type = SND_SEQ_EVENT_SONGSEL; snd_seq_ev_set_fixed(&ev); ev.data.raw8.d[0] = a & 0xff; /* status */ ev.data.raw8.d[1] = b & 0x7f; /* data */ break; default: bug("couldn't put alsa midi message"); break; } snd_seq_ev_set_direct(&ev); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_source(&ev, alsa_midioutfd[portno]); snd_seq_event_output_direct(midi_handle, &ev); } //post("%d %d %d\n", a, b, c); }
void MIDI_PLAYER::play_midi(unsigned int startTick) { int end_delay = 2; int err; // set data in (snd_seq_event_t ev) and output the event // common settings for all events snd_seq_event_t ev; snd_seq_ev_clear(&ev); ev.queue = queue; ev.source.port = 0; ev.flags = SND_SEQ_TIME_STAMP_TICK; // parse each event, already in sort order by 'tick' from parse_file for (std::vector<event>::iterator Event=all_events.begin(); Event!=all_events.end(); ++Event) { // skip over everything except TEMPO, CONTROLLER, PROGRAM, ChannelPressure and SysEx changes until startTick is reached. if (Event->tick<startTick && (Event->type!=SND_SEQ_EVENT_TEMPO || Event->type!=SND_SEQ_EVENT_CONTROLLER || Event->type!=SND_SEQ_EVENT_PGMCHANGE || Event->type!=SND_SEQ_EVENT_CHANPRESS || Event->type!=SND_SEQ_EVENT_SYSEX)) { continue; } ev.time.tick = Event->tick; ev.type = Event->type; // ev.dest = ports[Event->port]; ev.dest = ports[0]; switch (ev.type) { case SND_SEQ_EVENT_NOTEON: case SND_SEQ_EVENT_NOTEOFF: case SND_SEQ_EVENT_KEYPRESS: snd_seq_ev_set_fixed(&ev); ev.data.note.channel = Event->data.d[0]; ev.data.note.note = Event->data.d[1]; ev.data.note.velocity = Event->data.d[2]; break; case SND_SEQ_EVENT_CONTROLLER: snd_seq_ev_set_fixed(&ev); ev.data.control.channel = Event->data.d[0]; ev.data.control.param = Event->data.d[1]; ev.data.control.value = Event->data.d[2]; break; case SND_SEQ_EVENT_PGMCHANGE: case SND_SEQ_EVENT_CHANPRESS: snd_seq_ev_set_fixed(&ev); ev.data.control.channel = Event->data.d[0]; ev.data.control.value = Event->data.d[1]; break; case SND_SEQ_EVENT_PITCHBEND: snd_seq_ev_set_fixed(&ev); ev.data.control.channel = Event->data.d[0]; ev.data.control.value = ((Event->data.d[1]) | ((Event->data.d[2]) << 7)) - 0x2000; break; case SND_SEQ_EVENT_SYSEX: snd_seq_ev_set_variable(&ev, Event->data.length, &Event->sysex); break; case SND_SEQ_EVENT_TEMPO: snd_seq_ev_set_fixed(&ev); ev.dest.client = SND_SEQ_CLIENT_SYSTEM; ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; ev.data.queue.queue = queue; ev.data.queue.param.value = Event->data.tempo; break; default: QMessageBox::critical(this, "MIDI Player", QString("Invalid event type %1") .arg(ev.type)); } // end SWITCH ev.type // do the actual output of the event to the MIDI queue // this blocks when the output pool has been filled err = snd_seq_event_output(seq, &ev); check_snd("output event", err); } // end for all_events iterator // schedule queue stop at end of song snd_seq_ev_set_fixed(&ev); ev.type = SND_SEQ_EVENT_STOP; ev.time.tick = all_events.back().tick; ev.dest.client = SND_SEQ_CLIENT_SYSTEM; ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; ev.data.queue.queue = queue; err = snd_seq_event_output(seq, &ev); check_snd("output event", err); // make sure that the sequencer sees all our events err = snd_seq_drain_output(seq); check_snd("drain output", err); // There are three possibilities for how to wait until all events have been played: // 1) send an event back to us (like pmidi does), and wait for it; // 2) wait for the EVENT_STOP notification for our queue which is sent // by the system timer port (this would require a subscription); // 3) wait until the output pool is empty. // The last is the simplest. err = snd_seq_sync_output_queue(seq); check_snd("sync output", err); // give the last notes time to die away if (end_delay > 0) sleep(end_delay); } // end play_midi