Example #1
0
static
void do_jack_output(alsa_seqmidi_t *self, port_t *port, struct process_info* info)
{
	stream_t *str = &self->stream[info->dir];
	int nevents = jack_midi_get_event_count(port->jack_buf);
	int i;
	for (i=0; i<nevents; ++i) {
		jack_midi_event_t jack_event;
		snd_seq_event_t alsa_event;
		int64_t frame_offset;
		int64_t out_time;
		snd_seq_real_time_t out_rt;
		int err;

		jack_midi_event_get(&jack_event, port->jack_buf, i);

		snd_seq_ev_clear(&alsa_event);
		snd_midi_event_reset_encode(str->codec);
		if (!snd_midi_event_encode(str->codec, jack_event.buffer, jack_event.size, &alsa_event))
			continue; // invalid event

		snd_seq_ev_set_source(&alsa_event, self->port_id);
		snd_seq_ev_set_dest(&alsa_event, port->remote.client, port->remote.port);

		/* NOTE: in case of xrun it could become negative, so it is essential to use signed type! */
		frame_offset = (int64_t)jack_event.time + info->period_start + info->nframes - info->cur_frames;
		if (frame_offset < 0) {
			frame_offset = info->nframes + jack_event.time;
			error_log("internal xrun detected: frame_offset = %"PRId64"\n", frame_offset);
		}
		/* Ken Ellinwood reported problems with this assert.
		 * Seems, magic 2 should be replaced with nperiods. */
		//FIXME: assert (frame_offset < info->nframes*2);
		//if (frame_offset < info->nframes * info->nperiods)
		//        debug_log("alsa_out: BLAH-BLAH-BLAH");

		out_time = info->alsa_time + (frame_offset * NSEC_PER_SEC) / info->sample_rate;

		debug_log("alsa_out: frame_offset = %lld, info->alsa_time = %lld, out_time = %lld, port->last_out_time = %lld",
			frame_offset, info->alsa_time, out_time, port->last_out_time);

		// we should use absolute time to prevent reordering caused by rounding errors
		if (out_time < port->last_out_time) {
			debug_log("alsa_out: limiting out_time %lld at %lld", out_time, port->last_out_time);
			out_time = port->last_out_time;
		} else
			port->last_out_time = out_time;

		out_rt.tv_nsec = out_time % NSEC_PER_SEC;
		out_rt.tv_sec = out_time / NSEC_PER_SEC;
		snd_seq_ev_schedule_real(&alsa_event, self->queue, 0, &out_rt);

		err = snd_seq_event_output(self->seq, &alsa_event);
		debug_log("alsa_out: written %d bytes to %s at %+d (%lld): %d", (int)jack_event.size, port->name, (int)frame_offset, out_time, err);
	}
}
Example #2
0
void MIDIDevice::feedBack(t_input_channel channel, t_input_value value)
{
	/* MIDI devices can have only 128 notes or controllers */
	if (channel < 128)
	{
		snd_seq_event_t ev;
		MIDIInput* plugin;

		plugin = static_cast<MIDIInput*> (parent());
		Q_ASSERT(plugin != NULL);
		Q_ASSERT(plugin->alsa() != NULL);
		Q_ASSERT(m_address != NULL);

		/* Setup an event structure */
		snd_seq_ev_clear(&ev);
		snd_seq_ev_set_dest(&ev, m_address->client, m_address->port);
		snd_seq_ev_set_subs(&ev);
		snd_seq_ev_set_direct(&ev);

		char scaled = static_cast <char> (SCALE(double(value),
							double(0),
							double(KInputValueMax),
							double(0),
							double(127)));

		if (m_mode == ControlChange)
		{
			/* Send control change */
			snd_seq_ev_set_controller(&ev, midiChannel(),
						  channel, scaled);
			snd_seq_event_output(plugin->alsa(), &ev);
			snd_seq_drain_output(plugin->alsa());
		}
		else
		{
			/* Send note on/off */
			if (value == 0)
			{
				snd_seq_ev_set_noteoff(&ev, midiChannel(),
							channel, scaled);
			}
			else
			{
				snd_seq_ev_set_noteon(&ev, midiChannel(),
							channel, scaled);
			}

			snd_seq_event_output(plugin->alsa(), &ev);
			snd_seq_drain_output(plugin->alsa());
		}
	}
}
Example #3
0
void MIDIDevice::feedBack(quint32 channel, uchar value)
{
    MIDIInput* plugin = static_cast<MIDIInput*> (parent());
    Q_ASSERT(plugin != NULL);
    Q_ASSERT(plugin->alsa() != NULL);
    Q_ASSERT(m_address != NULL);

    uchar cmd = 0;
    uchar data1 = 0;
    uchar data2 = 0;
    bool d2v = false;

    if (QLCMIDIProtocol::feedbackToMidi(channel, value, midiChannel(), &cmd,
                                        &data1, &data2, &d2v) == true)
    {
        /* Setup an event structure */
        snd_seq_event_t ev;
        snd_seq_ev_clear(&ev);
        snd_seq_ev_set_dest(&ev, m_address->client, m_address->port);
        snd_seq_ev_set_subs(&ev);
        snd_seq_ev_set_direct(&ev);

        if (MIDI_CMD(cmd) == MIDI_NOTE_OFF)
        {
            /* Send data as note off command */
            snd_seq_ev_set_noteoff(&ev, midiChannel(), data1, data2);
            snd_seq_event_output(plugin->alsa(), &ev);
            snd_seq_drain_output(plugin->alsa());
        }
        else if (MIDI_CMD(cmd) == MIDI_NOTE_ON)
        {
            /* Send data as note on command */
            snd_seq_ev_set_noteon(&ev, midiChannel(), data1, data2);
            snd_seq_event_output(plugin->alsa(), &ev);
            snd_seq_drain_output(plugin->alsa());
        }
        else if (MIDI_CMD(cmd) == MIDI_CONTROL_CHANGE)
        {
            /* Send data as control change command */
            snd_seq_ev_set_controller(&ev, midiChannel(), data1, data2);
            snd_seq_event_output(plugin->alsa(), &ev);
            snd_seq_drain_output(plugin->alsa());
        }
    }
}
void AlsaMidiOutputDevice::writeSysEx(QByteArray message)
{
    if(message.isEmpty())
        return;

    if (isOpen() == false)
        return;

    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_dest(&ev, m_receiver_address->client, m_receiver_address->port);
    //snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);

    snd_seq_ev_set_sysex (&ev, message.count(), message.data());

    if (snd_seq_event_output(m_alsa, &ev) < 0)
        qDebug() << "snd_seq_event_output ERROR";

    // Make sure that all values go to the MIDI endpoint
    snd_seq_drain_output(m_alsa);
}
void AlsaMidiOutputDevice::writeFeedback(uchar cmd, uchar data1, uchar data2)
{
    if (isOpen() == false)
        return;

    // Setup a common event structure for all values
    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_dest(&ev, m_receiver_address->client, m_receiver_address->port);
    //snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);

    uchar midiCmd = MIDI_CMD(cmd);
    uchar midiCh = MIDI_CH(cmd);

    bool invalidCmd = false;

    switch(midiCmd)
    {
    case MIDI_NOTE_OFF:
        snd_seq_ev_set_noteoff(&ev, midiCh, data1, data2);
        break;

    case MIDI_NOTE_ON:
        snd_seq_ev_set_noteon(&ev, midiCh, data1, data2);
        break;

    case MIDI_CONTROL_CHANGE:
        snd_seq_ev_set_controller(&ev, midiCh, data1, data2);
        break;

    case MIDI_PROGRAM_CHANGE:
        snd_seq_ev_set_pgmchange(&ev, midiCh, data1);
        break;

    case MIDI_NOTE_AFTERTOUCH:
        snd_seq_ev_set_keypress(&ev, midiCh, data1, data2);
        break;

    case MIDI_CHANNEL_AFTERTOUCH:
        snd_seq_ev_set_chanpress(&ev, midiCh, data1);
        break;

    case MIDI_PITCH_WHEEL:
        snd_seq_ev_set_pitchbend(&ev, midiCh, ((data1 & 0x7f) | ((data2 & 0x7f) << 7)) - 8192);
        break;

    default:
        // What to do here ??
        invalidCmd = true;
        break;
    }

    if (!invalidCmd)
    {
        if (snd_seq_event_output(m_alsa, &ev) < 0)
            qDebug() << "snd_seq_event_output ERROR";
    }

    // Make sure that all values go to the MIDI endpoint
    snd_seq_drain_output(m_alsa);
}
void AlsaMidiOutputDevice::writeUniverse(const QByteArray& universe)
{
    if (isOpen() == false)
        return;

    // Setup a common event structure for all values
    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_dest(&ev, m_receiver_address->client, m_receiver_address->port);
    //snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);

    // Since MIDI devices can have only 128 real channels, we don't
    // attempt to write more than that.
    for (uchar channel = 0; channel < MAX_MIDI_DMX_CHANNELS &&
                            channel < universe.size(); channel++)
    {
        // Scale 0-255 to 0-127
        char scaled = DMX2MIDI(universe[channel]);
        bool invalidData = false;

        // Since MIDI is so slow, we only send values that are actually changed
        if (m_universe[channel] == scaled)
            continue;

        // Store the changed MIDI value
        m_universe[channel] = scaled;

        if (mode() == Note)
        {
            qDebug() << "Send out NOTE";
            // 0 is sent as a note off
            // 1-127 is sent as note on
            if (scaled == 0)
                snd_seq_ev_set_noteoff(&ev, midiChannel(), channel, scaled);
            else
                snd_seq_ev_set_noteon(&ev, midiChannel(), channel, scaled);
            snd_seq_event_output(m_alsa, &ev);
        }
        else if (mode() == ProgramChange)
        {
            qDebug() << "Send out Program Change";
            snd_seq_ev_set_pgmchange(&ev, midiChannel(), channel);
        }
        else if (mode() == ControlChange)
        {
            qDebug() << "Send out CC. Channel: " << midiChannel() << ", CC: " << channel << ", val: " << scaled;

            // Control change
            snd_seq_ev_set_controller(&ev, midiChannel(), channel, scaled);
        }
        else
            invalidData = true;

        if (!invalidData)
            if (snd_seq_event_output(m_alsa, &ev) < 0)
                qDebug() << "snd_seq_event_output ERROR";
    }

    // Make sure that all values go to the MIDI endpoint
    snd_seq_drain_output(m_alsa);
}
Example #7
0
void MIDIDevice::writeRange(t_value* values, t_channel num)
{
	Q_UNUSED(num);

	MIDIOut* plugin = static_cast<MIDIOut*> (parent());
	Q_ASSERT(plugin != NULL);
	Q_ASSERT(plugin->alsa() != NULL);
	Q_ASSERT(m_address != NULL);

	/* Setup a common event structure for all values */
	snd_seq_event_t ev;
	snd_seq_ev_clear(&ev);
	snd_seq_ev_set_dest(&ev, m_address->client, m_address->port);
	snd_seq_ev_set_subs(&ev);
	snd_seq_ev_set_direct(&ev);

	/* Since MIDI devices can have only 128 real channels, we don't
	   attempt to write more than that */

	for (unsigned char channel = 0; channel < MAX_MIDI_DMX_CHANNELS;
	     channel++)
	{
		/* Scale 0-255 to 0-127 */
		char scaled = static_cast <char> (SCALE(double(values[channel]),
							double(0),
							double(KInputValueMax),
							double(0),
							double(127)));

		/* Since MIDI is so slow, we only send values that are
           	   actually changed. */
		if (m_values[channel] == scaled)
        		continue;

		/* Store the changed MIDI value */
		m_values[channel] = scaled;

		if (mode() == Note)
		{
			if (scaled == 0)
			{
				/* 0 is sent as a note off command */
				snd_seq_ev_set_noteoff(&ev, midiChannel(),
						       channel, scaled);
			}
			else
			{
				/* 1-127 is sent as note on command */
				snd_seq_ev_set_noteon(&ev, midiChannel(),
						      channel, scaled);
			}

			snd_seq_event_output(plugin->alsa(), &ev);
		}
		else
		{
			/* Control change */
			snd_seq_ev_set_controller(&ev, midiChannel(),
						  channel, scaled);
			snd_seq_event_output_buffer(plugin->alsa(), &ev);
		}
	}

	/* Make sure that all values go to the MIDI endpoint */
	snd_seq_drain_output(plugin->alsa());
}
Example #8
0
/**************************************************************************
 *		modLongData					[internal]
 */
static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
{
    int		len_add = 0;
    LPBYTE	lpData, lpNewData = NULL;
    snd_seq_event_t event;

    TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);

    /* Note: MS doc does not say much about the dwBytesRecorded member of the MIDIHDR structure
     * but it seems to be used only for midi input.
     * Taking a look at the WAVEHDR structure (which is quite similar) confirms this assumption.
     */
    
    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;

    if (midiSeq == NULL) {
	WARN("can't play !\n");
	return MIDIERR_NODEVICE;
    }

    lpData = (LPBYTE) lpMidiHdr->lpData;
    
    if (lpData == NULL)
	return MIDIERR_UNPREPARED;
    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED))
	return MIDIERR_UNPREPARED;
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
	return MIDIERR_STILLPLAYING;
    lpMidiHdr->dwFlags &= ~MHDR_DONE;
    lpMidiHdr->dwFlags |= MHDR_INQUEUE;

    /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive
     * data, or can it also contain raw MIDI data, to be split up and sent to
     * modShortData() ?
     * If the latest is true, then the following WARNing will fire up
     */
    if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) {
	WARN("Alleged system exclusive buffer is not correct\n\tPlease report with MIDI file\n");
	lpNewData = HeapAlloc(GetProcessHeap(), 0, lpMidiHdr->dwBufferLength + 2);
    }

    TRACE("dwBufferLength=%lu !\n", lpMidiHdr->dwBufferLength);
    TRACE("                 %02X %02X %02X ... %02X %02X %02X\n",
	  lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3],
	  lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]);

    switch (MidiOutDev[wDevID].caps.wTechnology) {
    case MOD_FMSYNTH:
	/* FIXME: I don't think there is much to do here */
	break;
    case MOD_MIDIPORT:
	if (lpData[0] != 0xF0) {
	    /* Send start of System Exclusive */
	    len_add = 1;
	    lpData[0] = 0xF0;
	    memcpy(lpNewData, lpData, lpMidiHdr->dwBufferLength);
	    WARN("Adding missing 0xF0 marker at the beginning of "
		 "system exclusive byte stream\n");
	}
	if (lpData[lpMidiHdr->dwBufferLength-1] != 0xF7) {
	    /* Send end of System Exclusive */
	    memcpy(lpData + len_add, lpData, lpMidiHdr->dwBufferLength);
            lpNewData[lpMidiHdr->dwBufferLength + len_add - 1] = 0xF0;
	    len_add++;
	    WARN("Adding missing 0xF7 marker at the end of "
		 "system exclusive byte stream\n");
	}
	snd_seq_ev_clear(&event);
	snd_seq_ev_set_direct(&event);
	snd_seq_ev_set_source(&event, port_out);
	snd_seq_ev_set_dest(&event, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port);
	TRACE("client = %d port = %d\n", MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port);
	snd_seq_ev_set_sysex(&event, lpMidiHdr->dwBufferLength + len_add, lpNewData ? lpNewData : lpData);
	snd_seq_event_output_direct(midiSeq, &event);
	if (lpNewData)
		HeapFree(GetProcessHeap(), 0, lpData);
	break;
    default:
	WARN("Technology not supported (yet) %d !\n",
	     MidiOutDev[wDevID].caps.wTechnology);
	return MMSYSERR_NOTENABLED;
    }

    lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
    lpMidiHdr->dwFlags |= MHDR_DONE;
    if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD)lpMidiHdr, 0L) != MMSYSERR_NOERROR) {
	WARN("can't notify client !\n");
	return MMSYSERR_INVALPARAM;
    }
    return MMSYSERR_NOERROR;
}
Example #9
0
/**************************************************************************
 * 			modData					[internal]
 */
