diff --git a/extras/audio plugins/demo/Source/PluginProcessor.h b/extras/audio plugins/demo/Source/PluginProcessor.h index bc02e86d16..083fff0410 100644 --- a/extras/audio plugins/demo/Source/PluginProcessor.h +++ b/extras/audio plugins/demo/Source/PluginProcessor.h @@ -32,10 +32,11 @@ public: void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); //============================================================================== + bool hasEditor() const { return true; } AudioProcessorEditor* createEditor(); //============================================================================== - const String getName() const { return JucePlugin_Name; } + const String getName() const { return JucePlugin_Name; } int getNumParameters(); float getParameter (int index); diff --git a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp index e457bec73b..d3600a17e1 100644 --- a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp +++ b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp @@ -352,34 +352,20 @@ public: void open() { - JUCE_AUTORELEASEPOOL - if (editorComp == 0) - { - checkWhetherWavelabHasChangedThread(); - const MessageManagerLock mmLock; - - AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); - - if (ed != 0) - cEffect.flags |= effFlagsHasEditor; - else - cEffect.flags &= ~effFlagsHasEditor; - - filter->editorBeingDeleted (ed); - delete ed; - } - - startTimer (1000 / 4); + // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. + if (filter->hasEditor()) + cEffect.flags |= effFlagsHasEditor; + else + cEffect.flags &= ~effFlagsHasEditor; } void close() { - JUCE_AUTORELEASEPOOL - const NonWavelabMMLock mmLock; - jassert (! recursionCheck); - + // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. stopTimer(); - deleteEditor (false); + + if (MessageManager::getInstance()->isThisTheMessageThread()) + deleteEditor (false); } //============================================================================== @@ -439,8 +425,10 @@ public: { result = 1; } - else if (strcmp (text, "openCloseAnyThread" == 0) + else if (strcmp (text, "openCloseAnyThread") == 0) { + // This tells Wavelab to use the UI thread to invoke open/close, + // like all other hosts do. result = -1; } @@ -770,48 +758,22 @@ public: switch (ti->smpteFrameRate) { - case kVstSmpte24fps: - rate = AudioPlayHead::fps24; - fps = 24.0; - break; - - case kVstSmpte25fps: - rate = AudioPlayHead::fps25; - fps = 25.0; - break; - - case kVstSmpte2997fps: - rate = AudioPlayHead::fps2997; - fps = 29.97; - break; - - case kVstSmpte30fps: - rate = AudioPlayHead::fps30; - fps = 30.0; - break; - - case kVstSmpte2997dfps: - rate = AudioPlayHead::fps2997drop; - fps = 29.97; - break; - - case kVstSmpte30dfps: - rate = AudioPlayHead::fps30drop; - fps = 30.0; - break; - - case kVstSmpteFilm16mm: - case kVstSmpteFilm35mm: - fps = 24.0; - break; - - case kVstSmpte239fps: fps = 23.976; break; - case kVstSmpte249fps: fps = 24.976; break; - case kVstSmpte599fps: fps = 59.94; break; - case kVstSmpte60fps: fps = 60; break; - - default: - jassertfalse // unknown frame-rate.. + case kVstSmpte24fps: rate = AudioPlayHead::fps24; fps = 24.0; break; + case kVstSmpte25fps: rate = AudioPlayHead::fps25; fps = 25.0; break; + case kVstSmpte2997fps: rate = AudioPlayHead::fps2997; fps = 29.97; break; + case kVstSmpte30fps: rate = AudioPlayHead::fps30; fps = 30.0; break; + case kVstSmpte2997dfps: rate = AudioPlayHead::fps2997drop; fps = 29.97; break; + case kVstSmpte30dfps: rate = AudioPlayHead::fps30drop; fps = 30.0; break; + + case kVstSmpteFilm16mm: + case kVstSmpteFilm35mm: fps = 24.0; break; + + case kVstSmpte239fps: fps = 23.976; break; + case kVstSmpte249fps: fps = 24.976; break; + case kVstSmpte599fps: fps = 59.94; break; + case kVstSmpte60fps: fps = 60; break; + + default: jassertfalse; // unknown frame-rate.. } info.frameRate = rate; @@ -1068,6 +1030,7 @@ public: { recursionCheck = true; + JUCE_AUTORELEASEPOOL juce_callAnyTimersSynchronously(); for (int i = ComponentPeer::getNumPeers(); --i >= 0;) @@ -1105,6 +1068,7 @@ public: void deleteEditor (bool canDeleteLaterIfModal) { + JUCE_AUTORELEASEPOOL PopupMenu::dismissAllActiveMenus(); jassert (! recursionCheck); @@ -1161,10 +1125,12 @@ public: } else if (opCode == effEditOpen) { - checkWhetherWavelabHasChangedThread(); + checkWhetherMessageThreadIsCorrect(); const MessageManagerLock mmLock; jassert (! recursionCheck); + startTimer (1000 / 4); // performs misc housekeeping chores + deleteEditor (true); createEditorComp(); @@ -1191,14 +1157,14 @@ public: } else if (opCode == effEditClose) { - checkWhetherWavelabHasChangedThread(); + checkWhetherMessageThreadIsCorrect(); const MessageManagerLock mmLock; deleteEditor (true); return 0; } else if (opCode == effEditGetRect) { - checkWhetherWavelabHasChangedThread(); + checkWhetherMessageThreadIsCorrect(); const MessageManagerLock mmLock; createEditorComp(); @@ -1436,18 +1402,9 @@ private: bool shouldDeleteEditor; //============================================================================== -#if JUCE_WINDOWS // Workarounds for Wavelab's happy-go-lucky use of threads. - class NonWavelabMMLock - { - public: - NonWavelabMMLock() : mm (getHostType().isWavelab() || getHostType().isCubaseBridged() ? 0 : new MessageManagerLock()) {} - ~NonWavelabMMLock() {} - - private: - ScopedPointer mm; - }; - - static void checkWhetherWavelabHasChangedThread() +#if JUCE_WINDOWS + // Workarounds for Wavelab's happy-go-lucky use of threads. + static void checkWhetherMessageThreadIsCorrect() { if (getHostType().isWavelab() || getHostType().isCubaseBridged()) { @@ -1476,8 +1433,7 @@ private: } } #else - typedef MessageManagerLock NonWavelabMMLock; - static void checkWhetherWavelabHasChangedThread() {} + static void checkWhetherMessageThreadIsCorrect() {} #endif //============================================================================== diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 972b529713..25d28e5edb 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -22570,7 +22570,7 @@ END_JUCE_NAMESPACE /* If you've got an include error here, you probably need to install the QuickTime SDK and add its header directory to your include path. - Alternatively, if you don't need any QuickTime services, just turn off the JUC_QUICKTIME + Alternatively, if you don't need any QuickTime services, just turn off the JUCE_QUICKTIME flag in juce_Config.h */ #include @@ -22589,7 +22589,7 @@ BEGIN_JUCE_NAMESPACE bool juce_OpenQuickTimeMovieFromStream (InputStream* input, Movie& movie, Handle& dataHandle); static const char* const quickTimeFormatName = "QuickTime file"; -static const char* const quickTimeExtensions[] = { ".mov", ".mp3", ".mp4", 0 }; +static const char* const quickTimeExtensions[] = { ".mov", ".mp3", ".mp4", ".m4a", 0 }; class QTAudioReader : public AudioFormatReader { @@ -31327,6 +31327,7 @@ public: void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + bool hasEditor() const; AudioProcessorEditor* createEditor(); const String getInputChannelName (int index) const; @@ -32161,6 +32162,11 @@ private: #endif +bool AudioUnitPluginInstance::hasEditor() const +{ + return true; +} + AudioProcessorEditor* AudioUnitPluginInstance::createEditor() { ScopedPointer w (new AudioUnitPluginWindowCocoa (*this, false)); @@ -33424,6 +33430,7 @@ public: void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + bool hasEditor() const { return effect != 0 && (effect->flags & effFlagsHasEditor) != 0; } AudioProcessorEditor* createEditor(); const String getInputChannelName (int index) const; @@ -33494,7 +33501,6 @@ private: const String getVersion() const; const String getCategory() const; - bool hasEditor() const throw() { return effect != 0 && (effect->flags & effFlagsHasEditor) != 0; } void setPower (const bool on); VSTPluginInstance (const ReferenceCountedObjectPtr & module); @@ -35811,6 +35817,9 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() AudioProcessorEditor* const ed = createEditor(); + // You must make your hasEditor() method return a consistent result! + jassert (hasEditor() == (ed != 0)); + if (ed != 0) { // you must give your editor comp a size before returning it.. @@ -37153,10 +37162,8 @@ bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const return type == audioOutputNode || type == midiOutputNode; } -AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() -{ - return 0; -} +bool AudioProcessorGraph::AudioGraphIOProcessor::hasEditor() const { return false; } +AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() { return 0; } int AudioProcessorGraph::AudioGraphIOProcessor::getNumParameters() { return 0; } const String AudioProcessorGraph::AudioGraphIOProcessor::getParameterName (int) { return String::empty; } @@ -252484,65 +252491,72 @@ AudioIODeviceType* juce_createAudioIODeviceType_DirectSound() // compiled on its own). #if JUCE_INCLUDED_FILE && JUCE_WASAPI -#if 1 +#ifndef WASAPI_ENABLE_LOGGING + #define WASAPI_ENABLE_LOGGING 1 +#endif -const String getAudioErrorDesc (HRESULT hr) +namespace WasapiClasses { - const char* e = 0; - switch (hr) +static void logFailure (HRESULT hr) +{ + (void) hr; + + #if WASAPI_ENABLE_LOGGING + if (FAILED (hr)) { - case E_POINTER: e = "E_POINTER"; break; - case E_INVALIDARG: e = "E_INVALIDARG"; break; - case AUDCLNT_E_NOT_INITIALIZED: e = "AUDCLNT_E_NOT_INITIALIZED"; break; - case AUDCLNT_E_ALREADY_INITIALIZED: e = "AUDCLNT_E_ALREADY_INITIALIZED"; break; - case AUDCLNT_E_WRONG_ENDPOINT_TYPE: e = "AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break; - case AUDCLNT_E_DEVICE_INVALIDATED: e = "AUDCLNT_E_DEVICE_INVALIDATED"; break; - case AUDCLNT_E_NOT_STOPPED: e = "AUDCLNT_E_NOT_STOPPED"; break; - case AUDCLNT_E_BUFFER_TOO_LARGE: e = "AUDCLNT_E_BUFFER_TOO_LARGE"; break; - case AUDCLNT_E_OUT_OF_ORDER: e = "AUDCLNT_E_OUT_OF_ORDER"; break; - case AUDCLNT_E_UNSUPPORTED_FORMAT: e = "AUDCLNT_E_UNSUPPORTED_FORMAT"; break; - case AUDCLNT_E_INVALID_SIZE: e = "AUDCLNT_E_INVALID_SIZE"; break; - case AUDCLNT_E_DEVICE_IN_USE: e = "AUDCLNT_E_DEVICE_IN_USE"; break; - case AUDCLNT_E_BUFFER_OPERATION_PENDING: e = "AUDCLNT_E_BUFFER_OPERATION_PENDING"; break; - case AUDCLNT_E_THREAD_NOT_REGISTERED: e = "AUDCLNT_E_THREAD_NOT_REGISTERED"; break; - case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED: e = "AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break; - case AUDCLNT_E_ENDPOINT_CREATE_FAILED: e = "AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break; - case AUDCLNT_E_SERVICE_NOT_RUNNING: e = "AUDCLNT_E_SERVICE_NOT_RUNNING"; break; - case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED: e = "AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break; - case AUDCLNT_E_EXCLUSIVE_MODE_ONLY: e = "AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break; - case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: e = "AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break; - case AUDCLNT_E_EVENTHANDLE_NOT_SET: e = "AUDCLNT_E_EVENTHANDLE_NOT_SET"; break; - case AUDCLNT_E_INCORRECT_BUFFER_SIZE: e = "AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break; - case AUDCLNT_E_BUFFER_SIZE_ERROR: e = "AUDCLNT_E_BUFFER_SIZE_ERROR"; break; - case AUDCLNT_S_BUFFER_EMPTY: e = "AUDCLNT_S_BUFFER_EMPTY"; break; - case AUDCLNT_S_THREAD_ALREADY_REGISTERED: e = "AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break; - default: return String::toHexString ((int) hr); - } + String e; + e << Time::getCurrentTime().toString (true, true, true, true) + << " -- WASAPI error: "; - return e; -} + switch (hr) + { + case E_POINTER: e << "E_POINTER"; break; + case E_INVALIDARG: e << "E_INVALIDARG"; break; + case AUDCLNT_E_NOT_INITIALIZED: e << "AUDCLNT_E_NOT_INITIALIZED"; break; + case AUDCLNT_E_ALREADY_INITIALIZED: e << "AUDCLNT_E_ALREADY_INITIALIZED"; break; + case AUDCLNT_E_WRONG_ENDPOINT_TYPE: e << "AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break; + case AUDCLNT_E_DEVICE_INVALIDATED: e << "AUDCLNT_E_DEVICE_INVALIDATED"; break; + case AUDCLNT_E_NOT_STOPPED: e << "AUDCLNT_E_NOT_STOPPED"; break; + case AUDCLNT_E_BUFFER_TOO_LARGE: e << "AUDCLNT_E_BUFFER_TOO_LARGE"; break; + case AUDCLNT_E_OUT_OF_ORDER: e << "AUDCLNT_E_OUT_OF_ORDER"; break; + case AUDCLNT_E_UNSUPPORTED_FORMAT: e << "AUDCLNT_E_UNSUPPORTED_FORMAT"; break; + case AUDCLNT_E_INVALID_SIZE: e << "AUDCLNT_E_INVALID_SIZE"; break; + case AUDCLNT_E_DEVICE_IN_USE: e << "AUDCLNT_E_DEVICE_IN_USE"; break; + case AUDCLNT_E_BUFFER_OPERATION_PENDING: e << "AUDCLNT_E_BUFFER_OPERATION_PENDING"; break; + case AUDCLNT_E_THREAD_NOT_REGISTERED: e << "AUDCLNT_E_THREAD_NOT_REGISTERED"; break; + case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED: e << "AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break; + case AUDCLNT_E_ENDPOINT_CREATE_FAILED: e << "AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break; + case AUDCLNT_E_SERVICE_NOT_RUNNING: e << "AUDCLNT_E_SERVICE_NOT_RUNNING"; break; + case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED: e << "AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break; + case AUDCLNT_E_EXCLUSIVE_MODE_ONLY: e << "AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break; + case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: e << "AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break; + case AUDCLNT_E_EVENTHANDLE_NOT_SET: e << "AUDCLNT_E_EVENTHANDLE_NOT_SET"; break; + case AUDCLNT_E_INCORRECT_BUFFER_SIZE: e << "AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break; + case AUDCLNT_E_BUFFER_SIZE_ERROR: e << "AUDCLNT_E_BUFFER_SIZE_ERROR"; break; + case AUDCLNT_S_BUFFER_EMPTY: e << "AUDCLNT_S_BUFFER_EMPTY"; break; + case AUDCLNT_S_THREAD_ALREADY_REGISTERED: e << "AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break; + default: e << String::toHexString ((int) hr); break; + } -#define logFailure(hr) { if (FAILED (hr)) { DBG ("WASAPI FAIL! " + getAudioErrorDesc (hr)); jassertfalse; } } -#define OK(a) wasapi_checkResult(a) + DBG (e); + jassertfalse; + } + #endif +} -static bool wasapi_checkResult (HRESULT hr) +static bool check (HRESULT hr) { logFailure (hr); return SUCCEEDED (hr); } -#else - #define logFailure(hr) {} - #define OK(a) SUCCEEDED(a) -#endif - -static const String wasapi_getDeviceID (IMMDevice* const device) +static const String getDeviceID (IMMDevice* const device) { String s; WCHAR* deviceId = 0; - if (OK (device->GetId (&deviceId))) + if (check (device->GetId (&deviceId))) { s = String (deviceId); CoTaskMemFree (deviceId); @@ -252551,22 +252565,22 @@ static const String wasapi_getDeviceID (IMMDevice* const device) return s; } -static EDataFlow wasapi_getDataFlow (IMMDevice* const device) +static EDataFlow getDataFlow (IMMDevice* const device) { EDataFlow flow = eRender; ComSmartPtr endPoint; - if (OK (device->QueryInterface (__uuidof (IMMEndpoint), (void**) &endPoint))) - (void) OK (endPoint->GetDataFlow (&flow)); + if (check (device->QueryInterface (__uuidof (IMMEndpoint), (void**) &endPoint))) + (void) check (endPoint->GetDataFlow (&flow)); return flow; } -static int wasapi_refTimeToSamples (const REFERENCE_TIME& t, const double sampleRate) throw() +static int refTimeToSamples (const REFERENCE_TIME& t, const double sampleRate) throw() { return roundDoubleToInt (sampleRate * ((double) t) * 0.0000001); } -static void wasapi_copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* const src) throw() +static void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* const src) throw() { memcpy (&dest, src, src->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? sizeof (WAVEFORMATEXTENSIBLE) : sizeof (WAVEFORMATEX)); @@ -252593,21 +252607,21 @@ public: return; REFERENCE_TIME defaultPeriod, minPeriod; - if (! OK (tempClient->GetDevicePeriod (&defaultPeriod, &minPeriod))) + if (! check (tempClient->GetDevicePeriod (&defaultPeriod, &minPeriod))) return; WAVEFORMATEX* mixFormat = 0; - if (! OK (tempClient->GetMixFormat (&mixFormat))) + if (! check (tempClient->GetMixFormat (&mixFormat))) return; WAVEFORMATEXTENSIBLE format; - wasapi_copyWavFormat (format, mixFormat); + copyWavFormat (format, mixFormat); CoTaskMemFree (mixFormat); actualNumChannels = numChannels = format.Format.nChannels; defaultSampleRate = format.Format.nSamplesPerSec; - minBufferSize = wasapi_refTimeToSamples (minPeriod, defaultSampleRate); - defaultBufferSize = wasapi_refTimeToSamples (defaultPeriod, defaultSampleRate); + minBufferSize = refTimeToSamples (minPeriod, defaultSampleRate); + defaultBufferSize = refTimeToSamples (defaultPeriod, defaultSampleRate); rates.addUsingDefaultSort (defaultSampleRate); @@ -252657,12 +252671,12 @@ public: channelMaps.add (i); REFERENCE_TIME latency; - if (OK (client->GetStreamLatency (&latency))) - latencySamples = wasapi_refTimeToSamples (latency, sampleRate); + if (check (client->GetStreamLatency (&latency))) + latencySamples = refTimeToSamples (latency, sampleRate); - (void) OK (client->GetBufferSize (&actualBufferSize)); + (void) check (client->GetBufferSize (&actualBufferSize)); - return OK (client->SetEventHandle (clientEvent)); + return check (client->SetEventHandle (clientEvent)); } return false; @@ -252747,7 +252761,7 @@ private: if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec) { - wasapi_copyWavFormat (format, (WAVEFORMATEX*) nearestFormat); + copyWavFormat (format, (WAVEFORMATEX*) nearestFormat); hr = S_OK; } @@ -252755,13 +252769,13 @@ private: REFERENCE_TIME defaultPeriod = 0, minPeriod = 0; if (useExclusiveMode) - OK (client->GetDevicePeriod (&defaultPeriod, &minPeriod)); + check (client->GetDevicePeriod (&defaultPeriod, &minPeriod)); GUID session; if (hr == S_OK - && OK (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session))) + && check (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session))) { actualNumChannels = format.Format.nChannels; const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; @@ -252798,7 +252812,7 @@ public: reservoirCapacity = 16384; reservoir.setSize (actualNumChannels * reservoirCapacity * sizeof (float)); return openClient (newSampleRate, newChannels) - && (numChannels == 0 || OK (client->GetService (__uuidof (IAudioCaptureClient), (void**) &captureClient))); + && (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), (void**) &captureClient))); } void close() @@ -252845,7 +252859,7 @@ public: else { UINT32 packetLength = 0; - if (! OK (captureClient->GetNextPacketSize (&packetLength))) + if (! check (captureClient->GetNextPacketSize (&packetLength))) break; if (packetLength == 0) @@ -252861,7 +252875,7 @@ public: UINT32 numSamplesAvailable; DWORD flags; - if (OK (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, 0, 0))) + if (check (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, 0, 0))) { const int samplesToDo = jmin (bufferSize, (int) numSamplesAvailable); @@ -252910,7 +252924,7 @@ public: bool open (const double newSampleRate, const BigInteger& newChannels) { return openClient (newSampleRate, newChannels) - && (numChannels == 0 || OK (client->GetService (__uuidof (IAudioRenderClient), (void**) &renderClient))); + && (numChannels == 0 || check (client->GetService (__uuidof (IAudioRenderClient), (void**) &renderClient))); } void close() @@ -252943,7 +252957,7 @@ public: while (bufferSize > 0) { UINT32 padding = 0; - if (! OK (client->GetCurrentPadding (&padding))) + if (! check (client->GetCurrentPadding (&padding))) return; int samplesToDo = useExclusiveMode ? bufferSize @@ -252959,7 +252973,7 @@ public: } uint8* outputData = 0; - if (OK (renderClient->GetBuffer (samplesToDo, &outputData))) + if (check (renderClient->GetBuffer (samplesToDo, &outputData))) { for (int i = 0; i < numSrcBuffers; ++i) converter->convertSamples (outputData, channelMaps.getUnchecked(i), srcBuffers[i], offset, samplesToDo); @@ -253313,28 +253327,28 @@ private: bool createDevices() { ComSmartPtr enumerator; - if (! OK (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) + if (! check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) return false; ComSmartPtr deviceCollection; - if (! OK (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &deviceCollection))) + if (! check (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &deviceCollection))) return false; UINT32 numDevices = 0; - if (! OK (deviceCollection->GetCount (&numDevices))) + if (! check (deviceCollection->GetCount (&numDevices))) return false; for (UINT32 i = 0; i < numDevices; ++i) { ComSmartPtr device; - if (! OK (deviceCollection->Item (i, &device))) + if (! check (deviceCollection->Item (i, &device))) continue; - const String deviceId (wasapi_getDeviceID (device)); + const String deviceId (getDeviceID (device)); if (deviceId.isEmpty()) continue; - const EDataFlow flow = wasapi_getDataFlow (device); + const EDataFlow flow = getDataFlow (device); if (deviceId == inputDeviceId && flow == eCapture) inputDevice = new WASAPIInputDevice (device, useExclusiveMode); @@ -253373,7 +253387,7 @@ public: inputDeviceIds.clear(); ComSmartPtr enumerator; - if (! OK (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) + if (! check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) return; const String defaultRenderer = getDefaultEndpoint (enumerator, false); @@ -253382,20 +253396,20 @@ public: ComSmartPtr deviceCollection; UINT32 numDevices = 0; - if (! (OK (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &deviceCollection)) - && OK (deviceCollection->GetCount (&numDevices)))) + if (! (check (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &deviceCollection)) + && check (deviceCollection->GetCount (&numDevices)))) return; for (UINT32 i = 0; i < numDevices; ++i) { ComSmartPtr device; - if (! OK (deviceCollection->Item (i, &device))) + if (! check (deviceCollection->Item (i, &device))) continue; - const String deviceId (wasapi_getDeviceID (device)); + const String deviceId (getDeviceID (device)); DWORD state = 0; - if (! OK (device->GetState (&state))) + if (! check (device->GetState (&state))) continue; if (state != DEVICE_STATE_ACTIVE) @@ -253405,18 +253419,18 @@ public: { ComSmartPtr properties; - if (! OK (device->OpenPropertyStore (STGM_READ, &properties))) + if (! check (device->OpenPropertyStore (STGM_READ, &properties))) continue; PROPVARIANT value; PropVariantInit (&value); - if (OK (properties->GetValue (PKEY_Device_FriendlyName, &value))) + if (check (properties->GetValue (PKEY_Device_FriendlyName, &value))) name = value.pwszVal; PropVariantClear (&value); } - const EDataFlow flow = wasapi_getDataFlow (device); + const EDataFlow flow = getDataFlow (device); if (flow == eRender) { @@ -253498,11 +253512,11 @@ private: { String s; IMMDevice* dev = 0; - if (OK (enumerator->GetDefaultAudioEndpoint (forCapture ? eCapture : eRender, - eMultimedia, &dev))) + if (check (enumerator->GetDefaultAudioEndpoint (forCapture ? eCapture : eRender, + eMultimedia, &dev))) { WCHAR* deviceId = 0; - if (OK (dev->GetId (&deviceId))) + if (check (dev->GetId (&deviceId))) { s = String (deviceId); CoTaskMemFree (deviceId); @@ -253518,14 +253532,13 @@ private: WASAPIAudioIODeviceType& operator= (const WASAPIAudioIODeviceType&); }; +} + AudioIODeviceType* juce_createAudioIODeviceType_WASAPI() { - return new WASAPIAudioIODeviceType(); + return new WasapiClasses::WASAPIAudioIODeviceType(); } -#undef logFailure -#undef OK - #endif /*** End of inlined file: juce_win32_WASAPI.cpp ***/ @@ -269846,151 +269859,312 @@ AudioIODeviceType* juce_createAudioIODeviceType_iPhoneAudio() #if JUCE_MAC -#undef log -#define log(a) Logger::writeToLog(a) - -static bool logAnyErrorsMidi (const OSStatus err, const int lineNum) +namespace CoreMidiHelpers { - if (err == noErr) - return true; + static bool logError (const OSStatus err, const int lineNum) + { + if (err == noErr) + return true; - log ("CoreMidi error: " + String (lineNum) + " - " + String::toHexString ((int) err)); - jassertfalse; - return false; -} + Logger::writeToLog ("CoreMidi error: " + String (lineNum) + " - " + String::toHexString ((int) err)); + jassertfalse; + return false; + } -#undef OK -#define OK(a) logAnyErrorsMidi(a, __LINE__) + #undef CHECK_ERROR + #define CHECK_ERROR(a) CoreMidiHelpers::logError (a, __LINE__) -static const String getEndpointName (MIDIEndpointRef endpoint, bool isExternal) -{ - String result; - CFStringRef str = 0; + static const String getEndpointName (MIDIEndpointRef endpoint, bool isExternal) + { + String result; + CFStringRef str = 0; - MIDIObjectGetStringProperty (endpoint, kMIDIPropertyName, &str); + MIDIObjectGetStringProperty (endpoint, kMIDIPropertyName, &str); - if (str != 0) - { - result = PlatformUtilities::cfStringToJuceString (str); - CFRelease (str); - str = 0; - } + if (str != 0) + { + result = PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + str = 0; + } - MIDIEntityRef entity = 0; - MIDIEndpointGetEntity (endpoint, &entity); + MIDIEntityRef entity = 0; + MIDIEndpointGetEntity (endpoint, &entity); - if (entity == 0) - return result; // probably virtual + if (entity == 0) + return result; // probably virtual - if (result.isEmpty()) - { - // endpoint name has zero length - try the entity - MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str); + if (result.isEmpty()) + { + // endpoint name has zero length - try the entity + MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str); + + if (str != 0) + { + result += PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + str = 0; + } + } + + // now consider the device's name + MIDIDeviceRef device = 0; + MIDIEntityGetDevice (entity, &device); + if (device == 0) + return result; + + MIDIObjectGetStringProperty (device, kMIDIPropertyName, &str); if (str != 0) { - result += PlatformUtilities::cfStringToJuceString (str); + const String s (PlatformUtilities::cfStringToJuceString (str)); CFRelease (str); - str = 0; + + // if an external device has only one entity, throw away + // the endpoint name and just use the device name + if (isExternal && MIDIDeviceGetNumberOfEntities (device) < 2) + { + result = s; + } + else if (! result.startsWithIgnoreCase (s)) + { + // prepend the device name to the entity name + result = (s + " " + result).trimEnd(); + } } - } - // now consider the device's name - MIDIDeviceRef device = 0; - MIDIEntityGetDevice (entity, &device); - if (device == 0) return result; + } - MIDIObjectGetStringProperty (device, kMIDIPropertyName, &str); - - if (str != 0) + static const String getConnectedEndpointName (MIDIEndpointRef endpoint) { - const String s (PlatformUtilities::cfStringToJuceString (str)); - CFRelease (str); + String result; + + // Does the endpoint have connections? + CFDataRef connections = 0; + int numConnections = 0; + + MIDIObjectGetDataProperty (endpoint, kMIDIPropertyConnectionUniqueID, &connections); - // if an external device has only one entity, throw away - // the endpoint name and just use the device name - if (isExternal && MIDIDeviceGetNumberOfEntities (device) < 2) + if (connections != 0) { - result = s; + numConnections = (int) (CFDataGetLength (connections) / sizeof (MIDIUniqueID)); + + if (numConnections > 0) + { + const SInt32* pid = reinterpret_cast (CFDataGetBytePtr (connections)); + + for (int i = 0; i < numConnections; ++i, ++pid) + { + MIDIUniqueID uid = EndianS32_BtoN (*pid); + MIDIObjectRef connObject; + MIDIObjectType connObjectType; + OSStatus err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); + + if (err == noErr) + { + String s; + + if (connObjectType == kMIDIObjectType_ExternalSource + || connObjectType == kMIDIObjectType_ExternalDestination) + { + // Connected to an external device's endpoint (10.3 and later). + s = getEndpointName (static_cast (connObject), true); + } + else + { + // Connected to an external device (10.2) (or something else, catch-all) + CFStringRef str = 0; + MIDIObjectGetStringProperty (connObject, kMIDIPropertyName, &str); + + if (str != 0) + { + s = PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + } + } + + if (s.isNotEmpty()) + { + if (result.isNotEmpty()) + result += ", "; + + result += s; + } + } + } + } + + CFRelease (connections); } - else if (! result.startsWithIgnoreCase (s)) + + if (result.isNotEmpty()) + return result; + + // Here, either the endpoint had no connections, or we failed to obtain names for any of them. + return getEndpointName (endpoint, false); + } + + static MIDIClientRef getGlobalMidiClient() + { + static MIDIClientRef globalMidiClient = 0; + + if (globalMidiClient == 0) { - // prepend the device name to the entity name - result = (s + " " + result).trimEnd(); + String name ("JUCE"); + + if (JUCEApplication::getInstance() != 0) + name = JUCEApplication::getInstance()->getApplicationName(); + + CFStringRef appName = PlatformUtilities::juceStringToCFString (name); + CHECK_ERROR (MIDIClientCreate (appName, 0, 0, &globalMidiClient)); + CFRelease (appName); } + + return globalMidiClient; } - return result; -} + class MidiPortAndEndpoint + { + public: + MidiPortAndEndpoint (MIDIPortRef port_, MIDIEndpointRef endPoint_) + : port (port_), endPoint (endPoint_) + { + } -static const String getConnectedEndpointName (MIDIEndpointRef endpoint) -{ - String result; + ~MidiPortAndEndpoint() + { + if (port != 0) + MIDIPortDispose (port); - // Does the endpoint have connections? - CFDataRef connections = 0; - int numConnections = 0; + if (port == 0 && endPoint != 0) // if port == 0, it means we created the endpoint, so it's safe to delete it + MIDIEndpointDispose (endPoint); + } - MIDIObjectGetDataProperty (endpoint, kMIDIPropertyConnectionUniqueID, &connections); + MIDIPortRef port; + MIDIEndpointRef endPoint; + }; - if (connections != 0) + class MidiPortAndCallback { - numConnections = (int) (CFDataGetLength (connections) / sizeof (MIDIUniqueID)); + public: + MidiInput* input; + MidiPortAndEndpoint* portAndEndpoint; + MidiInputCallback* callback; + MemoryBlock pendingData; + int pendingBytes; + double pendingDataTime; + bool active; - if (numConnections > 0) + void processSysex (const uint8*& d, int& size, const double time) { - const SInt32* pid = reinterpret_cast (CFDataGetBytePtr (connections)); - - for (int i = 0; i < numConnections; ++i, ++pid) + if (*d == 0xf0) { - MIDIUniqueID uid = EndianS32_BtoN (*pid); - MIDIObjectRef connObject; - MIDIObjectType connObjectType; - OSStatus err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); + pendingBytes = 0; + pendingDataTime = time; + } - if (err == noErr) - { - String s; + pendingData.ensureSize (pendingBytes + size, false); + uint8* totalMessage = (uint8*) pendingData.getData(); + + uint8* dest = totalMessage + pendingBytes; - if (connObjectType == kMIDIObjectType_ExternalSource - || connObjectType == kMIDIObjectType_ExternalDestination) + while (size > 0) + { + if (pendingBytes > 0 && *d >= 0x80) + { + if (*d >= 0xfa || *d == 0xf8) { - // Connected to an external device's endpoint (10.3 and later). - s = getEndpointName (static_cast (connObject), true); + callback->handleIncomingMidiMessage (input, MidiMessage (*d, time)); + ++d; + --size; } else { - // Connected to an external device (10.2) (or something else, catch-all) - CFStringRef str = 0; - MIDIObjectGetStringProperty (connObject, kMIDIPropertyName, &str); - - if (str != 0) + if (*d == 0xf7) { - s = PlatformUtilities::cfStringToJuceString (str); - CFRelease (str); + *dest++ = *d++; + pendingBytes++; + --size; } + + break; } + } + else + { + *dest++ = *d++; + pendingBytes++; + --size; + } + } - if (s.isNotEmpty()) + if (totalMessage [pendingBytes - 1] == 0xf7) + { + callback->handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); + pendingBytes = 0; + } + else + { + callback->handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); + } + } + }; + + static CriticalSection callbackLock; + static Array activeCallbacks; + + static void midiInputProc (const MIDIPacketList* pktlist, + void* readProcRefCon, + void* /*srcConnRefCon*/) + { + double time = Time::getMillisecondCounterHiRes() * 0.001; + const double originalTime = time; + + MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon; + const ScopedLock sl (CoreMidiHelpers::callbackLock); + + if (CoreMidiHelpers::activeCallbacks.contains (mpc) && mpc->active) + { + const MIDIPacket* packet = &pktlist->packet[0]; + + for (unsigned int i = 0; i < pktlist->numPackets; ++i) + { + const uint8* d = (const uint8*) (packet->data); + int size = packet->length; + + while (size > 0) + { + time = originalTime; + + if (mpc->pendingBytes > 0 || d[0] == 0xf0) + { + mpc->processSysex (d, size, time); + } + else { - if (result.isNotEmpty()) - result += ", "; + int used = 0; + const MidiMessage m (d, size, used, 0, time); + + if (used <= 0) + { + jassertfalse; // malformed midi message + break; + } + else + { + mpc->callback->handleIncomingMidiMessage (mpc->input, m); + } - result += s; + size -= used; + d += used; } } + + packet = MIDIPacketNext (packet); } } - - CFRelease (connections); } - - if (result.isNotEmpty()) - return result; - - // Here, either the endpoint had no connections, or we failed to obtain names for any of them. - return getEndpointName (endpoint, false); } const StringArray MidiOutput::getDevices() @@ -270004,7 +270178,7 @@ const StringArray MidiOutput::getDevices() if (dest != 0) { - String name (getConnectedEndpointName (dest)); + String name (CoreMidiHelpers::getConnectedEndpointName (dest)); if (name.isEmpty()) name = ""; @@ -270025,48 +270199,6 @@ int MidiOutput::getDefaultDeviceIndex() return 0; } -static MIDIClientRef globalMidiClient; -static bool hasGlobalClientBeenCreated = false; - -static bool makeSureClientExists() -{ - if (! hasGlobalClientBeenCreated) - { - String name ("JUCE"); - - if (JUCEApplication::getInstance() != 0) - name = JUCEApplication::getInstance()->getApplicationName(); - - CFStringRef appName = PlatformUtilities::juceStringToCFString (name); - - hasGlobalClientBeenCreated = OK (MIDIClientCreate (appName, 0, 0, &globalMidiClient)); - CFRelease (appName); - } - - return hasGlobalClientBeenCreated; -} - -class MidiPortAndEndpoint -{ -public: - MidiPortAndEndpoint (MIDIPortRef port_, MIDIEndpointRef endPoint_) - : port (port_), endPoint (endPoint_) - { - } - - ~MidiPortAndEndpoint() - { - if (port != 0) - MIDIPortDispose (port); - - if (port == 0 && endPoint != 0) // if port == 0, it means we created the endpoint, so it's safe to delete it - MIDIEndpointDispose (endPoint); - } - - MIDIPortRef port; - MIDIEndpointRef endPoint; -}; - MidiOutput* MidiOutput::openDevice (int index) { MidiOutput* mo = 0; @@ -270076,19 +270208,15 @@ MidiOutput* MidiOutput::openDevice (int index) MIDIEndpointRef endPoint = MIDIGetDestination (index); CFStringRef pname; - if (OK (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) + if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) { - log ("CoreMidi - opening out: " + PlatformUtilities::cfStringToJuceString (pname)); + MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); + MIDIPortRef port; - if (makeSureClientExists()) + if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname, &port))) { - MIDIPortRef port; - - if (OK (MIDIOutputPortCreate (globalMidiClient, pname, &port))) - { - mo = new MidiOutput(); - mo->internal = new MidiPortAndEndpoint (port, endPoint); - } + mo = new MidiOutput(); + mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint); } CFRelease (pname); @@ -270101,27 +270229,24 @@ MidiOutput* MidiOutput::openDevice (int index) MidiOutput* MidiOutput::createNewDevice (const String& deviceName) { MidiOutput* mo = 0; + MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); - if (makeSureClientExists()) - { - MIDIEndpointRef endPoint; - CFStringRef name = PlatformUtilities::juceStringToCFString (deviceName); - - if (OK (MIDISourceCreate (globalMidiClient, name, &endPoint))) - { - mo = new MidiOutput(); - mo->internal = new MidiPortAndEndpoint (0, endPoint); - } + MIDIEndpointRef endPoint; + CFStringRef name = PlatformUtilities::juceStringToCFString (deviceName); - CFRelease (name); + if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name, &endPoint))) + { + mo = new MidiOutput(); + mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint); } + CFRelease (name); return mo; } MidiOutput::~MidiOutput() { - delete static_cast (internal); + delete static_cast (internal); } void MidiOutput::reset() @@ -270139,7 +270264,7 @@ void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) void MidiOutput::sendMessageNow (const MidiMessage& message) { - MidiPortAndEndpoint* const mpe = static_cast (internal); + CoreMidiHelpers::MidiPortAndEndpoint* const mpe = static_cast (internal); if (message.isSysEx()) { @@ -270193,7 +270318,7 @@ const StringArray MidiInput::getDevices() if (source != 0) { - String name (getConnectedEndpointName (source)); + String name (CoreMidiHelpers::getConnectedEndpointName (source)); if (name.isEmpty()) name = ""; @@ -270214,131 +270339,9 @@ int MidiInput::getDefaultDeviceIndex() return 0; } -struct MidiPortAndCallback -{ - MidiInput* input; - MidiPortAndEndpoint* portAndEndpoint; - MidiInputCallback* callback; - MemoryBlock pendingData; - int pendingBytes; - double pendingDataTime; - bool active; - - void processSysex (const uint8*& d, int& size, const double time) - { - if (*d == 0xf0) - { - pendingBytes = 0; - pendingDataTime = time; - } - - pendingData.ensureSize (pendingBytes + size, false); - uint8* totalMessage = (uint8*) pendingData.getData(); - - uint8* dest = totalMessage + pendingBytes; - - while (size > 0) - { - if (pendingBytes > 0 && *d >= 0x80) - { - if (*d >= 0xfa || *d == 0xf8) - { - callback->handleIncomingMidiMessage (input, MidiMessage (*d, time)); - ++d; - --size; - } - else - { - if (*d == 0xf7) - { - *dest++ = *d++; - pendingBytes++; - --size; - } - - break; - } - } - else - { - *dest++ = *d++; - pendingBytes++; - --size; - } - } - - if (totalMessage [pendingBytes - 1] == 0xf7) - { - callback->handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); - pendingBytes = 0; - } - else - { - callback->handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); - } - } -}; - -namespace CoreMidiCallbacks -{ - static CriticalSection callbackLock; - static Array activeCallbacks; -} - -static void midiInputProc (const MIDIPacketList* pktlist, - void* readProcRefCon, - void* /*srcConnRefCon*/) -{ - double time = Time::getMillisecondCounterHiRes() * 0.001; - const double originalTime = time; - - MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - - if (CoreMidiCallbacks::activeCallbacks.contains (mpc) && mpc->active) - { - const MIDIPacket* packet = &pktlist->packet[0]; - - for (unsigned int i = 0; i < pktlist->numPackets; ++i) - { - const uint8* d = (const uint8*) (packet->data); - int size = packet->length; - - while (size > 0) - { - time = originalTime; - - if (mpc->pendingBytes > 0 || d[0] == 0xf0) - { - mpc->processSysex (d, size, time); - } - else - { - int used = 0; - const MidiMessage m (d, size, used, 0, time); - - if (used <= 0) - { - jassertfalse; // malformed midi message - break; - } - else - { - mpc->callback->handleIncomingMidiMessage (mpc->input, m); - } - - size -= used; - d += used; - } - } - - packet = MIDIPacketNext (packet); - } - } -} - MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { + using namespace CoreMidiHelpers; MidiInput* mi = 0; if (((unsigned int) index) < (unsigned int) MIDIGetNumberOfSources()) @@ -270349,20 +270352,20 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { CFStringRef pname; - if (OK (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) + if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) { - log ("CoreMidi - opening inp: " + PlatformUtilities::cfStringToJuceString (pname)); + MIDIClientRef client = getGlobalMidiClient(); - if (makeSureClientExists()) + if (client != 0) { MIDIPortRef port; ScopedPointer mpc (new MidiPortAndCallback()); mpc->active = false; - if (OK (MIDIInputPortCreate (globalMidiClient, pname, midiInputProc, mpc, &port))) + if (CHECK_ERROR (MIDIInputPortCreate (client, pname, midiInputProc, mpc, &port))) { - if (OK (MIDIPortConnectSource (port, endPoint, 0))) + if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, 0))) { mpc->portAndEndpoint = new MidiPortAndEndpoint (port, endPoint); mpc->callback = callback; @@ -270373,12 +270376,12 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) mpc->input = mi; mi->internal = mpc; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.add (mpc.release()); + const ScopedLock sl (callbackLock); + activeCallbacks.add (mpc.release()); } else { - OK (MIDIPortDispose (port)); + CHECK_ERROR (MIDIPortDispose (port)); } } } @@ -270393,16 +270396,18 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) { + using namespace CoreMidiHelpers; MidiInput* mi = 0; + MIDIClientRef client = getGlobalMidiClient(); - if (makeSureClientExists()) + if (client != 0) { ScopedPointer mpc (new MidiPortAndCallback()); mpc->active = false; MIDIEndpointRef endPoint; CFStringRef name = PlatformUtilities::juceStringToCFString(deviceName); - if (OK (MIDIDestinationCreate (globalMidiClient, name, midiInputProc, mpc, &endPoint))) + if (CHECK_ERROR (MIDIDestinationCreate (client, name, midiInputProc, mpc, &endPoint))) { mpc->portAndEndpoint = new MidiPortAndEndpoint (0, endPoint); mpc->callback = callback; @@ -270413,8 +270418,8 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba mpc->input = mi; mi->internal = mpc; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.add (mpc.release()); + const ScopedLock sl (callbackLock); + activeCallbacks.add (mpc.release()); } CFRelease (name); @@ -270430,16 +270435,18 @@ MidiInput::MidiInput (const String& name_) MidiInput::~MidiInput() { + using namespace CoreMidiHelpers; + MidiPortAndCallback* const mpc = static_cast (internal); mpc->active = false; { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.removeValue (mpc); + const ScopedLock sl (callbackLock); + activeCallbacks.removeValue (mpc); } if (mpc->portAndEndpoint->port != 0) - OK (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); + CHECK_ERROR (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); delete mpc->portAndEndpoint; delete mpc; @@ -270447,60 +270454,29 @@ MidiInput::~MidiInput() void MidiInput::start() { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - static_cast (internal)->active = true; + const ScopedLock sl (CoreMidiHelpers::callbackLock); + static_cast (internal)->active = true; } void MidiInput::stop() { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - static_cast (internal)->active = false; -} - -#undef log - -#else - -MidiOutput::~MidiOutput() -{ + const ScopedLock sl (CoreMidiHelpers::callbackLock); + static_cast (internal)->active = false; } -void MidiOutput::reset() -{ -} +#undef CHECK_ERROR -bool MidiOutput::getVolume (float& /*leftVol*/, float& /*rightVol*/) -{ - return false; -} - -void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) -{ -} +#else // Stubs for iOS... -void MidiOutput::sendMessageNow (const MidiMessage& message) -{ -} - -const StringArray MidiOutput::getDevices() -{ - return StringArray(); -} - -MidiOutput* MidiOutput::openDevice (int index) -{ - return 0; -} - -const StringArray MidiInput::getDevices() -{ - return StringArray(); -} - -MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) -{ - return 0; -} +MidiOutput::~MidiOutput() {} +void MidiOutput::reset() {} +bool MidiOutput::getVolume (float& /*leftVol*/, float& /*rightVol*/) { return false; } +void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) {} +void MidiOutput::sendMessageNow (const MidiMessage& message) {} +const StringArray MidiOutput::getDevices() { return StringArray(); } +MidiOutput* MidiOutput::openDevice (int index) { return 0; } +const StringArray MidiInput::getDevices() { return StringArray(); } +MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { return 0; } #endif @@ -278428,151 +278404,312 @@ AudioIODeviceType* juce_createAudioIODeviceType_CoreAudio() #if JUCE_MAC -#undef log -#define log(a) Logger::writeToLog(a) - -static bool logAnyErrorsMidi (const OSStatus err, const int lineNum) +namespace CoreMidiHelpers { - if (err == noErr) - return true; + static bool logError (const OSStatus err, const int lineNum) + { + if (err == noErr) + return true; - log ("CoreMidi error: " + String (lineNum) + " - " + String::toHexString ((int) err)); - jassertfalse; - return false; -} + Logger::writeToLog ("CoreMidi error: " + String (lineNum) + " - " + String::toHexString ((int) err)); + jassertfalse; + return false; + } -#undef OK -#define OK(a) logAnyErrorsMidi(a, __LINE__) + #undef CHECK_ERROR + #define CHECK_ERROR(a) CoreMidiHelpers::logError (a, __LINE__) -static const String getEndpointName (MIDIEndpointRef endpoint, bool isExternal) -{ - String result; - CFStringRef str = 0; + static const String getEndpointName (MIDIEndpointRef endpoint, bool isExternal) + { + String result; + CFStringRef str = 0; - MIDIObjectGetStringProperty (endpoint, kMIDIPropertyName, &str); + MIDIObjectGetStringProperty (endpoint, kMIDIPropertyName, &str); - if (str != 0) - { - result = PlatformUtilities::cfStringToJuceString (str); - CFRelease (str); - str = 0; - } + if (str != 0) + { + result = PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + str = 0; + } - MIDIEntityRef entity = 0; - MIDIEndpointGetEntity (endpoint, &entity); + MIDIEntityRef entity = 0; + MIDIEndpointGetEntity (endpoint, &entity); - if (entity == 0) - return result; // probably virtual + if (entity == 0) + return result; // probably virtual - if (result.isEmpty()) - { - // endpoint name has zero length - try the entity - MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str); + if (result.isEmpty()) + { + // endpoint name has zero length - try the entity + MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str); + + if (str != 0) + { + result += PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + str = 0; + } + } + + // now consider the device's name + MIDIDeviceRef device = 0; + MIDIEntityGetDevice (entity, &device); + if (device == 0) + return result; + + MIDIObjectGetStringProperty (device, kMIDIPropertyName, &str); if (str != 0) { - result += PlatformUtilities::cfStringToJuceString (str); + const String s (PlatformUtilities::cfStringToJuceString (str)); CFRelease (str); - str = 0; + + // if an external device has only one entity, throw away + // the endpoint name and just use the device name + if (isExternal && MIDIDeviceGetNumberOfEntities (device) < 2) + { + result = s; + } + else if (! result.startsWithIgnoreCase (s)) + { + // prepend the device name to the entity name + result = (s + " " + result).trimEnd(); + } } - } - // now consider the device's name - MIDIDeviceRef device = 0; - MIDIEntityGetDevice (entity, &device); - if (device == 0) return result; + } - MIDIObjectGetStringProperty (device, kMIDIPropertyName, &str); - - if (str != 0) + static const String getConnectedEndpointName (MIDIEndpointRef endpoint) { - const String s (PlatformUtilities::cfStringToJuceString (str)); - CFRelease (str); + String result; + + // Does the endpoint have connections? + CFDataRef connections = 0; + int numConnections = 0; - // if an external device has only one entity, throw away - // the endpoint name and just use the device name - if (isExternal && MIDIDeviceGetNumberOfEntities (device) < 2) + MIDIObjectGetDataProperty (endpoint, kMIDIPropertyConnectionUniqueID, &connections); + + if (connections != 0) { - result = s; + numConnections = (int) (CFDataGetLength (connections) / sizeof (MIDIUniqueID)); + + if (numConnections > 0) + { + const SInt32* pid = reinterpret_cast (CFDataGetBytePtr (connections)); + + for (int i = 0; i < numConnections; ++i, ++pid) + { + MIDIUniqueID uid = EndianS32_BtoN (*pid); + MIDIObjectRef connObject; + MIDIObjectType connObjectType; + OSStatus err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); + + if (err == noErr) + { + String s; + + if (connObjectType == kMIDIObjectType_ExternalSource + || connObjectType == kMIDIObjectType_ExternalDestination) + { + // Connected to an external device's endpoint (10.3 and later). + s = getEndpointName (static_cast (connObject), true); + } + else + { + // Connected to an external device (10.2) (or something else, catch-all) + CFStringRef str = 0; + MIDIObjectGetStringProperty (connObject, kMIDIPropertyName, &str); + + if (str != 0) + { + s = PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + } + } + + if (s.isNotEmpty()) + { + if (result.isNotEmpty()) + result += ", "; + + result += s; + } + } + } + } + + CFRelease (connections); } - else if (! result.startsWithIgnoreCase (s)) + + if (result.isNotEmpty()) + return result; + + // Here, either the endpoint had no connections, or we failed to obtain names for any of them. + return getEndpointName (endpoint, false); + } + + static MIDIClientRef getGlobalMidiClient() + { + static MIDIClientRef globalMidiClient = 0; + + if (globalMidiClient == 0) { - // prepend the device name to the entity name - result = (s + " " + result).trimEnd(); + String name ("JUCE"); + + if (JUCEApplication::getInstance() != 0) + name = JUCEApplication::getInstance()->getApplicationName(); + + CFStringRef appName = PlatformUtilities::juceStringToCFString (name); + CHECK_ERROR (MIDIClientCreate (appName, 0, 0, &globalMidiClient)); + CFRelease (appName); } + + return globalMidiClient; } - return result; -} + class MidiPortAndEndpoint + { + public: + MidiPortAndEndpoint (MIDIPortRef port_, MIDIEndpointRef endPoint_) + : port (port_), endPoint (endPoint_) + { + } -static const String getConnectedEndpointName (MIDIEndpointRef endpoint) -{ - String result; + ~MidiPortAndEndpoint() + { + if (port != 0) + MIDIPortDispose (port); - // Does the endpoint have connections? - CFDataRef connections = 0; - int numConnections = 0; + if (port == 0 && endPoint != 0) // if port == 0, it means we created the endpoint, so it's safe to delete it + MIDIEndpointDispose (endPoint); + } - MIDIObjectGetDataProperty (endpoint, kMIDIPropertyConnectionUniqueID, &connections); + MIDIPortRef port; + MIDIEndpointRef endPoint; + }; - if (connections != 0) + class MidiPortAndCallback { - numConnections = (int) (CFDataGetLength (connections) / sizeof (MIDIUniqueID)); + public: + MidiInput* input; + MidiPortAndEndpoint* portAndEndpoint; + MidiInputCallback* callback; + MemoryBlock pendingData; + int pendingBytes; + double pendingDataTime; + bool active; - if (numConnections > 0) + void processSysex (const uint8*& d, int& size, const double time) { - const SInt32* pid = reinterpret_cast (CFDataGetBytePtr (connections)); - - for (int i = 0; i < numConnections; ++i, ++pid) + if (*d == 0xf0) { - MIDIUniqueID uid = EndianS32_BtoN (*pid); - MIDIObjectRef connObject; - MIDIObjectType connObjectType; - OSStatus err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); + pendingBytes = 0; + pendingDataTime = time; + } - if (err == noErr) - { - String s; + pendingData.ensureSize (pendingBytes + size, false); + uint8* totalMessage = (uint8*) pendingData.getData(); + + uint8* dest = totalMessage + pendingBytes; - if (connObjectType == kMIDIObjectType_ExternalSource - || connObjectType == kMIDIObjectType_ExternalDestination) + while (size > 0) + { + if (pendingBytes > 0 && *d >= 0x80) + { + if (*d >= 0xfa || *d == 0xf8) { - // Connected to an external device's endpoint (10.3 and later). - s = getEndpointName (static_cast (connObject), true); + callback->handleIncomingMidiMessage (input, MidiMessage (*d, time)); + ++d; + --size; } else { - // Connected to an external device (10.2) (or something else, catch-all) - CFStringRef str = 0; - MIDIObjectGetStringProperty (connObject, kMIDIPropertyName, &str); - - if (str != 0) + if (*d == 0xf7) { - s = PlatformUtilities::cfStringToJuceString (str); - CFRelease (str); + *dest++ = *d++; + pendingBytes++; + --size; } + + break; } + } + else + { + *dest++ = *d++; + pendingBytes++; + --size; + } + } + + if (totalMessage [pendingBytes - 1] == 0xf7) + { + callback->handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); + pendingBytes = 0; + } + else + { + callback->handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); + } + } + }; + + static CriticalSection callbackLock; + static Array activeCallbacks; + + static void midiInputProc (const MIDIPacketList* pktlist, + void* readProcRefCon, + void* /*srcConnRefCon*/) + { + double time = Time::getMillisecondCounterHiRes() * 0.001; + const double originalTime = time; + + MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon; + const ScopedLock sl (CoreMidiHelpers::callbackLock); + + if (CoreMidiHelpers::activeCallbacks.contains (mpc) && mpc->active) + { + const MIDIPacket* packet = &pktlist->packet[0]; + + for (unsigned int i = 0; i < pktlist->numPackets; ++i) + { + const uint8* d = (const uint8*) (packet->data); + int size = packet->length; - if (s.isNotEmpty()) + while (size > 0) + { + time = originalTime; + + if (mpc->pendingBytes > 0 || d[0] == 0xf0) { - if (result.isNotEmpty()) - result += ", "; + mpc->processSysex (d, size, time); + } + else + { + int used = 0; + const MidiMessage m (d, size, used, 0, time); + + if (used <= 0) + { + jassertfalse; // malformed midi message + break; + } + else + { + mpc->callback->handleIncomingMidiMessage (mpc->input, m); + } - result += s; + size -= used; + d += used; } } + + packet = MIDIPacketNext (packet); } } - - CFRelease (connections); } - - if (result.isNotEmpty()) - return result; - - // Here, either the endpoint had no connections, or we failed to obtain names for any of them. - return getEndpointName (endpoint, false); } const StringArray MidiOutput::getDevices() @@ -278586,7 +278723,7 @@ const StringArray MidiOutput::getDevices() if (dest != 0) { - String name (getConnectedEndpointName (dest)); + String name (CoreMidiHelpers::getConnectedEndpointName (dest)); if (name.isEmpty()) name = ""; @@ -278607,48 +278744,6 @@ int MidiOutput::getDefaultDeviceIndex() return 0; } -static MIDIClientRef globalMidiClient; -static bool hasGlobalClientBeenCreated = false; - -static bool makeSureClientExists() -{ - if (! hasGlobalClientBeenCreated) - { - String name ("JUCE"); - - if (JUCEApplication::getInstance() != 0) - name = JUCEApplication::getInstance()->getApplicationName(); - - CFStringRef appName = PlatformUtilities::juceStringToCFString (name); - - hasGlobalClientBeenCreated = OK (MIDIClientCreate (appName, 0, 0, &globalMidiClient)); - CFRelease (appName); - } - - return hasGlobalClientBeenCreated; -} - -class MidiPortAndEndpoint -{ -public: - MidiPortAndEndpoint (MIDIPortRef port_, MIDIEndpointRef endPoint_) - : port (port_), endPoint (endPoint_) - { - } - - ~MidiPortAndEndpoint() - { - if (port != 0) - MIDIPortDispose (port); - - if (port == 0 && endPoint != 0) // if port == 0, it means we created the endpoint, so it's safe to delete it - MIDIEndpointDispose (endPoint); - } - - MIDIPortRef port; - MIDIEndpointRef endPoint; -}; - MidiOutput* MidiOutput::openDevice (int index) { MidiOutput* mo = 0; @@ -278658,19 +278753,15 @@ MidiOutput* MidiOutput::openDevice (int index) MIDIEndpointRef endPoint = MIDIGetDestination (index); CFStringRef pname; - if (OK (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) + if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) { - log ("CoreMidi - opening out: " + PlatformUtilities::cfStringToJuceString (pname)); + MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); + MIDIPortRef port; - if (makeSureClientExists()) + if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname, &port))) { - MIDIPortRef port; - - if (OK (MIDIOutputPortCreate (globalMidiClient, pname, &port))) - { - mo = new MidiOutput(); - mo->internal = new MidiPortAndEndpoint (port, endPoint); - } + mo = new MidiOutput(); + mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint); } CFRelease (pname); @@ -278683,27 +278774,24 @@ MidiOutput* MidiOutput::openDevice (int index) MidiOutput* MidiOutput::createNewDevice (const String& deviceName) { MidiOutput* mo = 0; + MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); - if (makeSureClientExists()) - { - MIDIEndpointRef endPoint; - CFStringRef name = PlatformUtilities::juceStringToCFString (deviceName); - - if (OK (MIDISourceCreate (globalMidiClient, name, &endPoint))) - { - mo = new MidiOutput(); - mo->internal = new MidiPortAndEndpoint (0, endPoint); - } + MIDIEndpointRef endPoint; + CFStringRef name = PlatformUtilities::juceStringToCFString (deviceName); - CFRelease (name); + if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name, &endPoint))) + { + mo = new MidiOutput(); + mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint); } + CFRelease (name); return mo; } MidiOutput::~MidiOutput() { - delete static_cast (internal); + delete static_cast (internal); } void MidiOutput::reset() @@ -278721,7 +278809,7 @@ void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) void MidiOutput::sendMessageNow (const MidiMessage& message) { - MidiPortAndEndpoint* const mpe = static_cast (internal); + CoreMidiHelpers::MidiPortAndEndpoint* const mpe = static_cast (internal); if (message.isSysEx()) { @@ -278775,7 +278863,7 @@ const StringArray MidiInput::getDevices() if (source != 0) { - String name (getConnectedEndpointName (source)); + String name (CoreMidiHelpers::getConnectedEndpointName (source)); if (name.isEmpty()) name = ""; @@ -278796,131 +278884,9 @@ int MidiInput::getDefaultDeviceIndex() return 0; } -struct MidiPortAndCallback -{ - MidiInput* input; - MidiPortAndEndpoint* portAndEndpoint; - MidiInputCallback* callback; - MemoryBlock pendingData; - int pendingBytes; - double pendingDataTime; - bool active; - - void processSysex (const uint8*& d, int& size, const double time) - { - if (*d == 0xf0) - { - pendingBytes = 0; - pendingDataTime = time; - } - - pendingData.ensureSize (pendingBytes + size, false); - uint8* totalMessage = (uint8*) pendingData.getData(); - - uint8* dest = totalMessage + pendingBytes; - - while (size > 0) - { - if (pendingBytes > 0 && *d >= 0x80) - { - if (*d >= 0xfa || *d == 0xf8) - { - callback->handleIncomingMidiMessage (input, MidiMessage (*d, time)); - ++d; - --size; - } - else - { - if (*d == 0xf7) - { - *dest++ = *d++; - pendingBytes++; - --size; - } - - break; - } - } - else - { - *dest++ = *d++; - pendingBytes++; - --size; - } - } - - if (totalMessage [pendingBytes - 1] == 0xf7) - { - callback->handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); - pendingBytes = 0; - } - else - { - callback->handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); - } - } -}; - -namespace CoreMidiCallbacks -{ - static CriticalSection callbackLock; - static Array activeCallbacks; -} - -static void midiInputProc (const MIDIPacketList* pktlist, - void* readProcRefCon, - void* /*srcConnRefCon*/) -{ - double time = Time::getMillisecondCounterHiRes() * 0.001; - const double originalTime = time; - - MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - - if (CoreMidiCallbacks::activeCallbacks.contains (mpc) && mpc->active) - { - const MIDIPacket* packet = &pktlist->packet[0]; - - for (unsigned int i = 0; i < pktlist->numPackets; ++i) - { - const uint8* d = (const uint8*) (packet->data); - int size = packet->length; - - while (size > 0) - { - time = originalTime; - - if (mpc->pendingBytes > 0 || d[0] == 0xf0) - { - mpc->processSysex (d, size, time); - } - else - { - int used = 0; - const MidiMessage m (d, size, used, 0, time); - - if (used <= 0) - { - jassertfalse; // malformed midi message - break; - } - else - { - mpc->callback->handleIncomingMidiMessage (mpc->input, m); - } - - size -= used; - d += used; - } - } - - packet = MIDIPacketNext (packet); - } - } -} - MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { + using namespace CoreMidiHelpers; MidiInput* mi = 0; if (((unsigned int) index) < (unsigned int) MIDIGetNumberOfSources()) @@ -278931,20 +278897,20 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { CFStringRef pname; - if (OK (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) + if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) { - log ("CoreMidi - opening inp: " + PlatformUtilities::cfStringToJuceString (pname)); + MIDIClientRef client = getGlobalMidiClient(); - if (makeSureClientExists()) + if (client != 0) { MIDIPortRef port; ScopedPointer mpc (new MidiPortAndCallback()); mpc->active = false; - if (OK (MIDIInputPortCreate (globalMidiClient, pname, midiInputProc, mpc, &port))) + if (CHECK_ERROR (MIDIInputPortCreate (client, pname, midiInputProc, mpc, &port))) { - if (OK (MIDIPortConnectSource (port, endPoint, 0))) + if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, 0))) { mpc->portAndEndpoint = new MidiPortAndEndpoint (port, endPoint); mpc->callback = callback; @@ -278955,12 +278921,12 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) mpc->input = mi; mi->internal = mpc; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.add (mpc.release()); + const ScopedLock sl (callbackLock); + activeCallbacks.add (mpc.release()); } else { - OK (MIDIPortDispose (port)); + CHECK_ERROR (MIDIPortDispose (port)); } } } @@ -278975,16 +278941,18 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) { + using namespace CoreMidiHelpers; MidiInput* mi = 0; + MIDIClientRef client = getGlobalMidiClient(); - if (makeSureClientExists()) + if (client != 0) { ScopedPointer mpc (new MidiPortAndCallback()); mpc->active = false; MIDIEndpointRef endPoint; CFStringRef name = PlatformUtilities::juceStringToCFString(deviceName); - if (OK (MIDIDestinationCreate (globalMidiClient, name, midiInputProc, mpc, &endPoint))) + if (CHECK_ERROR (MIDIDestinationCreate (client, name, midiInputProc, mpc, &endPoint))) { mpc->portAndEndpoint = new MidiPortAndEndpoint (0, endPoint); mpc->callback = callback; @@ -278995,8 +278963,8 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba mpc->input = mi; mi->internal = mpc; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.add (mpc.release()); + const ScopedLock sl (callbackLock); + activeCallbacks.add (mpc.release()); } CFRelease (name); @@ -279012,16 +278980,18 @@ MidiInput::MidiInput (const String& name_) MidiInput::~MidiInput() { + using namespace CoreMidiHelpers; + MidiPortAndCallback* const mpc = static_cast (internal); mpc->active = false; { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.removeValue (mpc); + const ScopedLock sl (callbackLock); + activeCallbacks.removeValue (mpc); } if (mpc->portAndEndpoint->port != 0) - OK (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); + CHECK_ERROR (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); delete mpc->portAndEndpoint; delete mpc; @@ -279029,60 +278999,29 @@ MidiInput::~MidiInput() void MidiInput::start() { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - static_cast (internal)->active = true; + const ScopedLock sl (CoreMidiHelpers::callbackLock); + static_cast (internal)->active = true; } void MidiInput::stop() { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - static_cast (internal)->active = false; -} - -#undef log - -#else - -MidiOutput::~MidiOutput() -{ -} - -void MidiOutput::reset() -{ -} - -bool MidiOutput::getVolume (float& /*leftVol*/, float& /*rightVol*/) -{ - return false; -} - -void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) -{ + const ScopedLock sl (CoreMidiHelpers::callbackLock); + static_cast (internal)->active = false; } -void MidiOutput::sendMessageNow (const MidiMessage& message) -{ -} +#undef CHECK_ERROR -const StringArray MidiOutput::getDevices() -{ - return StringArray(); -} +#else // Stubs for iOS... -MidiOutput* MidiOutput::openDevice (int index) -{ - return 0; -} - -const StringArray MidiInput::getDevices() -{ - return StringArray(); -} - -MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) -{ - return 0; -} +MidiOutput::~MidiOutput() {} +void MidiOutput::reset() {} +bool MidiOutput::getVolume (float& /*leftVol*/, float& /*rightVol*/) { return false; } +void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) {} +void MidiOutput::sendMessageNow (const MidiMessage& message) {} +const StringArray MidiOutput::getDevices() { return StringArray(); } +MidiOutput* MidiOutput::openDevice (int index) { return 0; } +const StringArray MidiInput::getDevices() { return StringArray(); } +MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { return 0; } #endif diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 029d4da2f3..f06c217dfe 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 72 +#define JUCE_BUILDNUMBER 73 /** Current Juce version number. @@ -2594,6 +2594,11 @@ private: void createInternal (const juce_wchar* text, size_t numChars); void appendInternal (const juce_wchar* text, int numExtraChars); + + // This private cast operator should prevent strings being accidentally cast + // to bools (this is possible because the compiler can add an implicit cast + // via a const char*) + operator bool() const throw() { return false; } }; /** Concatenates two strings. */ @@ -39875,7 +39880,8 @@ public: a generic UI that lets the user twiddle the parameters directly. If you do want to pass back a component, the component should be created and set to - the correct size before returning it. + the correct size before returning it. If you implement this method, you must + also implement the hasEditor() method and make it return true. Remember not to do anything silly like allowing your filter to keep a pointer to the component that gets created - it could be deleted later without any warning, which @@ -39892,9 +39898,16 @@ public: not open one at all. Your filter mustn't rely on it being there. - An editor object may be deleted and a replacement one created again at any time. - It's safe to assume that an editor will be deleted before its filter. + + @see hasEditor */ virtual AudioProcessorEditor* createEditor() = 0; + /** Your filter must override this and return true if it can create an editor component. + @see createEditor + */ + virtual bool hasEditor() const = 0; + /** Returns the active editor, if there is one. Bear in mind this can return 0, even if an editor has previously been @@ -42011,6 +42024,7 @@ public: bool acceptsMidi() const; bool producesMidi() const; + bool hasEditor() const; AudioProcessorEditor* createEditor(); int getNumParameters(); @@ -42057,6 +42071,7 @@ public: bool acceptsMidi() const; bool producesMidi() const; + bool hasEditor() const { return false; } AudioProcessorEditor* createEditor() { return 0; } int getNumParameters() { return 0; } diff --git a/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp b/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp index 203dda2eee..96d8cc41b8 100644 --- a/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp +++ b/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp @@ -43,7 +43,7 @@ /* If you've got an include error here, you probably need to install the QuickTime SDK and add its header directory to your include path. - Alternatively, if you don't need any QuickTime services, just turn off the JUC_QUICKTIME + Alternatively, if you don't need any QuickTime services, just turn off the JUCE_QUICKTIME flag in juce_Config.h */ #include @@ -70,7 +70,7 @@ BEGIN_JUCE_NAMESPACE bool juce_OpenQuickTimeMovieFromStream (InputStream* input, Movie& movie, Handle& dataHandle); static const char* const quickTimeFormatName = "QuickTime file"; -static const char* const quickTimeExtensions[] = { ".mov", ".mp3", ".mp4", 0 }; +static const char* const quickTimeExtensions[] = { ".mov", ".mp3", ".mp4", ".m4a", 0 }; //============================================================================== class QTAudioReader : public AudioFormatReader diff --git a/src/audio/devices/juce_AudioDeviceManager.cpp b/src/audio/devices/juce_AudioDeviceManager.cpp index b15edd3d69..63433ace21 100644 --- a/src/audio/devices/juce_AudioDeviceManager.cpp +++ b/src/audio/devices/juce_AudioDeviceManager.cpp @@ -31,6 +31,7 @@ BEGIN_JUCE_NAMESPACE #include "../../gui/components/juce_Desktop.h" #include "../../text/juce_LocalisedStrings.h" #include "../dsp/juce_AudioSampleBuffer.h" +#include "../../core/juce_SystemStats.h" //============================================================================== diff --git a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm index b8dea7be67..1ce4b007ea 100644 --- a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm +++ b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm @@ -231,6 +231,7 @@ public: void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + bool hasEditor() const; AudioProcessorEditor* createEditor(); const String getInputChannelName (int index) const; @@ -1087,6 +1088,11 @@ private: #endif //============================================================================== +bool AudioUnitPluginInstance::hasEditor() const +{ + return true; +} + AudioProcessorEditor* AudioUnitPluginInstance::createEditor() { ScopedPointer w (new AudioUnitPluginWindowCocoa (*this, false)); diff --git a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp index ddeb801e35..a1c9ab45d0 100644 --- a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp +++ b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp @@ -729,6 +729,7 @@ public: void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + bool hasEditor() const { return effect != 0 && (effect->flags & effFlagsHasEditor) != 0; } AudioProcessorEditor* createEditor(); const String getInputChannelName (int index) const; @@ -805,7 +806,6 @@ private: const String getVersion() const; const String getCategory() const; - bool hasEditor() const throw() { return effect != 0 && (effect->flags & effFlagsHasEditor) != 0; } void setPower (const bool on); VSTPluginInstance (const ReferenceCountedObjectPtr & module); diff --git a/src/audio/processors/juce_AudioProcessor.cpp b/src/audio/processors/juce_AudioProcessor.cpp index 1e40bd54bc..9dd7d0e82a 100644 --- a/src/audio/processors/juce_AudioProcessor.cpp +++ b/src/audio/processors/juce_AudioProcessor.cpp @@ -231,6 +231,9 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() AudioProcessorEditor* const ed = createEditor(); + // You must make your hasEditor() method return a consistent result! + jassert (hasEditor() == (ed != 0)); + if (ed != 0) { // you must give your editor comp a size before returning it.. diff --git a/src/audio/processors/juce_AudioProcessor.h b/src/audio/processors/juce_AudioProcessor.h index d64234c0ef..bb79a994a0 100644 --- a/src/audio/processors/juce_AudioProcessor.h +++ b/src/audio/processors/juce_AudioProcessor.h @@ -318,7 +318,8 @@ public: a generic UI that lets the user twiddle the parameters directly. If you do want to pass back a component, the component should be created and set to - the correct size before returning it. + the correct size before returning it. If you implement this method, you must + also implement the hasEditor() method and make it return true. Remember not to do anything silly like allowing your filter to keep a pointer to the component that gets created - it could be deleted later without any warning, which @@ -335,9 +336,16 @@ public: not open one at all. Your filter mustn't rely on it being there. - An editor object may be deleted and a replacement one created again at any time. - It's safe to assume that an editor will be deleted before its filter. + + @see hasEditor */ virtual AudioProcessorEditor* createEditor() = 0; + /** Your filter must override this and return true if it can create an editor component. + @see createEditor + */ + virtual bool hasEditor() const = 0; + //============================================================================== /** Returns the active editor, if there is one. diff --git a/src/audio/processors/juce_AudioProcessorGraph.cpp b/src/audio/processors/juce_AudioProcessorGraph.cpp index 2c532482d8..a332972314 100644 --- a/src/audio/processors/juce_AudioProcessorGraph.cpp +++ b/src/audio/processors/juce_AudioProcessorGraph.cpp @@ -1276,10 +1276,8 @@ bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const return type == audioOutputNode || type == midiOutputNode; } -AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() -{ - return 0; -} +bool AudioProcessorGraph::AudioGraphIOProcessor::hasEditor() const { return false; } +AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() { return 0; } int AudioProcessorGraph::AudioGraphIOProcessor::getNumParameters() { return 0; } const String AudioProcessorGraph::AudioGraphIOProcessor::getParameterName (int) { return String::empty; } diff --git a/src/audio/processors/juce_AudioProcessorGraph.h b/src/audio/processors/juce_AudioProcessorGraph.h index ee722217ba..cba3e7c9c0 100644 --- a/src/audio/processors/juce_AudioProcessorGraph.h +++ b/src/audio/processors/juce_AudioProcessorGraph.h @@ -335,6 +335,7 @@ public: bool acceptsMidi() const; bool producesMidi() const; + bool hasEditor() const; AudioProcessorEditor* createEditor(); int getNumParameters(); @@ -382,6 +383,7 @@ public: bool acceptsMidi() const; bool producesMidi() const; + bool hasEditor() const { return false; } AudioProcessorEditor* createEditor() { return 0; } int getNumParameters() { return 0; } diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 43b6cf7a9b..530acdb68f 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 72 +#define JUCE_BUILDNUMBER 73 /** Current Juce version number. diff --git a/src/native/mac/juce_mac_CoreMidi.cpp b/src/native/mac/juce_mac_CoreMidi.cpp index fb137e7f36..7d09a7a4de 100644 --- a/src/native/mac/juce_mac_CoreMidi.cpp +++ b/src/native/mac/juce_mac_CoreMidi.cpp @@ -30,153 +30,315 @@ #if JUCE_MAC //============================================================================== -#undef log -#define log(a) Logger::writeToLog(a) - -static bool logAnyErrorsMidi (const OSStatus err, const int lineNum) +namespace CoreMidiHelpers { - if (err == noErr) - return true; + static bool logError (const OSStatus err, const int lineNum) + { + if (err == noErr) + return true; - log ("CoreMidi error: " + String (lineNum) + " - " + String::toHexString ((int) err)); - jassertfalse; - return false; -} + Logger::writeToLog ("CoreMidi error: " + String (lineNum) + " - " + String::toHexString ((int) err)); + jassertfalse; + return false; + } -#undef OK -#define OK(a) logAnyErrorsMidi(a, __LINE__) + #undef CHECK_ERROR + #define CHECK_ERROR(a) CoreMidiHelpers::logError (a, __LINE__) + //============================================================================== + static const String getEndpointName (MIDIEndpointRef endpoint, bool isExternal) + { + String result; + CFStringRef str = 0; -//============================================================================== -static const String getEndpointName (MIDIEndpointRef endpoint, bool isExternal) -{ - String result; - CFStringRef str = 0; + MIDIObjectGetStringProperty (endpoint, kMIDIPropertyName, &str); - MIDIObjectGetStringProperty (endpoint, kMIDIPropertyName, &str); + if (str != 0) + { + result = PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + str = 0; + } - if (str != 0) - { - result = PlatformUtilities::cfStringToJuceString (str); - CFRelease (str); - str = 0; - } + MIDIEntityRef entity = 0; + MIDIEndpointGetEntity (endpoint, &entity); - MIDIEntityRef entity = 0; - MIDIEndpointGetEntity (endpoint, &entity); + if (entity == 0) + return result; // probably virtual - if (entity == 0) - return result; // probably virtual + if (result.isEmpty()) + { + // endpoint name has zero length - try the entity + MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str); - if (result.isEmpty()) - { - // endpoint name has zero length - try the entity - MIDIObjectGetStringProperty (entity, kMIDIPropertyName, &str); + if (str != 0) + { + result += PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + str = 0; + } + } + + // now consider the device's name + MIDIDeviceRef device = 0; + MIDIEntityGetDevice (entity, &device); + if (device == 0) + return result; + + MIDIObjectGetStringProperty (device, kMIDIPropertyName, &str); if (str != 0) { - result += PlatformUtilities::cfStringToJuceString (str); + const String s (PlatformUtilities::cfStringToJuceString (str)); CFRelease (str); - str = 0; + + // if an external device has only one entity, throw away + // the endpoint name and just use the device name + if (isExternal && MIDIDeviceGetNumberOfEntities (device) < 2) + { + result = s; + } + else if (! result.startsWithIgnoreCase (s)) + { + // prepend the device name to the entity name + result = (s + " " + result).trimEnd(); + } } - } - // now consider the device's name - MIDIDeviceRef device = 0; - MIDIEntityGetDevice (entity, &device); - if (device == 0) return result; + } - MIDIObjectGetStringProperty (device, kMIDIPropertyName, &str); - - if (str != 0) + static const String getConnectedEndpointName (MIDIEndpointRef endpoint) { - const String s (PlatformUtilities::cfStringToJuceString (str)); - CFRelease (str); + String result; + + // Does the endpoint have connections? + CFDataRef connections = 0; + int numConnections = 0; + + MIDIObjectGetDataProperty (endpoint, kMIDIPropertyConnectionUniqueID, &connections); - // if an external device has only one entity, throw away - // the endpoint name and just use the device name - if (isExternal && MIDIDeviceGetNumberOfEntities (device) < 2) + if (connections != 0) { - result = s; + numConnections = (int) (CFDataGetLength (connections) / sizeof (MIDIUniqueID)); + + if (numConnections > 0) + { + const SInt32* pid = reinterpret_cast (CFDataGetBytePtr (connections)); + + for (int i = 0; i < numConnections; ++i, ++pid) + { + MIDIUniqueID uid = EndianS32_BtoN (*pid); + MIDIObjectRef connObject; + MIDIObjectType connObjectType; + OSStatus err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); + + if (err == noErr) + { + String s; + + if (connObjectType == kMIDIObjectType_ExternalSource + || connObjectType == kMIDIObjectType_ExternalDestination) + { + // Connected to an external device's endpoint (10.3 and later). + s = getEndpointName (static_cast (connObject), true); + } + else + { + // Connected to an external device (10.2) (or something else, catch-all) + CFStringRef str = 0; + MIDIObjectGetStringProperty (connObject, kMIDIPropertyName, &str); + + if (str != 0) + { + s = PlatformUtilities::cfStringToJuceString (str); + CFRelease (str); + } + } + + if (s.isNotEmpty()) + { + if (result.isNotEmpty()) + result += ", "; + + result += s; + } + } + } + } + + CFRelease (connections); } - else if (! result.startsWithIgnoreCase (s)) + + if (result.isNotEmpty()) + return result; + + // Here, either the endpoint had no connections, or we failed to obtain names for any of them. + return getEndpointName (endpoint, false); + } + + static MIDIClientRef getGlobalMidiClient() + { + static MIDIClientRef globalMidiClient = 0; + + if (globalMidiClient == 0) { - // prepend the device name to the entity name - result = (s + " " + result).trimEnd(); + String name ("JUCE"); + + if (JUCEApplication::getInstance() != 0) + name = JUCEApplication::getInstance()->getApplicationName(); + + CFStringRef appName = PlatformUtilities::juceStringToCFString (name); + CHECK_ERROR (MIDIClientCreate (appName, 0, 0, &globalMidiClient)); + CFRelease (appName); } + + return globalMidiClient; } - return result; -} + //============================================================================== + class MidiPortAndEndpoint + { + public: + MidiPortAndEndpoint (MIDIPortRef port_, MIDIEndpointRef endPoint_) + : port (port_), endPoint (endPoint_) + { + } -static const String getConnectedEndpointName (MIDIEndpointRef endpoint) -{ - String result; + ~MidiPortAndEndpoint() + { + if (port != 0) + MIDIPortDispose (port); + + if (port == 0 && endPoint != 0) // if port == 0, it means we created the endpoint, so it's safe to delete it + MIDIEndpointDispose (endPoint); + } + + MIDIPortRef port; + MIDIEndpointRef endPoint; + }; + + //============================================================================== + class MidiPortAndCallback + { + public: + MidiInput* input; + MidiPortAndEndpoint* portAndEndpoint; + MidiInputCallback* callback; + MemoryBlock pendingData; + int pendingBytes; + double pendingDataTime; + bool active; + + void processSysex (const uint8*& d, int& size, const double time) + { + if (*d == 0xf0) + { + pendingBytes = 0; + pendingDataTime = time; + } + + pendingData.ensureSize (pendingBytes + size, false); + uint8* totalMessage = (uint8*) pendingData.getData(); + + uint8* dest = totalMessage + pendingBytes; + + while (size > 0) + { + if (pendingBytes > 0 && *d >= 0x80) + { + if (*d >= 0xfa || *d == 0xf8) + { + callback->handleIncomingMidiMessage (input, MidiMessage (*d, time)); + ++d; + --size; + } + else + { + if (*d == 0xf7) + { + *dest++ = *d++; + pendingBytes++; + --size; + } + + break; + } + } + else + { + *dest++ = *d++; + pendingBytes++; + --size; + } + } - // Does the endpoint have connections? - CFDataRef connections = 0; - int numConnections = 0; + if (totalMessage [pendingBytes - 1] == 0xf7) + { + callback->handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); + pendingBytes = 0; + } + else + { + callback->handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); + } + } + }; - MIDIObjectGetDataProperty (endpoint, kMIDIPropertyConnectionUniqueID, &connections); + static CriticalSection callbackLock; + static Array activeCallbacks; - if (connections != 0) + static void midiInputProc (const MIDIPacketList* pktlist, + void* readProcRefCon, + void* /*srcConnRefCon*/) { - numConnections = (int) (CFDataGetLength (connections) / sizeof (MIDIUniqueID)); + double time = Time::getMillisecondCounterHiRes() * 0.001; + const double originalTime = time; - if (numConnections > 0) + MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon; + const ScopedLock sl (CoreMidiHelpers::callbackLock); + + if (CoreMidiHelpers::activeCallbacks.contains (mpc) && mpc->active) { - const SInt32* pid = reinterpret_cast (CFDataGetBytePtr (connections)); + const MIDIPacket* packet = &pktlist->packet[0]; - for (int i = 0; i < numConnections; ++i, ++pid) + for (unsigned int i = 0; i < pktlist->numPackets; ++i) { - MIDIUniqueID uid = EndianS32_BtoN (*pid); - MIDIObjectRef connObject; - MIDIObjectType connObjectType; - OSStatus err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); + const uint8* d = (const uint8*) (packet->data); + int size = packet->length; - if (err == noErr) + while (size > 0) { - String s; + time = originalTime; - if (connObjectType == kMIDIObjectType_ExternalSource - || connObjectType == kMIDIObjectType_ExternalDestination) + if (mpc->pendingBytes > 0 || d[0] == 0xf0) { - // Connected to an external device's endpoint (10.3 and later). - s = getEndpointName (static_cast (connObject), true); + mpc->processSysex (d, size, time); } else { - // Connected to an external device (10.2) (or something else, catch-all) - CFStringRef str = 0; - MIDIObjectGetStringProperty (connObject, kMIDIPropertyName, &str); + int used = 0; + const MidiMessage m (d, size, used, 0, time); - if (str != 0) + if (used <= 0) { - s = PlatformUtilities::cfStringToJuceString (str); - CFRelease (str); + jassertfalse; // malformed midi message + break; + } + else + { + mpc->callback->handleIncomingMidiMessage (mpc->input, m); } - } - - if (s.isNotEmpty()) - { - if (result.isNotEmpty()) - result += ", "; - result += s; + size -= used; + d += used; } } + + packet = MIDIPacketNext (packet); } } - - CFRelease (connections); } - - if (result.isNotEmpty()) - return result; - - // Here, either the endpoint had no connections, or we failed to obtain names for any of them. - return getEndpointName (endpoint, false); } //============================================================================== @@ -191,7 +353,7 @@ const StringArray MidiOutput::getDevices() if (dest != 0) { - String name (getConnectedEndpointName (dest)); + String name (CoreMidiHelpers::getConnectedEndpointName (dest)); if (name.isEmpty()) name = ""; @@ -212,48 +374,6 @@ int MidiOutput::getDefaultDeviceIndex() return 0; } -static MIDIClientRef globalMidiClient; -static bool hasGlobalClientBeenCreated = false; - -static bool makeSureClientExists() -{ - if (! hasGlobalClientBeenCreated) - { - String name ("JUCE"); - - if (JUCEApplication::getInstance() != 0) - name = JUCEApplication::getInstance()->getApplicationName(); - - CFStringRef appName = PlatformUtilities::juceStringToCFString (name); - - hasGlobalClientBeenCreated = OK (MIDIClientCreate (appName, 0, 0, &globalMidiClient)); - CFRelease (appName); - } - - return hasGlobalClientBeenCreated; -} - -class MidiPortAndEndpoint -{ -public: - MidiPortAndEndpoint (MIDIPortRef port_, MIDIEndpointRef endPoint_) - : port (port_), endPoint (endPoint_) - { - } - - ~MidiPortAndEndpoint() - { - if (port != 0) - MIDIPortDispose (port); - - if (port == 0 && endPoint != 0) // if port == 0, it means we created the endpoint, so it's safe to delete it - MIDIEndpointDispose (endPoint); - } - - MIDIPortRef port; - MIDIEndpointRef endPoint; -}; - MidiOutput* MidiOutput::openDevice (int index) { MidiOutput* mo = 0; @@ -263,19 +383,15 @@ MidiOutput* MidiOutput::openDevice (int index) MIDIEndpointRef endPoint = MIDIGetDestination (index); CFStringRef pname; - if (OK (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) + if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) { - log ("CoreMidi - opening out: " + PlatformUtilities::cfStringToJuceString (pname)); + MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); + MIDIPortRef port; - if (makeSureClientExists()) + if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname, &port))) { - MIDIPortRef port; - - if (OK (MIDIOutputPortCreate (globalMidiClient, pname, &port))) - { - mo = new MidiOutput(); - mo->internal = new MidiPortAndEndpoint (port, endPoint); - } + mo = new MidiOutput(); + mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint); } CFRelease (pname); @@ -288,27 +404,24 @@ MidiOutput* MidiOutput::openDevice (int index) MidiOutput* MidiOutput::createNewDevice (const String& deviceName) { MidiOutput* mo = 0; + MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); - if (makeSureClientExists()) - { - MIDIEndpointRef endPoint; - CFStringRef name = PlatformUtilities::juceStringToCFString (deviceName); - - if (OK (MIDISourceCreate (globalMidiClient, name, &endPoint))) - { - mo = new MidiOutput(); - mo->internal = new MidiPortAndEndpoint (0, endPoint); - } + MIDIEndpointRef endPoint; + CFStringRef name = PlatformUtilities::juceStringToCFString (deviceName); - CFRelease (name); + if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name, &endPoint))) + { + mo = new MidiOutput(); + mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint); } + CFRelease (name); return mo; } MidiOutput::~MidiOutput() { - delete static_cast (internal); + delete static_cast (internal); } void MidiOutput::reset() @@ -326,7 +439,7 @@ void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) void MidiOutput::sendMessageNow (const MidiMessage& message) { - MidiPortAndEndpoint* const mpe = static_cast (internal); + CoreMidiHelpers::MidiPortAndEndpoint* const mpe = static_cast (internal); if (message.isSysEx()) { @@ -381,7 +494,7 @@ const StringArray MidiInput::getDevices() if (source != 0) { - String name (getConnectedEndpointName (source)); + String name (CoreMidiHelpers::getConnectedEndpointName (source)); if (name.isEmpty()) name = ""; @@ -402,132 +515,9 @@ int MidiInput::getDefaultDeviceIndex() return 0; } -//============================================================================== -struct MidiPortAndCallback -{ - MidiInput* input; - MidiPortAndEndpoint* portAndEndpoint; - MidiInputCallback* callback; - MemoryBlock pendingData; - int pendingBytes; - double pendingDataTime; - bool active; - - void processSysex (const uint8*& d, int& size, const double time) - { - if (*d == 0xf0) - { - pendingBytes = 0; - pendingDataTime = time; - } - - pendingData.ensureSize (pendingBytes + size, false); - uint8* totalMessage = (uint8*) pendingData.getData(); - - uint8* dest = totalMessage + pendingBytes; - - while (size > 0) - { - if (pendingBytes > 0 && *d >= 0x80) - { - if (*d >= 0xfa || *d == 0xf8) - { - callback->handleIncomingMidiMessage (input, MidiMessage (*d, time)); - ++d; - --size; - } - else - { - if (*d == 0xf7) - { - *dest++ = *d++; - pendingBytes++; - --size; - } - - break; - } - } - else - { - *dest++ = *d++; - pendingBytes++; - --size; - } - } - - if (totalMessage [pendingBytes - 1] == 0xf7) - { - callback->handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); - pendingBytes = 0; - } - else - { - callback->handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); - } - } -}; - -namespace CoreMidiCallbacks -{ - static CriticalSection callbackLock; - static Array activeCallbacks; -} - -static void midiInputProc (const MIDIPacketList* pktlist, - void* readProcRefCon, - void* /*srcConnRefCon*/) -{ - double time = Time::getMillisecondCounterHiRes() * 0.001; - const double originalTime = time; - - MidiPortAndCallback* const mpc = (MidiPortAndCallback*) readProcRefCon; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - - if (CoreMidiCallbacks::activeCallbacks.contains (mpc) && mpc->active) - { - const MIDIPacket* packet = &pktlist->packet[0]; - - for (unsigned int i = 0; i < pktlist->numPackets; ++i) - { - const uint8* d = (const uint8*) (packet->data); - int size = packet->length; - - while (size > 0) - { - time = originalTime; - - if (mpc->pendingBytes > 0 || d[0] == 0xf0) - { - mpc->processSysex (d, size, time); - } - else - { - int used = 0; - const MidiMessage m (d, size, used, 0, time); - - if (used <= 0) - { - jassertfalse; // malformed midi message - break; - } - else - { - mpc->callback->handleIncomingMidiMessage (mpc->input, m); - } - - size -= used; - d += used; - } - } - - packet = MIDIPacketNext (packet); - } - } -} - MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { + using namespace CoreMidiHelpers; MidiInput* mi = 0; if (((unsigned int) index) < (unsigned int) MIDIGetNumberOfSources()) @@ -538,20 +528,20 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { CFStringRef pname; - if (OK (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) + if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) { - log ("CoreMidi - opening inp: " + PlatformUtilities::cfStringToJuceString (pname)); + MIDIClientRef client = getGlobalMidiClient(); - if (makeSureClientExists()) + if (client != 0) { MIDIPortRef port; ScopedPointer mpc (new MidiPortAndCallback()); mpc->active = false; - if (OK (MIDIInputPortCreate (globalMidiClient, pname, midiInputProc, mpc, &port))) + if (CHECK_ERROR (MIDIInputPortCreate (client, pname, midiInputProc, mpc, &port))) { - if (OK (MIDIPortConnectSource (port, endPoint, 0))) + if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, 0))) { mpc->portAndEndpoint = new MidiPortAndEndpoint (port, endPoint); mpc->callback = callback; @@ -562,12 +552,12 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) mpc->input = mi; mi->internal = mpc; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.add (mpc.release()); + const ScopedLock sl (callbackLock); + activeCallbacks.add (mpc.release()); } else { - OK (MIDIPortDispose (port)); + CHECK_ERROR (MIDIPortDispose (port)); } } } @@ -582,16 +572,18 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) { + using namespace CoreMidiHelpers; MidiInput* mi = 0; + MIDIClientRef client = getGlobalMidiClient(); - if (makeSureClientExists()) + if (client != 0) { ScopedPointer mpc (new MidiPortAndCallback()); mpc->active = false; MIDIEndpointRef endPoint; CFStringRef name = PlatformUtilities::juceStringToCFString(deviceName); - if (OK (MIDIDestinationCreate (globalMidiClient, name, midiInputProc, mpc, &endPoint))) + if (CHECK_ERROR (MIDIDestinationCreate (client, name, midiInputProc, mpc, &endPoint))) { mpc->portAndEndpoint = new MidiPortAndEndpoint (0, endPoint); mpc->callback = callback; @@ -602,8 +594,8 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba mpc->input = mi; mi->internal = mpc; - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.add (mpc.release()); + const ScopedLock sl (callbackLock); + activeCallbacks.add (mpc.release()); } CFRelease (name); @@ -619,16 +611,18 @@ MidiInput::MidiInput (const String& name_) MidiInput::~MidiInput() { + using namespace CoreMidiHelpers; + MidiPortAndCallback* const mpc = static_cast (internal); mpc->active = false; { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - CoreMidiCallbacks::activeCallbacks.removeValue (mpc); + const ScopedLock sl (callbackLock); + activeCallbacks.removeValue (mpc); } if (mpc->portAndEndpoint->port != 0) - OK (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); + CHECK_ERROR (MIDIPortDisconnectSource (mpc->portAndEndpoint->port, mpc->portAndEndpoint->endPoint)); delete mpc->portAndEndpoint; delete mpc; @@ -636,61 +630,31 @@ MidiInput::~MidiInput() void MidiInput::start() { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - static_cast (internal)->active = true; + const ScopedLock sl (CoreMidiHelpers::callbackLock); + static_cast (internal)->active = true; } void MidiInput::stop() { - const ScopedLock sl (CoreMidiCallbacks::callbackLock); - static_cast (internal)->active = false; -} - -#undef log - -#else - -MidiOutput::~MidiOutput() -{ -} - -void MidiOutput::reset() -{ -} - -bool MidiOutput::getVolume (float& /*leftVol*/, float& /*rightVol*/) -{ - return false; -} - -void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) -{ -} - -void MidiOutput::sendMessageNow (const MidiMessage& message) -{ -} - -const StringArray MidiOutput::getDevices() -{ - return StringArray(); -} - -MidiOutput* MidiOutput::openDevice (int index) -{ - return 0; + const ScopedLock sl (CoreMidiHelpers::callbackLock); + static_cast (internal)->active = false; } -const StringArray MidiInput::getDevices() -{ - return StringArray(); -} +#undef CHECK_ERROR -MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) -{ - return 0; -} +//============================================================================== +#else // Stubs for iOS... + +MidiOutput::~MidiOutput() {} +void MidiOutput::reset() {} +bool MidiOutput::getVolume (float& /*leftVol*/, float& /*rightVol*/) { return false; } +void MidiOutput::setVolume (float /*leftVol*/, float /*rightVol*/) {} +void MidiOutput::sendMessageNow (const MidiMessage& message) {} +const StringArray MidiOutput::getDevices() { return StringArray(); } +MidiOutput* MidiOutput::openDevice (int index) { return 0; } +const StringArray MidiInput::getDevices() { return StringArray(); } +MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) { return 0; } #endif diff --git a/src/native/windows/juce_win32_WASAPI.cpp b/src/native/windows/juce_win32_WASAPI.cpp index d6565f6c79..1ee911cb59 100644 --- a/src/native/windows/juce_win32_WASAPI.cpp +++ b/src/native/windows/juce_win32_WASAPI.cpp @@ -27,67 +27,74 @@ // compiled on its own). #if JUCE_INCLUDED_FILE && JUCE_WASAPI +#ifndef WASAPI_ENABLE_LOGGING + #define WASAPI_ENABLE_LOGGING 1 +#endif + //============================================================================== -#if 1 +namespace WasapiClasses +{ -const String getAudioErrorDesc (HRESULT hr) +static void logFailure (HRESULT hr) { - const char* e = 0; + (void) hr; - switch (hr) + #if WASAPI_ENABLE_LOGGING + if (FAILED (hr)) { - case E_POINTER: e = "E_POINTER"; break; - case E_INVALIDARG: e = "E_INVALIDARG"; break; - case AUDCLNT_E_NOT_INITIALIZED: e = "AUDCLNT_E_NOT_INITIALIZED"; break; - case AUDCLNT_E_ALREADY_INITIALIZED: e = "AUDCLNT_E_ALREADY_INITIALIZED"; break; - case AUDCLNT_E_WRONG_ENDPOINT_TYPE: e = "AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break; - case AUDCLNT_E_DEVICE_INVALIDATED: e = "AUDCLNT_E_DEVICE_INVALIDATED"; break; - case AUDCLNT_E_NOT_STOPPED: e = "AUDCLNT_E_NOT_STOPPED"; break; - case AUDCLNT_E_BUFFER_TOO_LARGE: e = "AUDCLNT_E_BUFFER_TOO_LARGE"; break; - case AUDCLNT_E_OUT_OF_ORDER: e = "AUDCLNT_E_OUT_OF_ORDER"; break; - case AUDCLNT_E_UNSUPPORTED_FORMAT: e = "AUDCLNT_E_UNSUPPORTED_FORMAT"; break; - case AUDCLNT_E_INVALID_SIZE: e = "AUDCLNT_E_INVALID_SIZE"; break; - case AUDCLNT_E_DEVICE_IN_USE: e = "AUDCLNT_E_DEVICE_IN_USE"; break; - case AUDCLNT_E_BUFFER_OPERATION_PENDING: e = "AUDCLNT_E_BUFFER_OPERATION_PENDING"; break; - case AUDCLNT_E_THREAD_NOT_REGISTERED: e = "AUDCLNT_E_THREAD_NOT_REGISTERED"; break; - case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED: e = "AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break; - case AUDCLNT_E_ENDPOINT_CREATE_FAILED: e = "AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break; - case AUDCLNT_E_SERVICE_NOT_RUNNING: e = "AUDCLNT_E_SERVICE_NOT_RUNNING"; break; - case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED: e = "AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break; - case AUDCLNT_E_EXCLUSIVE_MODE_ONLY: e = "AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break; - case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: e = "AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break; - case AUDCLNT_E_EVENTHANDLE_NOT_SET: e = "AUDCLNT_E_EVENTHANDLE_NOT_SET"; break; - case AUDCLNT_E_INCORRECT_BUFFER_SIZE: e = "AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break; - case AUDCLNT_E_BUFFER_SIZE_ERROR: e = "AUDCLNT_E_BUFFER_SIZE_ERROR"; break; - case AUDCLNT_S_BUFFER_EMPTY: e = "AUDCLNT_S_BUFFER_EMPTY"; break; - case AUDCLNT_S_THREAD_ALREADY_REGISTERED: e = "AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break; - default: return String::toHexString ((int) hr); - } + String e; + e << Time::getCurrentTime().toString (true, true, true, true) + << " -- WASAPI error: "; - return e; -} + switch (hr) + { + case E_POINTER: e << "E_POINTER"; break; + case E_INVALIDARG: e << "E_INVALIDARG"; break; + case AUDCLNT_E_NOT_INITIALIZED: e << "AUDCLNT_E_NOT_INITIALIZED"; break; + case AUDCLNT_E_ALREADY_INITIALIZED: e << "AUDCLNT_E_ALREADY_INITIALIZED"; break; + case AUDCLNT_E_WRONG_ENDPOINT_TYPE: e << "AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break; + case AUDCLNT_E_DEVICE_INVALIDATED: e << "AUDCLNT_E_DEVICE_INVALIDATED"; break; + case AUDCLNT_E_NOT_STOPPED: e << "AUDCLNT_E_NOT_STOPPED"; break; + case AUDCLNT_E_BUFFER_TOO_LARGE: e << "AUDCLNT_E_BUFFER_TOO_LARGE"; break; + case AUDCLNT_E_OUT_OF_ORDER: e << "AUDCLNT_E_OUT_OF_ORDER"; break; + case AUDCLNT_E_UNSUPPORTED_FORMAT: e << "AUDCLNT_E_UNSUPPORTED_FORMAT"; break; + case AUDCLNT_E_INVALID_SIZE: e << "AUDCLNT_E_INVALID_SIZE"; break; + case AUDCLNT_E_DEVICE_IN_USE: e << "AUDCLNT_E_DEVICE_IN_USE"; break; + case AUDCLNT_E_BUFFER_OPERATION_PENDING: e << "AUDCLNT_E_BUFFER_OPERATION_PENDING"; break; + case AUDCLNT_E_THREAD_NOT_REGISTERED: e << "AUDCLNT_E_THREAD_NOT_REGISTERED"; break; + case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED: e << "AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break; + case AUDCLNT_E_ENDPOINT_CREATE_FAILED: e << "AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break; + case AUDCLNT_E_SERVICE_NOT_RUNNING: e << "AUDCLNT_E_SERVICE_NOT_RUNNING"; break; + case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED: e << "AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break; + case AUDCLNT_E_EXCLUSIVE_MODE_ONLY: e << "AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break; + case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: e << "AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break; + case AUDCLNT_E_EVENTHANDLE_NOT_SET: e << "AUDCLNT_E_EVENTHANDLE_NOT_SET"; break; + case AUDCLNT_E_INCORRECT_BUFFER_SIZE: e << "AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break; + case AUDCLNT_E_BUFFER_SIZE_ERROR: e << "AUDCLNT_E_BUFFER_SIZE_ERROR"; break; + case AUDCLNT_S_BUFFER_EMPTY: e << "AUDCLNT_S_BUFFER_EMPTY"; break; + case AUDCLNT_S_THREAD_ALREADY_REGISTERED: e << "AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break; + default: e << String::toHexString ((int) hr); break; + } -#define logFailure(hr) { if (FAILED (hr)) { DBG ("WASAPI FAIL! " + getAudioErrorDesc (hr)); jassertfalse; } } -#define OK(a) wasapi_checkResult(a) + DBG (e); + jassertfalse; + } + #endif +} -static bool wasapi_checkResult (HRESULT hr) +static bool check (HRESULT hr) { logFailure (hr); return SUCCEEDED (hr); } -#else - #define logFailure(hr) {} - #define OK(a) SUCCEEDED(a) -#endif - //============================================================================== -static const String wasapi_getDeviceID (IMMDevice* const device) +static const String getDeviceID (IMMDevice* const device) { String s; WCHAR* deviceId = 0; - if (OK (device->GetId (&deviceId))) + if (check (device->GetId (&deviceId))) { s = String (deviceId); CoTaskMemFree (deviceId); @@ -96,27 +103,28 @@ static const String wasapi_getDeviceID (IMMDevice* const device) return s; } -static EDataFlow wasapi_getDataFlow (IMMDevice* const device) +static EDataFlow getDataFlow (IMMDevice* const device) { EDataFlow flow = eRender; ComSmartPtr endPoint; - if (OK (device->QueryInterface (__uuidof (IMMEndpoint), (void**) &endPoint))) - (void) OK (endPoint->GetDataFlow (&flow)); + if (check (device->QueryInterface (__uuidof (IMMEndpoint), (void**) &endPoint))) + (void) check (endPoint->GetDataFlow (&flow)); return flow; } -static int wasapi_refTimeToSamples (const REFERENCE_TIME& t, const double sampleRate) throw() +static int refTimeToSamples (const REFERENCE_TIME& t, const double sampleRate) throw() { return roundDoubleToInt (sampleRate * ((double) t) * 0.0000001); } -static void wasapi_copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* const src) throw() +static void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* const src) throw() { memcpy (&dest, src, src->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? sizeof (WAVEFORMATEXTENSIBLE) : sizeof (WAVEFORMATEX)); } + //============================================================================== class WASAPIDeviceBase { @@ -139,21 +147,21 @@ public: return; REFERENCE_TIME defaultPeriod, minPeriod; - if (! OK (tempClient->GetDevicePeriod (&defaultPeriod, &minPeriod))) + if (! check (tempClient->GetDevicePeriod (&defaultPeriod, &minPeriod))) return; WAVEFORMATEX* mixFormat = 0; - if (! OK (tempClient->GetMixFormat (&mixFormat))) + if (! check (tempClient->GetMixFormat (&mixFormat))) return; WAVEFORMATEXTENSIBLE format; - wasapi_copyWavFormat (format, mixFormat); + copyWavFormat (format, mixFormat); CoTaskMemFree (mixFormat); actualNumChannels = numChannels = format.Format.nChannels; defaultSampleRate = format.Format.nSamplesPerSec; - minBufferSize = wasapi_refTimeToSamples (minPeriod, defaultSampleRate); - defaultBufferSize = wasapi_refTimeToSamples (defaultPeriod, defaultSampleRate); + minBufferSize = refTimeToSamples (minPeriod, defaultSampleRate); + defaultBufferSize = refTimeToSamples (defaultPeriod, defaultSampleRate); rates.addUsingDefaultSort (defaultSampleRate); @@ -203,12 +211,12 @@ public: channelMaps.add (i); REFERENCE_TIME latency; - if (OK (client->GetStreamLatency (&latency))) - latencySamples = wasapi_refTimeToSamples (latency, sampleRate); + if (check (client->GetStreamLatency (&latency))) + latencySamples = refTimeToSamples (latency, sampleRate); - (void) OK (client->GetBufferSize (&actualBufferSize)); + (void) check (client->GetBufferSize (&actualBufferSize)); - return OK (client->SetEventHandle (clientEvent)); + return check (client->SetEventHandle (clientEvent)); } return false; @@ -293,7 +301,7 @@ private: if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec) { - wasapi_copyWavFormat (format, (WAVEFORMATEX*) nearestFormat); + copyWavFormat (format, (WAVEFORMATEX*) nearestFormat); hr = S_OK; } @@ -301,13 +309,13 @@ private: REFERENCE_TIME defaultPeriod = 0, minPeriod = 0; if (useExclusiveMode) - OK (client->GetDevicePeriod (&defaultPeriod, &minPeriod)); + check (client->GetDevicePeriod (&defaultPeriod, &minPeriod)); GUID session; if (hr == S_OK - && OK (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session))) + && check (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session))) { actualNumChannels = format.Format.nChannels; const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; @@ -345,7 +353,7 @@ public: reservoirCapacity = 16384; reservoir.setSize (actualNumChannels * reservoirCapacity * sizeof (float)); return openClient (newSampleRate, newChannels) - && (numChannels == 0 || OK (client->GetService (__uuidof (IAudioCaptureClient), (void**) &captureClient))); + && (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), (void**) &captureClient))); } void close() @@ -392,7 +400,7 @@ public: else { UINT32 packetLength = 0; - if (! OK (captureClient->GetNextPacketSize (&packetLength))) + if (! check (captureClient->GetNextPacketSize (&packetLength))) break; if (packetLength == 0) @@ -408,7 +416,7 @@ public: UINT32 numSamplesAvailable; DWORD flags; - if (OK (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, 0, 0))) + if (check (captureClient->GetBuffer (&inputData, &numSamplesAvailable, &flags, 0, 0))) { const int samplesToDo = jmin (bufferSize, (int) numSamplesAvailable); @@ -458,7 +466,7 @@ public: bool open (const double newSampleRate, const BigInteger& newChannels) { return openClient (newSampleRate, newChannels) - && (numChannels == 0 || OK (client->GetService (__uuidof (IAudioRenderClient), (void**) &renderClient))); + && (numChannels == 0 || check (client->GetService (__uuidof (IAudioRenderClient), (void**) &renderClient))); } void close() @@ -491,7 +499,7 @@ public: while (bufferSize > 0) { UINT32 padding = 0; - if (! OK (client->GetCurrentPadding (&padding))) + if (! check (client->GetCurrentPadding (&padding))) return; int samplesToDo = useExclusiveMode ? bufferSize @@ -507,7 +515,7 @@ public: } uint8* outputData = 0; - if (OK (renderClient->GetBuffer (samplesToDo, &outputData))) + if (check (renderClient->GetBuffer (samplesToDo, &outputData))) { for (int i = 0; i < numSrcBuffers; ++i) converter->convertSamples (outputData, channelMaps.getUnchecked(i), srcBuffers[i], offset, samplesToDo); @@ -866,28 +874,28 @@ private: bool createDevices() { ComSmartPtr enumerator; - if (! OK (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) + if (! check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) return false; ComSmartPtr deviceCollection; - if (! OK (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &deviceCollection))) + if (! check (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &deviceCollection))) return false; UINT32 numDevices = 0; - if (! OK (deviceCollection->GetCount (&numDevices))) + if (! check (deviceCollection->GetCount (&numDevices))) return false; for (UINT32 i = 0; i < numDevices; ++i) { ComSmartPtr device; - if (! OK (deviceCollection->Item (i, &device))) + if (! check (deviceCollection->Item (i, &device))) continue; - const String deviceId (wasapi_getDeviceID (device)); + const String deviceId (getDeviceID (device)); if (deviceId.isEmpty()) continue; - const EDataFlow flow = wasapi_getDataFlow (device); + const EDataFlow flow = getDataFlow (device); if (deviceId == inputDeviceId && flow == eCapture) inputDevice = new WASAPIInputDevice (device, useExclusiveMode); @@ -930,7 +938,7 @@ public: inputDeviceIds.clear(); ComSmartPtr enumerator; - if (! OK (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) + if (! check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) return; const String defaultRenderer = getDefaultEndpoint (enumerator, false); @@ -939,20 +947,20 @@ public: ComSmartPtr deviceCollection; UINT32 numDevices = 0; - if (! (OK (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &deviceCollection)) - && OK (deviceCollection->GetCount (&numDevices)))) + if (! (check (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, &deviceCollection)) + && check (deviceCollection->GetCount (&numDevices)))) return; for (UINT32 i = 0; i < numDevices; ++i) { ComSmartPtr device; - if (! OK (deviceCollection->Item (i, &device))) + if (! check (deviceCollection->Item (i, &device))) continue; - const String deviceId (wasapi_getDeviceID (device)); + const String deviceId (getDeviceID (device)); DWORD state = 0; - if (! OK (device->GetState (&state))) + if (! check (device->GetState (&state))) continue; if (state != DEVICE_STATE_ACTIVE) @@ -962,18 +970,18 @@ public: { ComSmartPtr properties; - if (! OK (device->OpenPropertyStore (STGM_READ, &properties))) + if (! check (device->OpenPropertyStore (STGM_READ, &properties))) continue; PROPVARIANT value; PropVariantInit (&value); - if (OK (properties->GetValue (PKEY_Device_FriendlyName, &value))) + if (check (properties->GetValue (PKEY_Device_FriendlyName, &value))) name = value.pwszVal; PropVariantClear (&value); } - const EDataFlow flow = wasapi_getDataFlow (device); + const EDataFlow flow = getDataFlow (device); if (flow == eRender) { @@ -1057,11 +1065,11 @@ private: { String s; IMMDevice* dev = 0; - if (OK (enumerator->GetDefaultAudioEndpoint (forCapture ? eCapture : eRender, - eMultimedia, &dev))) + if (check (enumerator->GetDefaultAudioEndpoint (forCapture ? eCapture : eRender, + eMultimedia, &dev))) { WCHAR* deviceId = 0; - if (OK (dev->GetId (&deviceId))) + if (check (dev->GetId (&deviceId))) { s = String (deviceId); CoTaskMemFree (deviceId); @@ -1078,13 +1086,12 @@ private: WASAPIAudioIODeviceType& operator= (const WASAPIAudioIODeviceType&); }; +} + //============================================================================== AudioIODeviceType* juce_createAudioIODeviceType_WASAPI() { - return new WASAPIAudioIODeviceType(); + return new WasapiClasses::WASAPIAudioIODeviceType(); } -#undef logFailure -#undef OK - #endif diff --git a/src/text/juce_String.h b/src/text/juce_String.h index b3e0b5a23c..ab9b640aa1 100644 --- a/src/text/juce_String.h +++ b/src/text/juce_String.h @@ -1052,6 +1052,11 @@ private: void createInternal (const juce_wchar* text, size_t numChars); void appendInternal (const juce_wchar* text, int numExtraChars); + + // This private cast operator should prevent strings being accidentally cast + // to bools (this is possible because the compiler can add an implicit cast + // via a const char*) + operator bool() const throw() { return false; } }; //==============================================================================