0N/A/*
2362N/A * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#define USE_ERROR
0N/A#define USE_TRACE
0N/A
0N/A#include "PLATFORM_API_WinOS_Util.h"
0N/A
0N/A#if USE_PLATFORM_MIDI_OUT == TRUE
0N/A
0N/A
0N/A#ifdef USE_ERROR
0N/A#include <stdio.h>
0N/A#define MIDIOUT_CHECK_ERROR { \
0N/A if (err != MMSYSERR_NOERROR) \
0N/A ERROR3("MIDI OUT Error in %s:%d : %s\n", __FILE__, __LINE__, MIDI_OUT_GetErrorStr((INT32) err)); \
0N/A }
0N/A#else
0N/A#define MIDIOUT_CHECK_ERROR
0N/A#endif
0N/A
0N/A/* *************************** MidiOutDeviceProvider implementation *********************************** */
0N/A
0N/A/* not thread safe */
0N/Astatic char winMidiOutErrMsg[WIN_MAX_ERROR_LEN];
0N/A
0N/Achar* MIDI_OUT_GetErrorStr(INT32 err) {
0N/A winMidiOutErrMsg[0] = 0;
0N/A midiOutGetErrorText((MMRESULT) err, winMidiOutErrMsg, WIN_MAX_ERROR_LEN);
0N/A return winMidiOutErrMsg;
0N/A}
0N/A
0N/AINT32 MIDI_OUT_GetNumDevices() {
0N/A // add one for the MIDI_MAPPER
0N/A // we want to return it first so it'll be the default, so we
0N/A // decrement each deviceID for these methods....
0N/A return (INT32) (midiOutGetNumDevs() + 1);
0N/A}
0N/A
0N/A
0N/AINT32 getMidiOutCaps(INT32 deviceID, MIDIOUTCAPS* caps, INT32* err) {
0N/A if (deviceID == 0) {
0N/A deviceID = MIDI_MAPPER;
0N/A } else {
0N/A deviceID--;
0N/A }
0N/A (*err) = (INT32) midiOutGetDevCaps(deviceID, caps, sizeof(MIDIOUTCAPS));
0N/A return ((*err) == MMSYSERR_NOERROR);
0N/A}
0N/A
0N/A
0N/AINT32 MIDI_OUT_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength) {
0N/A MIDIOUTCAPS midiOutCaps;
0N/A INT32 err;
0N/A
0N/A if (getMidiOutCaps(deviceID, &midiOutCaps, &err)) {
0N/A strncpy(name, midiOutCaps.szPname, nameLength-1);
0N/A name[nameLength-1] = 0;
0N/A return MIDI_SUCCESS;
0N/A }
0N/A MIDIOUT_CHECK_ERROR;
0N/A return err;
0N/A}
0N/A
0N/A
0N/AINT32 MIDI_OUT_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength) {
0N/A return MIDI_NOT_SUPPORTED;
0N/A}
0N/A
0N/A
0N/AINT32 MIDI_OUT_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength) {
0N/A MIDIOUTCAPS midiOutCaps;
0N/A char *desc;
0N/A INT32 err;
0N/A
0N/A if (getMidiOutCaps(deviceID, &midiOutCaps, &err)) {
0N/A int tech = (int)midiOutCaps.wTechnology;
0N/A switch(tech) {
0N/A case MOD_MIDIPORT:
0N/A desc = "External MIDI Port";
0N/A break;
0N/A case MOD_SQSYNTH:
0N/A desc = "Internal square wave synthesizer";
0N/A break;
0N/A case MOD_FMSYNTH:
0N/A desc = "Internal FM synthesizer";
0N/A break;
0N/A case MOD_SYNTH:
0N/A desc = "Internal synthesizer (generic)";
0N/A break;
0N/A case MOD_MAPPER:
0N/A desc = "Windows MIDI_MAPPER";
0N/A break;
0N/A case 7 /* MOD_SWSYNTH*/:
0N/A desc = "Internal software synthesizer";
0N/A break;
0N/A default:
0N/A return MIDI_NOT_SUPPORTED;
0N/A }
0N/A strncpy(name, desc, nameLength-1);
0N/A name[nameLength-1] = 0;
0N/A return MIDI_SUCCESS;
0N/A }
0N/A return err;
0N/A}
0N/A
0N/A
0N/AINT32 MIDI_OUT_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength) {
0N/A MIDIOUTCAPS midiOutCaps;
0N/A INT32 err;
0N/A
0N/A if (getMidiOutCaps(deviceID, &midiOutCaps, &err) && nameLength>7) {
0N/A sprintf(name, "%d.%d", (midiOutCaps.vDriverVersion & 0xFF00) >> 8, midiOutCaps.vDriverVersion & 0xFF);
0N/A return MIDI_SUCCESS;
0N/A }
0N/A MIDIOUT_CHECK_ERROR;
0N/A return err;
0N/A}
0N/A
0N/A
0N/A/* *************************** MidiOutDevice implementation ***************************************** */
0N/A
0N/A
0N/AINT32 unprepareLongBuffers(MidiDeviceHandle* handle) {
0N/A SysExQueue* sysex;
0N/A MMRESULT err = MMSYSERR_NOERROR;
0N/A int i;
0N/A
0N/A if (!handle || !handle->deviceHandle || !handle->longBuffers) {
0N/A ERROR0("MIDI_OUT_unprepareLongBuffers: handle, deviceHandle, or longBuffers == NULL\n");
0N/A return MIDI_INVALID_HANDLE;
0N/A }
0N/A sysex = (SysExQueue*) handle->longBuffers;
0N/A for (i = 0; i<sysex->count; i++) {
0N/A MIDIHDR* hdr = &(sysex->header[i]);
0N/A if (hdr->dwFlags) {
0N/A err = midiOutUnprepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
0N/A }
0N/A }
0N/A MIDIOUT_CHECK_ERROR;
0N/A return (INT32) err;
0N/A}
0N/A
0N/AINT32 freeLongBuffer(MIDIHDR* hdr, HMIDIOUT deviceHandle, INT32 minToLeaveData) {
0N/A MMRESULT err = MMSYSERR_NOERROR;
0N/A
0N/A if (!hdr) {
0N/A ERROR0("MIDI_OUT_freeLongBuffer: hdr == NULL\n");
0N/A return MIDI_INVALID_HANDLE;
0N/A }
0N/A if (hdr->dwFlags && deviceHandle) {
0N/A err = midiOutUnprepareHeader(deviceHandle, hdr, sizeof(MIDIHDR));
0N/A }
0N/A if (hdr->lpData && (((INT32) hdr->dwBufferLength) < minToLeaveData || minToLeaveData < 0)) {
0N/A free(hdr->lpData);
0N/A hdr->lpData=NULL;
0N/A hdr->dwBufferLength=0;
0N/A }
0N/A hdr->dwBytesRecorded=0;
0N/A hdr->dwFlags=0;
0N/A return (INT32) err;
0N/A}
0N/A
0N/AINT32 freeLongBuffers(MidiDeviceHandle* handle) {
0N/A SysExQueue* sysex;
0N/A MMRESULT err = MMSYSERR_NOERROR;
0N/A int i;
0N/A
0N/A if (!handle || !handle->longBuffers) {
0N/A ERROR0("MIDI_OUT_freeLongBuffers: handle or longBuffers == NULL\n");
0N/A return MIDI_INVALID_HANDLE;
0N/A }
0N/A sysex = (SysExQueue*) handle->longBuffers;
0N/A for (i = 0; i<sysex->count; i++) {
0N/A err = freeLongBuffer(&(sysex->header[i]), (HMIDIOUT) handle->deviceHandle, -1);
0N/A }
0N/A MIDIOUT_CHECK_ERROR;
0N/A return (INT32) err;
0N/A}
0N/A
0N/AINT32 MIDI_OUT_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle) {
0N/A MMRESULT err;
0N/A
0N/A TRACE1(">> MIDI_OUT_OpenDevice: deviceID: %d\n", deviceID);
0N/A
0N/A if (deviceID == 0) {
0N/A deviceID = MIDI_MAPPER;
0N/A } else {
0N/A deviceID--;
0N/A }
0N/A#ifdef USE_ERROR
0N/A setvbuf(stdout, NULL, (int)_IONBF, 0);
0N/A setvbuf(stderr, NULL, (int)_IONBF, 0);
0N/A#endif
0N/A
0N/A (*handle) = (MidiDeviceHandle*) malloc(sizeof(MidiDeviceHandle));
0N/A if (!(*handle)) {
0N/A ERROR0("ERROR: MIDI_OUT_OpenDevice: out of memory\n");
0N/A return MIDI_OUT_OF_MEMORY;
0N/A }
0N/A memset(*handle, 0, sizeof(MidiDeviceHandle));
0N/A
0N/A // create long buffer queue
0N/A if (!MIDI_WinCreateEmptyLongBufferQueue(*handle, MIDI_OUT_LONG_QUEUE_SIZE)) {
0N/A ERROR0("ERROR: MIDI_OUT_OpenDevice: could not create long Buffers\n");
0N/A free(*handle);
0N/A (*handle) = NULL;
0N/A return MIDI_OUT_OF_MEMORY;
0N/A }
0N/A
0N/A // create notification event
0N/A (*handle)->platformData = (void*) CreateEvent(NULL, FALSE /*manual reset*/, FALSE /*signaled*/, NULL);
0N/A if (!(*handle)->platformData) {
0N/A ERROR0("ERROR: MIDI_OUT_StartDevice: could not create event\n");
0N/A MIDI_WinDestroyLongBufferQueue(*handle);
0N/A free(*handle);
0N/A (*handle) = NULL;
0N/A return MIDI_OUT_OF_MEMORY;
0N/A }
0N/A
0N/A // finally open the device
0N/A err = midiOutOpen((HMIDIOUT*) &((*handle)->deviceHandle), deviceID,
0N/A (UINT_PTR) (*handle)->platformData, (UINT_PTR) (*handle), CALLBACK_EVENT);
0N/A
0N/A if ((err != MMSYSERR_NOERROR) || (!(*handle)->deviceHandle)) {
0N/A /* some devices return non zero, but no error! */
0N/A if (midiOutShortMsg((HMIDIOUT) ((*handle)->deviceHandle),0) == MMSYSERR_INVALHANDLE) {
0N/A MIDIOUT_CHECK_ERROR;
0N/A CloseHandle((HANDLE) (*handle)->platformData);
0N/A MIDI_WinDestroyLongBufferQueue(*handle);
0N/A free(*handle);
0N/A (*handle) = NULL;
0N/A return (INT32) err;
0N/A }
0N/A }
0N/A //$$fb enable high resolution time
0N/A timeBeginPeriod(1);
0N/A MIDI_SetStartTime(*handle);
0N/A TRACE0("<< MIDI_OUT_OpenDevice: succeeded\n");
0N/A return MIDI_SUCCESS;
0N/A}
0N/A
0N/AINT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) {
0N/A MMRESULT err = MMSYSERR_NOERROR;
0N/A HANDLE event;
0N/A
0N/A TRACE0("> MIDI_OUT_CloseDevice\n");
0N/A if (!handle) {
0N/A ERROR0("ERROR: MIDI_OUT_StopDevice: handle is NULL\n");
0N/A return MIDI_INVALID_HANDLE; // failure
0N/A }
0N/A // encourage MIDI_OUT_SendLongMessage to return soon
0N/A event = handle->platformData;
0N/A handle->platformData = NULL;
0N/A if (event) {
0N/A SetEvent(event);
0N/A } else {
0N/A ERROR0("ERROR: MIDI_OUT_StopDevice: event is NULL\n");
0N/A }
0N/A
0N/A if (handle->deviceHandle) {
0N/A //$$fb disable high resolution time
0N/A timeEndPeriod(1);
0N/A err = midiOutReset((HMIDIOUT) handle->deviceHandle);
0N/A } else {
0N/A ERROR0("ERROR: MIDI_OUT_CloseDevice: deviceHandle is NULL\n");
0N/A }
0N/A
0N/A // issue a "SUSTAIN OFF" message to each MIDI channel, 0 to 15.
0N/A // "CONTROL CHANGE" is 176, "SUSTAIN CONTROLLER" is 64, and the value is 0.
0N/A // $$fb 2002-04-04: It is responsability of the application developer to
0N/A // leave the device in a consistent state. So I put this in comments
0N/A /*
0N/A for (channel = 0; channel < 16; channel++)
0N/A MIDI_OUT_SendShortMessage(deviceHandle, (unsigned char)(176 + channel), (unsigned char)64, (unsigned char)0, (UINT32)-1);
0N/A */
0N/A
0N/A if (event) {
0N/A // wait until MIDI_OUT_SendLongMessage has finished
0N/A while (handle->isWaiting) Sleep(0);
0N/A }
0N/A
0N/A unprepareLongBuffers(handle);
0N/A
0N/A if (handle->deviceHandle) {
0N/A err = midiOutClose((HMIDIOUT) handle->deviceHandle);
0N/A MIDIOUT_CHECK_ERROR;
0N/A handle->deviceHandle = NULL;
0N/A }
0N/A freeLongBuffers(handle);
0N/A
0N/A if (event) {
0N/A CloseHandle(event);
0N/A }
0N/A MIDI_WinDestroyLongBufferQueue(handle);
0N/A free(handle);
0N/A
0N/A TRACE0("< MIDI_OUT_CloseDevice\n");
0N/A return (INT32) err;
0N/A}
0N/A
0N/A
0N/A/* return time stamp in microseconds */
0N/AINT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) {
0N/A return MIDI_GetTimeStamp(handle);
0N/A}
0N/A
0N/A
0N/AINT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT32 timestamp) {
0N/A MMRESULT err = MMSYSERR_NOERROR;
0N/A
0N/A TRACE2("> MIDI_OUT_SendShortMessage %x, time: %d\n", packedMsg, timestamp);
0N/A if (!handle) {
0N/A ERROR0("ERROR: MIDI_OUT_SendShortMessage: handle is NULL\n");
0N/A return MIDI_INVALID_HANDLE; // failure
0N/A }
0N/A err = midiOutShortMsg((HMIDIOUT) handle->deviceHandle, packedMsg);
0N/A MIDIOUT_CHECK_ERROR;
0N/A TRACE0("< MIDI_OUT_SendShortMessage\n");
0N/A return (INT32) err;
0N/A}
0N/A
0N/AINT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 size, UINT32 timestamp) {
0N/A MMRESULT err;
0N/A SysExQueue* sysex;
0N/A MIDIHDR* hdr = NULL;
0N/A INT32 remainingSize;
0N/A int i;
0N/A
0N/A TRACE2("> MIDI_OUT_SendLongMessage size %d, time: %d\n", size, timestamp);
0N/A if (!handle || !data || !handle->longBuffers) {
0N/A ERROR0("< ERROR: MIDI_OUT_SendLongMessage: handle, data, or longBuffers is NULL\n");
0N/A return MIDI_INVALID_HANDLE; // failure
0N/A }
0N/A if (size == 0) {
0N/A return MIDI_SUCCESS;
0N/A }
0N/A
0N/A sysex = (SysExQueue*) handle->longBuffers;
0N/A remainingSize = size;
0N/A
0N/A // send in chunks of 512 bytes
0N/A size = 512;
0N/A while (remainingSize > 0) {
0N/A if (remainingSize < (INT32) size) {
0N/A size = (UINT32) remainingSize;
0N/A }
0N/A
0N/A while (!hdr && handle->platformData) {
0N/A /* find a non-queued header */
0N/A for (i = 0; i < sysex->count; i++) {
0N/A hdr = &(sysex->header[i]);
0N/A if ((hdr->dwFlags & MHDR_DONE) || (hdr->dwFlags == 0)) {
0N/A break;
0N/A }
0N/A hdr = NULL;
0N/A }
0N/A /* wait for a buffer to free up */
0N/A if (!hdr && handle->platformData) {
0N/A DWORD res;
0N/A TRACE0(" Need to wait for free buffer\n");
0N/A handle->isWaiting = TRUE;
0N/A res = WaitForSingleObject((HANDLE) handle->platformData, 700);
0N/A handle->isWaiting = FALSE;
0N/A if (res == WAIT_TIMEOUT) {
0N/A // break out back to Java if no buffer freed up after 700 milliseconds
0N/A TRACE0("-> TIMEOUT. Need to go back to Java\n");
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A if (!hdr) {
0N/A // no free buffer
0N/A return MIDI_NOT_SUPPORTED;
0N/A }
0N/A
0N/A TRACE2("-> sending %d bytes with buffer index=%d\n", (int) size, (int) hdr->dwUser);
0N/A freeLongBuffer(hdr, handle->deviceHandle, (INT32) size);
0N/A if (hdr->lpData == NULL) {
0N/A hdr->lpData = malloc(size);
0N/A hdr->dwBufferLength = size;
0N/A }
0N/A hdr->dwBytesRecorded = size;
0N/A memcpy(hdr->lpData, data, size);
0N/A err = midiOutPrepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
0N/A if (err != MMSYSERR_NOERROR) {
0N/A freeLongBuffer(hdr, handle->deviceHandle, -1);
0N/A MIDIOUT_CHECK_ERROR;
0N/A return (INT32) err;
0N/A }
0N/A err = midiOutLongMsg((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
0N/A if (err != MMSYSERR_NOERROR) {
0N/A freeLongBuffer(hdr, handle->deviceHandle, -1);
0N/A ERROR0("ERROR: MIDI_OUT_SendLongMessage: midiOutLongMsg returned error:\n");
0N/A MIDIOUT_CHECK_ERROR;
0N/A return (INT32) err;
0N/A }
0N/A remainingSize -= size;
0N/A data += size;
0N/A }
0N/A TRACE0("< MIDI_OUT_SendLongMessage success\n");
0N/A return MIDI_SUCCESS;
0N/A}
0N/A
0N/A#endif // USE_PLATFORM_MIDI_OUT