Commit e506d99c authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

winecoreaudio: Move midi_init and midi_release to the unixlib.

midi_init temporarily returns unix-side info, which will eventually be removed. Signed-off-by: 's avatarHuw Davies <huw@codeweavers.com> Signed-off-by: 's avatarAndrew Eikum <aeikum@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent dcbbe185
......@@ -1629,4 +1629,6 @@ unixlib_entry_t __wine_unix_call_funcs[] =
get_frequency,
is_started,
set_volumes,
midi_init,
midi_release,
};
......@@ -21,46 +21,90 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#include "config.h"
#include <CoreMIDI/CoreMIDI.h>
#define ULONG __carbon_ULONG
#define E_INVALIDARG __carbon_E_INVALIDARG
#define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY
#define E_HANDLE __carbon_E_HANDLE
#define E_ACCESSDENIED __carbon_E_ACCESSDENIED
#define E_UNEXPECTED __carbon_E_UNEXPECTED
#define E_FAIL __carbon_E_FAIL
#define E_ABORT __carbon_E_ABORT
#define E_POINTER __carbon_E_POINTER
#define E_NOINTERFACE __carbon_E_NOINTERFACE
#define E_NOTIMPL __carbon_E_NOTIMPL
#define S_FALSE __carbon_S_FALSE
#define S_OK __carbon_S_OK
#define HRESULT_FACILITY __carbon_HRESULT_FACILITY
#define IS_ERROR __carbon_IS_ERROR
#define FAILED __carbon_FAILED
#define SUCCEEDED __carbon_SUCCEEDED
#define MAKE_HRESULT __carbon_MAKE_HRESULT
#define HRESULT __carbon_HRESULT
#define STDMETHODCALLTYPE __carbon_STDMETHODCALLT
#include <mach/mach_time.h>
#include <CoreMIDI/CoreMIDI.h>
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h>
#undef ULONG
#undef E_INVALIDARG
#undef E_OUTOFMEMORY
#undef E_HANDLE
#undef E_ACCESSDENIED
#undef E_UNEXPECTED
#undef E_FAIL
#undef E_ABORT
#undef E_POINTER
#undef E_NOINTERFACE
#undef E_NOTIMPL
#undef S_FALSE
#undef S_OK
#undef HRESULT_FACILITY
#undef IS_ERROR
#undef FAILED
#undef SUCCEEDED
#undef MAKE_HRESULT
#undef HRESULT
#undef STDMETHODCALLTYPE
#include "coremidi.h"
MIDIClientRef CoreMIDI_CreateClient(CFStringRef name)
{
MIDIClientRef client = 0;
if (MIDIClientCreate(name, NULL /* FIXME use notify proc */, NULL, &client) != noErr)
return 0;
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winreg.h"
#include "mmsystem.h"
#include "mmddk.h"
#include "mmdeviceapi.h"
#include "audioclient.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "wine/unixlib.h"
return client;
}
#include "coremidi.h"
#include "unixlib.h"
void CoreMIDI_GetObjectName(MIDIObjectRef obj, char *name, int size)
{
OSStatus err = noErr;
CFStringRef cfname;
WINE_DEFAULT_DEBUG_CHANNEL(midi);
err = MIDIObjectGetStringProperty(obj, kMIDIPropertyName, &cfname);
if (err == noErr)
{
CFStringGetCString(cfname, name, size, kCFStringEncodingASCII);
CFRelease(cfname);
}
}
static MIDIClientRef midi_client;
static MIDIPortRef midi_out_port, midi_in_port;
static UINT num_dests, num_srcs;
static struct midi_dest *dests;
static struct midi_src *srcs;
static CFStringRef midi_in_thread_port_name;
/*
* CoreMIDI IO threaded callback,
* we can't call Wine debug channels, critical section or anything using NtCurrentTeb here.
*/
void MIDIIn_ReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
static void midi_in_read_proc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
{
CFMessagePortRef msg_port = CFMessagePortCreateRemote(kCFAllocatorDefault, MIDIInThreadPortName);
CFMessagePortRef msg_port = CFMessagePortCreateRemote(kCFAllocatorDefault, midi_in_thread_port_name);
MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
CFMutableDataRef data;
MIDIMessage msg;
......@@ -82,3 +126,140 @@ void MIDIIn_ReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefC
}
CFRelease(msg_port);
}
NTSTATUS midi_init(void *args)
{
CFStringRef name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("wineMIDIClient.%d"), getpid());
struct midi_init_params *params = args;
OSStatus sc;
UINT i;
sc = MIDIClientCreate(name, NULL /* FIXME use notify proc */, NULL, &midi_client);
CFRelease(name);
if (sc)
{
ERR("can't create MIDI Client\n");
*params->err = DRV_FAILURE;
return STATUS_SUCCESS;
}
num_dests = MAX_MIDI_SYNTHS + MIDIGetNumberOfDestinations();
num_srcs = MIDIGetNumberOfSources();
TRACE("num_dests %d num_srcs %d\n", num_dests, num_srcs);
dests = calloc(num_dests, sizeof(*dests));
srcs = calloc(num_srcs, sizeof(*srcs));
if (num_srcs > 0)
{
midi_in_thread_port_name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("MIDIInThreadPortName.%u"), getpid());
name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineInputPort.%u"), getpid());
MIDIInputPortCreate(midi_client, name, midi_in_read_proc, NULL, &midi_in_port);
CFRelease(name);
}
if (num_dests > MAX_MIDI_SYNTHS)
{
name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineOutputPort.%u"), getpid());
MIDIOutputPortCreate(midi_client, name, &midi_out_port);
CFRelease(name);
}
/* initialize sources */
for (i = 0; i < num_srcs; i++)
{
srcs[i].wDevID = i;
srcs[i].source = MIDIGetSource(i);
sc = MIDIObjectGetStringProperty(srcs[i].source, kMIDIPropertyName, &name);
if (!sc)
{
int len = min(CFStringGetLength(name), ARRAY_SIZE(srcs[i].caps.szPname) - 1);
CFStringGetCharacters(name, CFRangeMake(0, len), srcs[i].caps.szPname);
srcs[i].caps.szPname[len] = '\0';
}
MIDIPortConnectSource(midi_in_port, srcs[i].source, &srcs[i].wDevID);
srcs[i].state = 0;
/* FIXME */
srcs[i].caps.wMid = 0x00FF; /* Manufac ID */
srcs[i].caps.wPid = 0x0001; /* Product ID */
srcs[i].caps.vDriverVersion = 0x0001;
srcs[i].caps.dwSupport = 0;
}
/* initialise MIDI synths */
for (i = 0; i < MAX_MIDI_SYNTHS; i++)
{
static const WCHAR synth_name[] = {'C','o','r','e','A','u','d','i','o',' ','M','I','D','I',' ','S','y','n','t','h',' '};
C_ASSERT(MAX_MIDI_SYNTHS < 10);
memcpy(dests[i].caps.szPname, synth_name, sizeof(synth_name));
dests[i].caps.szPname[ARRAY_SIZE(synth_name)] = '1' + i;
dests[i].caps.szPname[ARRAY_SIZE(synth_name) + 1] = '\0';
dests[i].caps.wTechnology = MOD_SYNTH;
dests[i].caps.wChannelMask = 0xFFFF;
dests[i].caps.wMid = 0x00FF; /* Manufac ID */
dests[i].caps.wPid = 0x0001; /* Product ID */
dests[i].caps.vDriverVersion = 0x0001;
dests[i].caps.dwSupport = MIDICAPS_VOLUME;
dests[i].caps.wVoices = 16;
dests[i].caps.wNotes = 16;
}
/* initialise available destinations */
for (i = MAX_MIDI_SYNTHS; i < num_dests; i++)
{
dests[i].dest = MIDIGetDestination(i - MAX_MIDI_SYNTHS);
sc = MIDIObjectGetStringProperty(dests[i].dest, kMIDIPropertyName, &name);
if (!sc)
{
int len = min(CFStringGetLength(name), ARRAY_SIZE(dests[i].caps.szPname) - 1);
CFStringGetCharacters(name, CFRangeMake(0, len), dests[i].caps.szPname);
dests[i].caps.szPname[len] = '\0';
}
dests[i].caps.wTechnology = MOD_MIDIPORT;
dests[i].caps.wChannelMask = 0xFFFF;
dests[i].caps.wMid = 0x00FF; /* Manufac ID */
dests[i].caps.wPid = 0x0001;
dests[i].caps.vDriverVersion = 0x0001;
dests[i].caps.dwSupport = 0;
dests[i].caps.wVoices = 0;
dests[i].caps.wNotes = 0;
}
params->num_dests = num_dests;
params->num_srcs = num_srcs;
params->dests = dests;
params->srcs = srcs;
params->midi_out_port = (void *)midi_out_port;
params->midi_in_port = (void *)midi_in_port;
*params->err = DRV_SUCCESS;
return STATUS_SUCCESS;
}
NTSTATUS midi_release(void *args)
{
CFMessagePortRef msg_port;
if (num_srcs)
{
/* Stop CFRunLoop in MIDIIn_MessageThread */
msg_port = CFMessagePortCreateRemote(kCFAllocatorDefault, midi_in_thread_port_name);
CFMessagePortSendRequest(msg_port, 1, NULL, 0.0, 0.0, NULL, NULL);
CFRelease(msg_port);
}
if (midi_client) MIDIClientDispose(midi_client); /* MIDIClientDispose will close all ports */
free(srcs);
free(dests);
return STATUS_SUCCESS;
}
......@@ -23,6 +23,8 @@
#include <CoreFoundation/CoreFoundation.h>
#define MAX_MIDI_SYNTHS 1
#ifdef WINE_DEFINITIONS
/*
* Due to CoreMIDI headers conflict redefine some types for Wine
......@@ -73,7 +75,31 @@ extern void MIDIIn_ReadProc(const MIDIPacketList *pktlist, void *refCon, void *c
extern void MIDIOut_Send(MIDIPortRef port, MIDIEndpointRef dest, UInt8 *buffer, unsigned length);
/* midi.c */
extern CFStringRef MIDIInThreadPortName;
typedef struct midi_dest
{
/* graph and synth are only used for MIDI Synth */
AUGraph graph;
AudioUnit synth;
MIDIEndpointRef dest;
MIDIOUTCAPSW caps;
MIDIOPENDESC midiDesc;
WORD wFlags;
} MIDIDestination;
typedef struct midi_src
{
MIDIEndpointRef source;
WORD wDevID;
int state; /* 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */
MIDIINCAPSW caps;
MIDIOPENDESC midiDesc;
LPMIDIHDR lpQueueHdr;
WORD wFlags;
DWORD startTime;
} MIDISource;
typedef struct {
UInt16 devID;
......
......@@ -35,9 +35,13 @@
#include "winuser.h"
#include "winnls.h"
#include "mmddk.h"
#include "mmdeviceapi.h"
#include "audioclient.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/unixlib.h"
#include "coreaudio.h"
#include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(midi);
......@@ -46,45 +50,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(midi);
#define WINE_DEFINITIONS
#include "coremidi.h"
static MIDIClientRef wineMIDIClient = NULL;
static DWORD MIDIOut_NumDevs = 0;
static DWORD MIDIIn_NumDevs = 0;
typedef struct tagMIDIDestination {
/* graph and synth are only used for MIDI Synth */
AUGraph graph;
AudioUnit synth;
MIDIEndpointRef dest;
MIDIOUTCAPSW caps;
MIDIOPENDESC midiDesc;
WORD wFlags;
} MIDIDestination;
typedef struct tagMIDISource {
MIDIEndpointRef source;
WORD wDevID;
int state; /* 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */
MIDIINCAPSW caps;
MIDIOPENDESC midiDesc;
LPMIDIHDR lpQueueHdr;
WORD wFlags;
DWORD startTime;
} MIDISource;
static CRITICAL_SECTION midiInLock; /* Critical section for MIDI In */
CFStringRef MIDIInThreadPortName = NULL;
static CFStringRef MIDIInThreadPortName;
static DWORD WINAPI MIDIIn_MessageThread(LPVOID p);
static MIDIPortRef MIDIInPort = NULL;
static MIDIPortRef MIDIOutPort = NULL;
#define MAX_MIDI_SYNTHS 1
MIDIDestination *destinations;
MIDISource *sources;
......@@ -92,127 +68,52 @@ extern int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth);
extern int SynthUnit_Initialize(AudioUnit synth, AUGraph graph);
extern int SynthUnit_Close(AUGraph graph);
LONG CoreAudio_MIDIInit(void)
static LONG CoreAudio_MIDIInit(void)
{
int i;
CHAR szPname[MAXPNAMELEN] = {0};
struct midi_init_params params;
DWORD err;
int numDest = MIDIGetNumberOfDestinations();
CFStringRef name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("wineMIDIClient.%d"), getpid());
params.err = &err;
wineMIDIClient = CoreMIDI_CreateClient( name );
if (wineMIDIClient == NULL)
UNIX_CALL(midi_init, &params);
if (err != DRV_SUCCESS)
{
CFRelease(name);
ERR("can't create wineMIDIClient\n");
return DRV_FAILURE;
ERR("can't create midi client\n");
return err;
}
CFRelease(name);
MIDIOut_NumDevs = MAX_MIDI_SYNTHS;
MIDIOut_NumDevs += numDest;
MIDIIn_NumDevs = MIDIGetNumberOfSources();
TRACE("MIDIOut_NumDevs %d MIDIIn_NumDevs %d\n", MIDIOut_NumDevs, MIDIIn_NumDevs);
destinations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MIDIOut_NumDevs * sizeof(MIDIDestination));
sources = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MIDIIn_NumDevs * sizeof(MIDISource));
MIDIOut_NumDevs = params.num_dests;
MIDIIn_NumDevs = params.num_srcs;
destinations = params.dests;
sources = params.srcs;
MIDIOutPort = params.midi_out_port;
MIDIInPort = params.midi_in_port;
if (MIDIIn_NumDevs > 0)
{
InitializeCriticalSection(&midiInLock);
midiInLock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": midiInLock");
MIDIInThreadPortName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("MIDIInThreadPortName.%u"), getpid());
CloseHandle( CreateThread(NULL, 0, MIDIIn_MessageThread, NULL, 0, NULL));
name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineInputPort.%u"), getpid());
MIDIInputPortCreate(wineMIDIClient, name, MIDIIn_ReadProc, NULL, &MIDIInPort);
CFRelease(name);
}
if (numDest > 0)
{
name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineOutputPort.%u"), getpid());
MIDIOutputPortCreate(wineMIDIClient, name, &MIDIOutPort);
CFRelease(name);
}
/* initialize sources */
for (i = 0; i < MIDIIn_NumDevs; i++)
{
sources[i].wDevID = i;
sources[i].source = MIDIGetSource(i);
CoreMIDI_GetObjectName(sources[i].source, szPname, sizeof(szPname));
MultiByteToWideChar(CP_ACP, 0, szPname, -1, sources[i].caps.szPname, ARRAY_SIZE(sources[i].caps.szPname));
MIDIPortConnectSource(MIDIInPort, sources[i].source, &sources[i].wDevID);
sources[i].state = 0;
/* FIXME */
sources[i].caps.wMid = 0x00FF; /* Manufac ID */
sources[i].caps.wPid = 0x0001; /* Product ID */
sources[i].caps.vDriverVersion = 0x0001;
sources[i].caps.dwSupport = 0;
}
/* initialise MIDI synths */
for (i = 0; i < MAX_MIDI_SYNTHS; i++)
{
snprintf(szPname, sizeof(szPname), "CoreAudio MIDI Synth %d", i);
MultiByteToWideChar(CP_ACP, 0, szPname, -1, destinations[i].caps.szPname, ARRAY_SIZE(destinations[i].caps.szPname));
destinations[i].caps.wTechnology = MOD_SYNTH;
destinations[i].caps.wChannelMask = 0xFFFF;
destinations[i].caps.wMid = 0x00FF; /* Manufac ID */
destinations[i].caps.wPid = 0x0001; /* Product ID */
destinations[i].caps.vDriverVersion = 0x0001;
destinations[i].caps.dwSupport = MIDICAPS_VOLUME;
destinations[i].caps.wVoices = 16;
destinations[i].caps.wNotes = 16;
}
/* initialise available destinations */
for (i = MAX_MIDI_SYNTHS; i < numDest + MAX_MIDI_SYNTHS; i++)
{
destinations[i].dest = MIDIGetDestination(i - MAX_MIDI_SYNTHS);
CoreMIDI_GetObjectName(destinations[i].dest, szPname, sizeof(szPname));
MultiByteToWideChar(CP_ACP, 0, szPname, -1, destinations[i].caps.szPname, ARRAY_SIZE(destinations[i].caps.szPname));
destinations[i].caps.wTechnology = MOD_MIDIPORT;
destinations[i].caps.wChannelMask = 0xFFFF;
destinations[i].caps.wMid = 0x00FF; /* Manufac ID */
destinations[i].caps.wPid = 0x0001;
destinations[i].caps.vDriverVersion = 0x0001;
destinations[i].caps.dwSupport = 0;
destinations[i].caps.wVoices = 0;
destinations[i].caps.wNotes = 0;
}
return DRV_SUCCESS;
return err;
}
LONG CoreAudio_MIDIRelease(void)
static LONG CoreAudio_MIDIRelease(void)
{
TRACE("\n");
UNIX_CALL(midi_release, NULL);
sources = NULL;
destinations = NULL;
if (MIDIIn_NumDevs > 0)
{
CFMessagePortRef messagePort;
/* Stop CFRunLoop in MIDIIn_MessageThread */
messagePort = CFMessagePortCreateRemote(kCFAllocatorDefault, MIDIInThreadPortName);
CFMessagePortSendRequest(messagePort, 1, NULL, 0.0, 0.0, NULL, NULL);
CFRelease(messagePort);
midiInLock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&midiInLock);
}
if (wineMIDIClient) MIDIClientDispose(wineMIDIClient); /* MIDIClientDispose will close all ports */
HeapFree(GetProcessHeap(), 0, sources);
HeapFree(GetProcessHeap(), 0, destinations);
return DRV_SUCCESS;
}
......
......@@ -182,6 +182,14 @@ struct set_volumes_params
int channel;
};
struct midi_init_params
{
DWORD *err;
UINT num_dests, num_srcs;
void *dests, *srcs;
void *midi_out_port, *midi_in_port;
};
enum unix_funcs
{
unix_get_endpoint_ids,
......@@ -204,8 +212,13 @@ enum unix_funcs
unix_get_frequency,
unix_is_started,
unix_set_volumes,
unix_midi_init,
unix_midi_release,
};
NTSTATUS midi_init( void * ) DECLSPEC_HIDDEN;
NTSTATUS midi_release( void * ) DECLSPEC_HIDDEN;
extern unixlib_handle_t coreaudio_handle;
#define UNIX_CALL( func, params ) __wine_unix_call( coreaudio_handle, unix_ ## func, params )
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment