|
- /*
- Copyright (C) 2009 Grame
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
- #include "JackWinMMEDriver.h"
- #include "JackGraphManager.h"
- #include "JackEngineControl.h"
- #include "JackDriverLoader.h"
-
- #include <assert.h>
- #include <iostream>
- #include <sstream>
- #include <string>
-
- #include <windows.h>
- #include <windowsx.h>
- #include <mmsystem.h>
-
- namespace Jack
- {
-
- static bool InitHeaders(MidiSlot* slot)
- {
- slot->fHeader = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, sizeof(MIDIHDR) + kBuffSize);
- if (!slot->fHeader)
- return false;
-
- slot->fHeader->lpData = (LPSTR)((LPBYTE)slot->fHeader + sizeof(MIDIHDR));
- slot->fHeader->dwBufferLength = kBuffSize;
- slot->fHeader->dwFlags = 0;
- slot->fHeader->dwUser = 0;
- slot->fHeader->lpNext = 0;
- slot->fHeader->dwBytesRecorded = 0;
- return true;
- }
-
- void CALLBACK JackWinMMEDriver::MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD userData, DWORD dwParam1, DWORD dwParam2)
- {
- jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)userData;
- //jack_info("JackWinMMEDriver::MidiInProc 0\n");
-
- switch (wMsg) {
- case MIM_OPEN:
- break;
-
- case MIM_ERROR:
- case MIM_DATA: {
-
- //jack_info("JackWinMMEDriver::MidiInProc");
-
- // One event
- unsigned int num_packet = 1;
- jack_ringbuffer_write(ringbuffer, (char*)&num_packet, sizeof(unsigned int));
-
- // Write event actual data
- jack_ringbuffer_write(ringbuffer, (char*)&dwParam1, 3);
- break;
- }
-
- case MIM_LONGERROR:
- case MIM_LONGDATA:
- /*
- Nothing for now
- */
- break;
- }
- }
-
- JackWinMMEDriver::JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
- : JackMidiDriver(name, alias, engine, table),
- fRealCaptureChannels(0),
- fRealPlaybackChannels(0),
- fMidiSource(NULL),
- fMidiDestination(NULL)
- {}
-
- JackWinMMEDriver::~JackWinMMEDriver()
- {}
-
- int JackWinMMEDriver::Open(bool capturing,
- bool playing,
- int inchannels,
- int outchannels,
- bool monitor,
- const char* capture_driver_name,
- const char* playback_driver_name,
- jack_nframes_t capture_latency,
- jack_nframes_t playback_latency)
- {
-
- jack_log("JackWinMMEDriver::Open");
-
- fRealCaptureChannels = midiInGetNumDevs();
- fRealPlaybackChannels = midiOutGetNumDevs();
-
- // Generic JackMidiDriver Open
- if (JackMidiDriver::Open(capturing, playing, fRealCaptureChannels, fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
- return -1;
-
- fMidiDestination = new MidiSlot[fRealCaptureChannels];
- assert(fMidiDestination);
-
- // Real input
- int devindex = 0;
- for (int i = 0; i < fRealCaptureChannels; i++) {
-
- HMIDIIN handle;
- fMidiDestination[devindex].fIndex = i;
- MMRESULT ret = midiInOpen(&handle, fMidiDestination[devindex].fIndex, (DWORD)MidiInProc, (DWORD)fRingBuffer[devindex], CALLBACK_FUNCTION);
-
- if (ret == MMSYSERR_NOERROR) {
- fMidiDestination[devindex].fHandle = handle;
- if (!InitHeaders(&fMidiDestination[devindex])) {
- jack_error("memory allocation failed");
- midiInClose(handle);
- continue;
- }
- ret = midiInPrepareHeader(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR));
-
- if (ret == MMSYSERR_NOERROR) {
- fMidiDestination[devindex].fHeader->dwUser = 1;
- ret = midiInAddBuffer(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR));
- if (ret == MMSYSERR_NOERROR) {
- ret = midiInStart(handle);
- if (ret != MMSYSERR_NOERROR) {
- jack_error("midiInStart error");
- CloseInput(&fMidiDestination[devindex]);
- continue;
- }
- } else {
- jack_error ("midiInAddBuffer error");
- CloseInput(&fMidiDestination[devindex]);
- continue;
- }
- } else {
- jack_error("midiInPrepareHeader error");
- midiInClose(handle);
- continue;
- }
- } else {
- jack_error ("midiInOpen error");
- continue;
- }
- devindex += 1;
- }
- fRealCaptureChannels = devindex;
- fCaptureChannels = devindex;
-
- fMidiSource = new MidiSlot[fRealPlaybackChannels];
- assert(fMidiSource);
-
- // Real output
- devindex = 0;
- for (int i = 0; i < fRealPlaybackChannels; i++) {
- MMRESULT res;
- HMIDIOUT handle;
- fMidiSource[devindex].fIndex = i;
- UINT ret = midiOutOpen(&handle, fMidiSource[devindex].fIndex, 0L, 0L, CALLBACK_NULL);
- if (ret == MMSYSERR_NOERROR) {
- fMidiSource[devindex].fHandle = handle;
- if (!InitHeaders(&fMidiSource[devindex])) {
- jack_error("memory allocation failed");
- midiOutClose(handle);
- continue;
- }
- res = midiOutPrepareHeader(handle, fMidiSource[devindex].fHeader, sizeof(MIDIHDR));
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiOutPrepareHeader error %d %d %d", i, handle, res);
- continue;
- } else {
- fMidiSource[devindex].fHeader->dwUser = 1;
- }
- } else {
- jack_error("midiOutOpen error");
- continue;
- }
- devindex += 1;
- }
- fRealPlaybackChannels = devindex;
- fPlaybackChannels = devindex;
- return 0;
- }
-
- void JackWinMMEDriver::CloseInput(MidiSlot* slot)
- {
- MMRESULT res;
- int retry = 0;
-
- if (slot->fHandle == 0)
- return;
-
- HMIDIIN handle = (HMIDIIN)slot->fHandle;
- slot->fHeader->dwUser = 0;
- res = midiInStop(handle);
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiInStop error");
- }
- res = midiInReset(handle);
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiInReset error");
- }
- res = midiInUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiInUnprepareHeader error");
- }
- do {
- res = midiInClose(handle);
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiInClose error");
- }
- if (res == MIDIERR_STILLPLAYING)
- midiInReset(handle);
- Sleep (10);
- retry++;
- } while ((res == MIDIERR_STILLPLAYING) && (retry < 10));
-
- if (slot->fHeader) {
- GlobalFreePtr(slot->fHeader);
- }
- }
-
- void JackWinMMEDriver::CloseOutput(MidiSlot* slot)
- {
- MMRESULT res;
- int retry = 0;
-
- if (slot->fHandle == 0)
- return;
-
- HMIDIOUT handle = (HMIDIOUT)slot->fHandle;
- res = midiOutReset(handle);
- if (res != MMSYSERR_NOERROR)
- jack_error("midiOutReset error");
- midiOutUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
- do {
- res = midiOutClose(handle);
- if (res != MMSYSERR_NOERROR)
- jack_error("midiOutClose error");
- Sleep(10);
- retry++;
- } while ((res == MIDIERR_STILLPLAYING) && (retry < 10));
-
- if (slot->fHeader) {
- GlobalFreePtr(slot->fHeader);
- }
- }
-
- int JackWinMMEDriver::Close()
- {
- jack_log("JackWinMMEDriver::Close");
-
- // Close input
- if (fMidiDestination) {
- for (int i = 0; i < fRealCaptureChannels; i++) {
- CloseInput(&fMidiDestination[i]);
- }
- delete[] fMidiDestination;
- }
-
- // Close output
- if (fMidiSource) {
- for (int i = 0; i < fRealPlaybackChannels; i++) {
- CloseOutput(&fMidiSource[i]);
- }
- delete[] fMidiSource;
- }
-
- return 0;
- }
-
- int JackWinMMEDriver::Attach()
- {
- JackPort* port;
- jack_port_id_t port_index;
- char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
- char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
- MMRESULT res;
- int i;
-
- jack_log("JackMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
-
- for (i = 0; i < fCaptureChannels; i++) {
- MIDIINCAPS caps;
- res = midiInGetDevCaps(fMidiDestination[i].fIndex, &caps, sizeof(caps));
- if (res == MMSYSERR_NOERROR) {
- snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
- } else {
- snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
- }
- snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
-
- if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
- jack_error("driver: cannot register port for %s", name);
- return -1;
- }
- port = fGraphManager->GetPort(port_index);
- port->SetAlias(alias);
- fCapturePortList[i] = port_index;
- jack_log("JackMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
- }
-
- for (i = 0; i < fPlaybackChannels; i++) {
- MIDIOUTCAPS caps;
- res = midiOutGetDevCaps(fMidiSource[i].fIndex, &caps, sizeof(caps));
- if (res == MMSYSERR_NOERROR) {
- snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
- } else {
- snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fPlaybackDriverName, i + 1);
- }
- snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
-
- if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
- jack_error("driver: cannot register port for %s", name);
- return -1;
- }
- port = fGraphManager->GetPort(port_index);
- port->SetAlias(alias);
- fPlaybackPortList[i] = port_index;
- jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
- }
-
- return 0;
- }
-
- int JackWinMMEDriver::Read()
- {
- size_t size;
-
- for (int chan = 0; chan < fCaptureChannels; chan++) {
-
- if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) {
-
- JackMidiBuffer* midi_buffer = GetInputBuffer(chan);
-
- if (jack_ringbuffer_read_space (fRingBuffer[chan]) == 0) {
- // Reset buffer
- midi_buffer->Reset(midi_buffer->nframes);
- } else {
-
- while ((size = jack_ringbuffer_read_space (fRingBuffer[chan])) > 0) {
-
- //jack_info("jack_ringbuffer_read_space %d", size);
- int ev_count = 0;
- jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int));
-
- if (ev_count > 0) {
- for (int j = 0; j < ev_count; j++) {
- unsigned int event_len = 3;
- // Read event actual data
- jack_midi_data_t* dest = midi_buffer->ReserveEvent(0, event_len);
- jack_ringbuffer_read(fRingBuffer[chan], (char*)dest, event_len);
- }
- }
- }
- }
- } else {
- //jack_info("Consume ring buffer");
- jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan]));
- }
- }
- return 0;
- }
-
- int JackWinMMEDriver::Write()
- {
- for (int chan = 0; chan < fPlaybackChannels; chan++) {
-
- if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) {
-
- JackMidiBuffer* midi_buffer = GetOutputBuffer(chan);
-
- // TODO : use timestamp
-
- for (unsigned int j = 0; j < midi_buffer->event_count; j++) {
- JackMidiEvent* ev = &midi_buffer->events[j];
- if (ev->size <= 3) {
- jack_midi_data_t *d = ev->GetData(midi_buffer);
- DWORD winev = 0;
- if (ev->size > 0) winev |= d[0];
- if (ev->size > 1) winev |= (d[1] << 8);
- if (ev->size > 2) winev |= (d[2] << 16);
- MMRESULT res = midiOutShortMsg((HMIDIOUT)fMidiSource[chan].fHandle, winev);
- if (res != MMSYSERR_NOERROR)
- jack_error ("midiOutShortMsg error res %d", res);
- } else {
-
- }
- }
- }
- }
-
- return 0;
- }
-
- } // end of namespace
-
- #ifdef __cplusplus
- extern "C"
- {
- #endif
-
- SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
- {
- jack_driver_desc_t * desc;
- //unsigned int i;
-
- desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
- strcpy(desc->name, "winmme"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
- strcpy(desc->desc, "WinMME API based MIDI backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
-
- desc->nparams = 0;
- desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
-
- return desc;
- }
-
- SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
- {
- /*
- unsigned int capture_ports = 2;
- unsigned int playback_ports = 2;
- unsigned long wait_time = 0;
- const JSList * node;
- const jack_driver_param_t * param;
- bool monitor = false;
-
- for (node = params; node; node = jack_slist_next (node)) {
- param = (const jack_driver_param_t *) node->data;
-
- switch (param->character) {
-
- case 'C':
- capture_ports = param->value.ui;
- break;
-
- case 'P':
- playback_ports = param->value.ui;
- break;
-
- case 'r':
- sample_rate = param->value.ui;
- break;
-
- case 'p':
- period_size = param->value.ui;
- break;
-
- case 'w':
- wait_time = param->value.ui;
- break;
-
- case 'm':
- monitor = param->value.i;
- break;
- }
- }
- */
-
- Jack::JackDriverClientInterface* driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
- if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
- return driver;
- } else {
- delete driver;
- return NULL;
- }
- }
-
- #ifdef __cplusplus
- }
- #endif
-
-
- /*
- jack_connect system:midi_capture_1 system_midi:playback_1
- jack_connect system:midi_capture_1 system_midi:playback_2
-
- jack_connect system:midi_capture_1 system_midi:playback_1
-
- jack_connect system:midi_capture_1 system_midi:playback_1
-
- jack_connect system:midi_capture_1 system_midi:playback_1
-
- jack_connect system_midi:capture_1 system:midi_playback_1
- jack_connect system_midi:capture_2 system:midi_playback_1
-
- jack_connect system_midi:capture_1 system_midi:playback_1
-
- */
|