Ejemplo n.º 1
0
/*
 * Send a sysex event. The status byte is to distiguish
 * continuation sysex messages.
 *  Arguments:
 *    ctxp      - Application context
 *    ep        - Event template
 *    status    - Status byte for sysex
 *    data      - Data to send
 *    length    - Length of data
 */
void 
SeqContext::seq_midi_sysex(snd_seq_event_t *ep, int status, 
        unsigned char *data, int length)
{
	unsigned char *ndata;
	int  nlen;

	ep->type = SND_SEQ_EVENT_SYSEX;

	ndata = new unsigned char[length + 1];
	nlen = length +1;

	ndata[0] = status;
	memcpy(ndata+1, data, length);

	snd_seq_ev_set_variable(ep, nlen, ndata);

	seq_write(ep);

	delete ndata;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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