static DWORD modData(WORD wDevID, DWORD dwParam)
{
    BYTE	evt = LOBYTE(LOWORD(dwParam));
    BYTE	d1  = HIBYTE(LOWORD(dwParam));
    BYTE	d2  = LOBYTE(HIWORD(dwParam));
    
    TRACE("(%04X, %08lX);\n", wDevID, dwParam);

    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;

    if (midiSeq == NULL) {
	WARN("can't play !\n");
	return MIDIERR_NODEVICE;
    }
    switch (MidiOutDev[wDevID].caps.wTechnology) {
    case MOD_SYNTH:
    case MOD_MIDIPORT:
	{
	    int handled = 1; /* Assume event is handled */
            snd_seq_event_t event;
            snd_seq_ev_clear(&event);
            snd_seq_ev_set_direct(&event);
            snd_seq_ev_set_source(&event, port_out);
            snd_seq_ev_set_dest(&event, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port);
	    
	    switch (evt & 0xF0) {
	    case MIDI_CMD_NOTE_OFF:
		snd_seq_ev_set_noteoff(&event, evt&0x0F, d1, d2);
		break;
	    case MIDI_CMD_NOTE_ON:
		snd_seq_ev_set_noteon(&event, evt&0x0F, d1, d2);
		break;
	    case MIDI_CMD_NOTE_PRESSURE:
		snd_seq_ev_set_keypress(&event, evt&0x0F, d1, d2);
		break;
	    case MIDI_CMD_CONTROL:
		snd_seq_ev_set_controller(&event, evt&0x0F, d1, d2);
		break;
	    case MIDI_CMD_BENDER:
		snd_seq_ev_set_pitchbend(&event, evt&0x0F, ((WORD)d2 << 7 | (WORD)d1) - 0x2000);
		break;
	    case MIDI_CMD_PGM_CHANGE:
		snd_seq_ev_set_pgmchange(&event, evt&0x0F, d1);
		break;
	    case MIDI_CMD_CHANNEL_PRESSURE:
		snd_seq_ev_set_chanpress(&event, evt&0x0F, d1);
		break;
	    case MIDI_CMD_COMMON_SYSEX:
		switch (evt & 0x0F) {
		case 0x00:	/* System Exclusive, don't do it on modData,
				 * should require modLongData*/
		case 0x01:	/* Undefined */
		case 0x04:	/* Undefined. */
		case 0x05:	/* Undefined. */
		case 0x07:	/* End of Exclusive. */
		case 0x09:	/* Undefined. */
		case 0x0D:	/* Undefined. */
		    handled = 0;
		    break;
		case 0x06:	/* Tune Request */
		case 0x08:	/* Timing Clock. */
		case 0x0A:	/* Start. */
		case 0x0B:	/* Continue */
		case 0x0C:	/* Stop */
		case 0x0E: 	/* Active Sensing. */
		    /* FIXME: Is this function suitable for these purposes
		       (and also Song Select and Song Position Pointer) */
	            snd_seq_ev_set_sysex(&event, 1, &evt);
		    break;
		case 0x0F: 	/* Reset */
				/* snd_seq_ev_set_sysex(&event, 1, &evt);
				   this other way may be better */
		    {
			BYTE reset_sysex_seq[] = {MIDI_CMD_COMMON_SYSEX, 0x7e, 0x7f, 0x09, 0x01, 0xf7};
			snd_seq_ev_set_sysex(&event, sizeof(reset_sysex_seq), reset_sysex_seq);
		    }
		    break;
		case 0x03:	/* Song Select. */
		    {
			BYTE buf[2];
			buf[0] = evt;
			buf[1] = d1;
			snd_seq_ev_set_sysex(&event, sizeof(buf), buf);
	            }
	            break;
		case 0x02:	/* Song Position Pointer. */
		    {
			BYTE buf[3];
			buf[0] = evt;
			buf[1] = d1;
			buf[2] = d2;
			snd_seq_ev_set_sysex(&event, sizeof(buf), buf);
	            }
		    break;
		}
		break;
	    }
	    if (handled)
                snd_seq_event_output_direct(midiSeq, &event);
	}
	break;
    default:
	WARN("Technology not supported (yet) %d !\n",
	     MidiOutDev[wDevID].caps.wTechnology);
	return MMSYSERR_NOTENABLED;
    }

    return MMSYSERR_NOERROR;
}