From: <man...@us...> - 2013-09-28 17:58:49
|
Revision: 2789 http://sourceforge.net/p/modplug/code/2789 Author: manxorist Date: 2013-09-28 17:58:40 +0000 (Sat, 28 Sep 2013) Log Message: ----------- Merged revision(s) 2780-2788 from branches/manx/snddev: [Ref] sounddev: Simplify ISoundDevice interface and always provide GetStreamPositionSamples(). [Ref] Remove m_TotalSamplesRendered from CMainFrame. The sound device itself knows better. ........ [Mod] sounddev: Always default or fallback to a WaveOut device which is by far the most stable and has the least suprising user experience. ........ [Fix] sounddev: Move querying of default ASIO device samplerate until after sound device code has actually been initialized. This breaks circular dependencies and removes strange initialization order fluctuation depending on values stored in configuration. ........ [Ref] sounddev: Add a class SoundDevicesManager which stores sound device enumeration data instead of storing this globally. [Imp] sounddev: Remove static limit of 16 DirectSound devices. [Imp] sounddev: Remove static limit of 8 ASIO devices. [Ref] sounddev: Let CreateSoundDevice() not only take the device type but also the device index, remove device index from Open(). Cleanup backends code accordingly. [Ref] sounddev: Rework sound device enumeration and avoid storing device names to fixed size char buffers. [Imp] sounddev: Make sound device names Unicode. Not really useful at the moment, but unicodification has to start somewhere. [New] sounddev: Add possibility to re-enumerate sound devices (not in GUI yet). ........ [Ref] sounddev: Remove redundant CASIODevice::m_nChannels. ........ [Ref] sounddev: Rename CanRampleRate() to GetSampleRates() and simplify it a tiny bit. [Fix] When selecting a new sound device in the settings dialog and last selected samplerate is not supported by the new device, no samplerate gets selected in the ComboBox. Select the first one instead. ........ [Ref] Simplify audioOpenDevice() and audioTryOpeningDevice(). There is no need to open ISoundDevice twice for fixed-sampleformat devices like ASIO. Just let CASIODevice update its internal sampleformat unconditionally and query it after the device has been opened to update the tracker settings accordingly. ........ [Ref] Avoid touching TrackerSettings in CMainFrame::AudioRead. ........ [Fix] sounddev: Compile fix for VS2008 and older SDKs. ........ Modified Paths: -------------- trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/Mainfrm.h trunk/OpenMPT/mptrack/Mpdlgs.cpp trunk/OpenMPT/mptrack/Mptrack.cpp trunk/OpenMPT/mptrack/Mptrack.h trunk/OpenMPT/mptrack/Notification.h trunk/OpenMPT/mptrack/TrackerSettings.cpp trunk/OpenMPT/sounddev/SoundDevice.cpp trunk/OpenMPT/sounddev/SoundDevice.h trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp trunk/OpenMPT/sounddev/SoundDeviceASIO.h trunk/OpenMPT/sounddev/SoundDeviceDirectSound.cpp trunk/OpenMPT/sounddev/SoundDeviceDirectSound.h trunk/OpenMPT/sounddev/SoundDevicePortAudio.cpp trunk/OpenMPT/sounddev/SoundDevicePortAudio.h trunk/OpenMPT/sounddev/SoundDeviceWaveout.cpp trunk/OpenMPT/sounddev/SoundDeviceWaveout.h Property Changed: ---------------- trunk/OpenMPT/ Index: trunk/OpenMPT =================================================================== --- trunk/OpenMPT 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT 2013-09-28 17:58:40 UTC (rev 2789) Property changes on: trunk/OpenMPT ___________________________________________________________________ Modified: svn:mergeinfo ## -12,6 +12,7 ## /branches/manx/project-files-cleanups:1378-1382 /branches/manx/sampleformat-ref:2554-2582 /branches/manx/serialization-utils-cleanup:2382-2386,2395 +/branches/manx/snddev:2780-2788 /branches/manx/snddev-fixes:1605-1713 /branches/manx/stdstring-names:2223,2228 /branches/manx/stdstring-song-name:2462-2463 \ No newline at end of property Modified: trunk/OpenMPT/mptrack/MainFrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/mptrack/MainFrm.cpp 2013-09-28 17:58:40 UTC (rev 2789) @@ -205,7 +205,6 @@ m_szInfoText[0] = 0; m_szXInfoText[0]= 0; //rewbs.xinfo - m_TotalSamplesRendered = 0; m_PendingNotificationSempahore = NULL; MemsetZero(gcolrefVuMeter); @@ -245,14 +244,27 @@ OnUpdateFrameTitle(false); // Check for valid sound device - if (!EnumerateSoundDevices(SNDDEV_GET_TYPE(TrackerSettings::Instance().m_nWaveDevice), SNDDEV_GET_NUMBER(TrackerSettings::Instance().m_nWaveDevice), nullptr, 0)) + if(!theApp.GetSoundDevicesManager()->FindDeviceInfo(TrackerSettings::Instance().m_nWaveDevice)) { - TrackerSettings::Instance().m_nWaveDevice = SNDDEV_BUILD_ID(0, SNDDEV_DSOUND); - if (!EnumerateSoundDevices(SNDDEV_GET_TYPE(TrackerSettings::Instance().m_nWaveDevice), SNDDEV_GET_NUMBER(TrackerSettings::Instance().m_nWaveDevice), nullptr, 0)) - { - TrackerSettings::Instance().m_nWaveDevice = SNDDEV_BUILD_ID(0, SNDDEV_WAVEOUT); - } + // Fall back to default WaveOut device + TrackerSettings::Instance().m_nWaveDevice = SNDDEV_BUILD_ID(0, SNDDEV_WAVEOUT); } + if(TrackerSettings::Instance().m_MixerSettings.gdwMixingFreq == 0) + { + TrackerSettings::Instance().m_MixerSettings.gdwMixingFreq = MixerSettings().gdwMixingFreq; + #ifndef NO_ASIO + // If no mixing rate is specified and we're using ASIO, get a mixing rate supported by the device. + if(SNDDEV_GET_TYPE(TrackerSettings::Instance().m_nWaveDevice) == SNDDEV_ASIO) + { + ISoundDevice *dummy = theApp.GetSoundDevicesManager()->CreateSoundDevice(TrackerSettings::Instance().m_nWaveDevice); + if(dummy) + { + TrackerSettings::Instance().m_MixerSettings.gdwMixingFreq = dummy->GetCurrentSampleRate(); + delete dummy; + } + } + #endif // NO_ASIO + } // Create Notify Thread m_PendingNotificationSempahore = CreateSemaphore(NULL, 0, 1, NULL); @@ -721,23 +733,16 @@ Notification PendingNotification; bool found = false; int64 currenttotalsamples = 0; - bool currenttotalsamplesValid = false; { Util::lock_guard<Util::mutex> lock(m_SoundDeviceMutex); - if(gpSoundDevice && gpSoundDevice->HasGetStreamPosition()) + if(gpSoundDevice) { currenttotalsamples = gpSoundDevice->GetStreamPositionSamples(); - currenttotalsamplesValid = true; } } { // advance to the newest notification, drop the obsolete ones Util::lock_guard<Util::mutex> lock(m_NotificationBufferMutex); - if(!currenttotalsamplesValid) - { - currenttotalsamples = m_TotalSamplesRendered; - currenttotalsamplesValid = true; - } const Notification * pnotify = nullptr; const Notification * p = m_NotifyBuffer.peek_p(); if(p && currenttotalsamples >= p->timestampSamples) @@ -849,11 +854,10 @@ }; -void CMainFrame::AudioRead(PVOID pvData, ULONG NumFrames) -//------------------------------------------------------- +void CMainFrame::AudioRead(PVOID pvData, ULONG NumFrames, SampleFormat sampleFormat) +//---------------------------------------------------------------------------------- { OPENMPT_PROFILE_FUNCTION(Profiler::Audio); - const SampleFormat sampleFormat = TrackerSettings::Instance().m_SampleFormat; StereoVuMeterTargetWrapper target(sampleFormat, m_Dither, pvData); CSoundFile::samplecount_t renderedFrames = m_pSndFile->Read(NumFrames, target); ASSERT(renderedFrames <= NumFrames); @@ -874,35 +878,27 @@ } -void CMainFrame::AudioDone(ULONG NumSamples, ULONG SamplesLatency) +void CMainFrame::AudioDone(ULONG NumSamples, int64 streamPosition) //---------------------------------------------------------------- { OPENMPT_PROFILE_FUNCTION(Profiler::Notify); - DoNotification(NumSamples, SamplesLatency, false); + DoNotification(NumSamples, streamPosition); } -void CMainFrame::AudioDone(ULONG NumSamples) -//------------------------------------------ +bool CMainFrame::audioTryOpeningDevice() +//-------------------------------------- { - OPENMPT_PROFILE_FUNCTION(Profiler::Notify); - DoNotification(NumSamples, 0, true); -} - - -bool CMainFrame::audioTryOpeningDevice(UINT channels, SampleFormat sampleFormat, UINT samplespersec) -//-------------------------------------------------------------------------------------------------- -{ Util::lock_guard<Util::mutex> lock(m_SoundDeviceMutex); - const UINT nDevType = SNDDEV_GET_TYPE(TrackerSettings::Instance().m_nWaveDevice); - if(gpSoundDevice && (gpSoundDevice->GetDeviceType() != nDevType)) + const UINT nDevID = TrackerSettings::Instance().m_nWaveDevice; + if(gpSoundDevice && (gpSoundDevice->GetDeviceID() != nDevID)) { delete gpSoundDevice; - gpSoundDevice = NULL; + gpSoundDevice = nullptr; } if(!gpSoundDevice) { - gpSoundDevice = CreateSoundDevice(nDevType); + gpSoundDevice = theApp.GetSoundDevicesManager()->CreateSoundDevice(nDevID); } if(!gpSoundDevice) { @@ -914,10 +910,10 @@ settings.LatencyMS = TrackerSettings::Instance().m_LatencyMS; settings.UpdateIntervalMS = TrackerSettings::Instance().m_UpdateIntervalMS; settings.fulCfgOptions = TrackerSettings::Instance().GetSoundDeviceFlags(); - settings.Samplerate = samplespersec; - settings.Channels = (uint8)channels; - settings.sampleFormat = sampleFormat; - return gpSoundDevice->Open(SNDDEV_GET_NUMBER(TrackerSettings::Instance().m_nWaveDevice), settings); + settings.Samplerate = TrackerSettings::Instance().m_MixerSettings.gdwMixingFreq; + settings.Channels = (uint8)TrackerSettings::Instance().m_MixerSettings.gnChannels; + settings.sampleFormat = TrackerSettings::Instance().m_SampleFormat; + return gpSoundDevice->Open(settings); } @@ -932,37 +928,30 @@ bool CMainFrame::audioOpenDevice() //-------------------------------- { - if(IsAudioDeviceOpen()) return true; - bool err = false; - - if (!TrackerSettings::Instance().m_MixerSettings.gdwMixingFreq) err = true; - if ((TrackerSettings::Instance().m_MixerSettings.gnChannels != 1) && (TrackerSettings::Instance().m_MixerSettings.gnChannels != 2) && (TrackerSettings::Instance().m_MixerSettings.gnChannels != 4)) err = true; - if(!err) + if(IsAudioDeviceOpen()) { - err = !audioTryOpeningDevice(TrackerSettings::Instance().m_MixerSettings.gnChannels, - TrackerSettings::Instance().m_SampleFormat, - TrackerSettings::Instance().m_MixerSettings.gdwMixingFreq); - SampleFormat fixedBitsPerSample = SampleFormatInvalid; + return true; + } + if(TrackerSettings::Instance().m_MixerSettings.IsValid()) + { + if(audioTryOpeningDevice()) { - Util::lock_guard<Util::mutex> lock(m_SoundDeviceMutex); - fixedBitsPerSample = (gpSoundDevice) ? SampleFormat(gpSoundDevice->HasFixedSampleFormat()) : SampleFormatInvalid; + SampleFormat actualSampleFormat = SampleFormatInvalid; + { + Util::lock_guard<Util::mutex> lock(m_SoundDeviceMutex); + actualSampleFormat = gpSoundDevice->GetActualSampleFormat(); + } + if(actualSampleFormat.IsValid()) + { + TrackerSettings::Instance().m_SampleFormat = actualSampleFormat; + // Device is ready + return true; + } } - if(fixedBitsPerSample.IsValid() && (fixedBitsPerSample != TrackerSettings::Instance().m_SampleFormat)) - { - TrackerSettings::Instance().m_SampleFormat = fixedBitsPerSample; - err = !audioTryOpeningDevice(TrackerSettings::Instance().m_MixerSettings.gnChannels, - TrackerSettings::Instance().m_SampleFormat, - TrackerSettings::Instance().m_MixerSettings.gdwMixingFreq); - } } // Display error message box - if(err) - { - Reporting::Error("Unable to open sound device!"); - return false; - } - // Device is ready - return true; + Reporting::Error("Unable to open sound device!"); + return false; } @@ -988,7 +977,6 @@ { Util::lock_guard<Util::mutex> lock(m_NotificationBufferMutex); m_NotifyBuffer.clear(); - m_TotalSamplesRendered = 0; } } @@ -1026,23 +1014,10 @@ } -BOOL CMainFrame::DoNotification(DWORD dwSamplesRead, DWORD SamplesLatency, bool hasSoundDeviceGetStreamPosition) -//-------------------------------------------------------------------------------------------------------------- +bool CMainFrame::DoNotification(DWORD dwSamplesRead, int64 streamPosition) +//------------------------------------------------------------------------ { - if(dwSamplesRead == 0) return FALSE; - int64 notificationtimestamp = 0; - { - Util::lock_guard<Util::mutex> lock(m_NotificationBufferMutex); // protect m_TotalSamplesRendered - m_TotalSamplesRendered += dwSamplesRead; - if(hasSoundDeviceGetStreamPosition) - { - notificationtimestamp = m_TotalSamplesRendered; - } else - { - notificationtimestamp = m_TotalSamplesRendered + SamplesLatency; - } - } - if(!m_pSndFile) return FALSE; + if(!m_pSndFile) return false; FlagSet<Notification::Type> notifyType(Notification::Default); Notification::Item notifyItem = 0; @@ -1052,14 +1027,13 @@ notifyType = m_pSndFile->m_pModDoc->GetNotificationType(); notifyItem = m_pSndFile->m_pModDoc->GetNotificationItem(); } + // Notify Client - //if(m_NotifyBuffer.read_size() > 0) - { - SetEvent(m_hNotifyWakeUp); - } + SetEvent(m_hNotifyWakeUp); + // Add an entry to the notification history - Notification notification(notifyType, notifyItem, notificationtimestamp, m_pSndFile->m_nRow, m_pSndFile->m_nTickCount, m_pSndFile->m_nCurrentOrder, m_pSndFile->m_nPattern, m_pSndFile->GetMixStat()); + Notification notification(notifyType, notifyItem, streamPosition, m_pSndFile->m_nRow, m_pSndFile->m_nTickCount, m_pSndFile->m_nCurrentOrder, m_pSndFile->m_nPattern, m_pSndFile->GetMixStat()); m_pSndFile->ResetMixStat(); @@ -1166,8 +1140,7 @@ SetEvent(m_hNotifyWakeUp); - return TRUE; - + return true; } Modified: trunk/OpenMPT/mptrack/Mainfrm.h =================================================================== --- trunk/OpenMPT/mptrack/Mainfrm.h 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/mptrack/Mainfrm.h 2013-09-28 17:58:40 UTC (rev 2789) @@ -302,7 +302,6 @@ // Notification Buffer Util::mutex m_NotificationBufferMutex; // to avoid deadlocks, this mutex should only be taken as a innermost lock, i.e. do not block on anything while holding this mutex - int64 m_TotalSamplesRendered; Util::fixed_size_queue<Notification,MAX_UPDATE_HISTORY> m_NotifyBuffer; HANDLE m_PendingNotificationSempahore; // protects the one notification that is in flight from the notification thread to the gui thread from being freed while the gui thread still uses it @@ -326,16 +325,15 @@ // from ISoundSource void FillAudioBufferLocked(IFillAudioBuffer &callback); - void AudioRead(PVOID pData, ULONG NumSamples); - void AudioDone(ULONG NumSamples, ULONG SamplesLatency); - void AudioDone(ULONG NumSamples); + void AudioRead(PVOID pData, ULONG NumSamples, SampleFormat sampleFormat); + void AudioDone(ULONG NumSamples, int64 streamPosition); - bool audioTryOpeningDevice(UINT channels, SampleFormat sampleFormat, UINT samplespersec); + bool audioTryOpeningDevice(); bool audioOpenDevice(); bool audioReopenDevice(); void audioCloseDevice(); bool IsAudioDeviceOpen() const; - BOOL DoNotification(DWORD dwSamplesRead, DWORD SamplesLatency, bool hasSoundDeviceGetStreamPosition); + bool DoNotification(DWORD dwSamplesRead, int64 streamPosition); // Midi Input Functions public: Modified: trunk/OpenMPT/mptrack/Mpdlgs.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mpdlgs.cpp 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/mptrack/Mpdlgs.cpp 2013-09-28 17:58:40 UTC (rev 2789) @@ -18,6 +18,7 @@ #include "moddoc.h" #include "../sounddev/SoundDevice.h" #include ".\mpdlgs.h" +#include "../common/StringFixer.h" #define str_preampChangeNote GetStrI18N(_TEXT("Note: The Pre-Amp setting affects sample volume only. Changing it may cause undesired effects on volume balance between sample based instruments and plugin instruments.\nIn other words: Don't touch this slider unless you know what you are doing.")) @@ -185,25 +186,25 @@ COMBOBOXEXITEM cbi; UINT iItem = 0; - for (UINT nDevType = 0; nDevType < SNDDEV_NUM_DEVTYPES; nDevType++) + for(std::vector<SoundDeviceInfo>::const_iterator it = theApp.GetSoundDevicesManager()->begin(); it != theApp.GetSoundDevicesManager()->end(); ++it) { + if(!TrackerSettings::Instance().m_MorePortaudio) { - if(nDevType == SNDDEV_PORTAUDIO_ASIO || nDevType == SNDDEV_PORTAUDIO_DS || nDevType == SNDDEV_PORTAUDIO_WMME) + if(it->type == SNDDEV_PORTAUDIO_ASIO || it->type == SNDDEV_PORTAUDIO_DS || it->type == SNDDEV_PORTAUDIO_WMME) { // skip those portaudio apis that are already implemented via our own ISoundDevice class // can be overwritten via [Sound Settings]MorePortaudio=1 continue; } } - UINT nDev = 0; - while (EnumerateSoundDevices(nDevType, nDev, s, CountOf(s))) { + mpt::String::Copy(s, mpt::String::Encode(it->name, mpt::CharsetLocale)); cbi.mask = CBEIF_IMAGE | CBEIF_LPARAM | CBEIF_TEXT | CBEIF_SELECTEDIMAGE | CBEIF_OVERLAY; cbi.iItem = iItem; cbi.cchTextMax = 0; - switch(nDevType) + switch(it->type) { case SNDDEV_DSOUND: case SNDDEV_PORTAUDIO_DS: @@ -220,12 +221,11 @@ cbi.iSelectedImage = cbi.iImage; cbi.iOverlay = cbi.iImage; cbi.iIndent = 0; - cbi.lParam = SNDDEV_BUILD_ID(nDev, nDevType); + cbi.lParam = SNDDEV_BUILD_ID(it->index, it->type); cbi.pszText = s; int pos = m_CbnDevice.InsertItem(&cbi); if (cbi.lParam == (LONG)m_nSoundDevice) m_CbnDevice.SetCurSel(pos); iItem++; - nDev++; } } UpdateControls(m_nSoundDevice); @@ -377,54 +377,50 @@ void COptionsSoundcard::UpdateSampleRates(int dev) //------------------------------------------------ { - CHAR s[16]; m_CbnMixingFreq.ResetContent(); - std::vector<bool> supportedRates; - const std::vector<uint32> samplerates = TrackerSettings::Instance().GetSampleRates(); + std::vector<uint32> samplerates = TrackerSettings::Instance().GetSampleRates(); - bool knowRates = false; { - Util::lock_guard<Util::mutex> lock(CMainFrame::GetMainFrame()->m_SoundDeviceMutex); - ISoundDevice *dummy = nullptr; - bool justCreated = false; - if(TrackerSettings::Instance().m_nWaveDevice == dev) - { - // If this is the currently active sound device, it might already be playing something, so we shouldn't create yet another instance of it. - dummy = CMainFrame::GetMainFrame()->gpSoundDevice; - } - if(dummy == nullptr) - { - justCreated = true; - dummy = CreateSoundDevice(SNDDEV_GET_TYPE(dev)); - } + Util::lock_guard<Util::mutex> lock(CMainFrame::GetMainFrame()->m_SoundDeviceMutex); + ISoundDevice *dummy = nullptr; + bool justCreated = false; + if(TrackerSettings::Instance().m_nWaveDevice == dev) + { + // If this is the currently active sound device, it might already be playing something, so we shouldn't create yet another instance of it. + dummy = CMainFrame::GetMainFrame()->gpSoundDevice; + } + if(dummy == nullptr) + { + justCreated = true; + dummy = theApp.GetSoundDevicesManager()->CreateSoundDevice(dev); + } - if(dummy != nullptr) - { - // Now we can query the supported sample rates. - knowRates = dummy->CanSampleRate(SNDDEV_GET_NUMBER(dev), samplerates, supportedRates); - if(justCreated) + if(dummy != nullptr) { - delete dummy; + // Now we can query the supported sample rates. + samplerates = dummy->GetSampleRates(samplerates); + if(justCreated) + { + delete dummy; + } } } - } - if(!knowRates) + if(samplerates.empty()) { // We have no valid list of supported playback rates! Assume all rates supported by OpenMPT are possible... - supportedRates.assign(samplerates.size(), true); + samplerates = TrackerSettings::Instance().GetSampleRates(); } - int n = 1; + + int n = 0; for(size_t i = 0; i < samplerates.size(); i++) { - if(supportedRates[i]) - { - wsprintf(s, "%i Hz", samplerates[i]); - int pos = m_CbnMixingFreq.AddString(s); - m_CbnMixingFreq.SetItemData(pos, samplerates[i]); - if(m_dwRate == samplerates[i]) n = pos; - } + CHAR s[16]; + wsprintf(s, "%i Hz", samplerates[i]); + int pos = m_CbnMixingFreq.AddString(s); + m_CbnMixingFreq.SetItemData(pos, samplerates[i]); + if(m_dwRate == samplerates[i]) n = pos; } m_CbnMixingFreq.SetCurSel(n); } Modified: trunk/OpenMPT/mptrack/Mptrack.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mptrack.cpp 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/mptrack/Mptrack.cpp 2013-09-28 17:58:40 UTC (rev 2789) @@ -620,6 +620,7 @@ m_bPortableMode = false; m_pModTemplate = NULL; m_pPluginManager = NULL; + m_pSoundDevicesManager = nullptr; m_bInitialized = FALSE; m_szConfigFileName[0] = 0; } @@ -862,7 +863,7 @@ //RegisterExtensions(); // Load sound APIs - SndDevInitialize(); + m_pSoundDevicesManager = new SoundDevicesManager(); // Load DLS Banks if (!cmdInfo.m_bNoDls) LoadDefaultDLSBanks(); @@ -916,7 +917,8 @@ int CTrackApp::ExitInstance() //--------------------------- { - SndDevUninitialize(); + delete m_pSoundDevicesManager; + m_pSoundDevicesManager = nullptr; if (glpMidiLibrary) { if (m_szConfigFileName[0]) ExportMidiConfig(m_szConfigFileName); Modified: trunk/OpenMPT/mptrack/Mptrack.h =================================================================== --- trunk/OpenMPT/mptrack/Mptrack.h 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/mptrack/Mptrack.h 2013-09-28 17:58:40 UTC (rev 2789) @@ -20,6 +20,7 @@ class CModDoc; class CVstPluginManager; +class SoundDevicesManager; class CDLSBank; ///////////////////////////////////////////////////////////////////////////// @@ -111,6 +112,7 @@ protected: CMultiDocTemplate *m_pModTemplate; CVstPluginManager *m_pPluginManager; + SoundDevicesManager *m_pSoundDevicesManager; BOOL m_bInitialized; DWORD m_dwTimeStarted, m_dwLastPluginIdleCall; // Default macro configuration @@ -155,6 +157,7 @@ public: CDocTemplate *GetModDocTemplate() const { return m_pModTemplate; } CVstPluginManager *GetPluginManager() const { return m_pPluginManager; } + SoundDevicesManager *GetSoundDevicesManager() const { return m_pSoundDevicesManager; } void GetDefaultMidiMacro(MIDIMacroConfig &cfg) const { cfg = m_MidiCfg; } void SetDefaultMidiMacro(const MIDIMacroConfig &cfg) { m_MidiCfg = cfg; } LPCTSTR GetConfigFileName() const { return m_szConfigFileName; } Modified: trunk/OpenMPT/mptrack/Notification.h =================================================================== --- trunk/OpenMPT/mptrack/Notification.h 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/mptrack/Notification.h 2013-09-28 17:58:40 UTC (rev 2789) @@ -33,13 +33,6 @@ static const SmpLength PosInvalid = SmpLength(-1); // pos[i] is not valid (if it contains sample or envelope position) static const uint32 ClipVU = 0x80000000; // Master VU clip indicator bit (sound output has previously clipped) - /* - timestampSamples is kind of confusing at the moment: - If gpSoundDevice->HasGetStreamPosition(), - then it contains the sample timestamp as when it was generated and the output stream is later queried when this exact timestamp has actually reached the speakers. - If !gpSoundDevice->HasGetStreamPosition(), - then it contains a sample timestamp in the future, incremented by the current latency estimation of the sound buffers. It is later checked against the total number of rendered samples at that time. - */ int64 timestampSamples; FlagSet<Type, uint16> type; Item item; // Sample or instrument number, depending on type Modified: trunk/OpenMPT/mptrack/TrackerSettings.cpp =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-09-28 17:58:40 UTC (rev 2789) @@ -334,11 +334,6 @@ m_MorePortaudio = CMainFrame::GetPrivateProfileBool("Sound Settings", "MorePortaudio", m_MorePortaudio, iniFile); DWORD defaultDevice = SNDDEV_BUILD_ID(0, SNDDEV_WAVEOUT); // first WaveOut device #ifndef NO_ASIO - // If there's an ASIO device available, prefer it over DirectSound - if(EnumerateSoundDevices(SNDDEV_ASIO, 0, nullptr, 0)) - { - defaultDevice = SNDDEV_BUILD_ID(0, SNDDEV_ASIO); - } CASIODevice::baseChannel = GetPrivateProfileInt("Sound Settings", "ASIOBaseChannel", CASIODevice::baseChannel, iniFile); #endif // NO_ASIO m_nWaveDevice = CMainFrame::GetPrivateProfileLong("Sound Settings", "WaveDevice", defaultDevice, iniFile); @@ -389,22 +384,6 @@ m_LatencyMS = LatencyMS; m_UpdateIntervalMS = UpdateIntervalMS; } - if(m_MixerSettings.gdwMixingFreq == 0) - { - m_MixerSettings.gdwMixingFreq = 44100; -#ifndef NO_ASIO - // If no mixing rate is specified and we're using ASIO, get a mixing rate supported by the device. - if(SNDDEV_GET_TYPE(m_nWaveDevice) == SNDDEV_ASIO) - { - ISoundDevice *dummy = CreateSoundDevice(SNDDEV_ASIO); - if(dummy) - { - m_MixerSettings.gdwMixingFreq = dummy->GetCurrentSampleRate(SNDDEV_GET_NUMBER(m_nWaveDevice)); - delete dummy; - } - } -#endif // NO_ASIO - } m_MixerSettings.m_nPreAmp = CMainFrame::GetPrivateProfileDWord("Sound Settings", "PreAmp", m_MixerSettings.m_nPreAmp, iniFile); m_MixerSettings.m_nStereoSeparation = CMainFrame::GetPrivateProfileLong("Sound Settings", "StereoSeparation", m_MixerSettings.m_nStereoSeparation, iniFile); Modified: trunk/OpenMPT/sounddev/SoundDevice.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDevice.cpp 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/sounddev/SoundDevice.cpp 2013-09-28 17:58:40 UTC (rev 2789) @@ -22,7 +22,10 @@ #include "SoundDevicePortAudio.h" #include "SoundDeviceWaveout.h" +#include <algorithm> +#include <iterator> + /////////////////////////////////////////////////////////////////////////////////////// // // ISoundDevice base class @@ -33,10 +36,13 @@ { m_Source = nullptr; + m_Index = 0; + m_RealLatencyMS = static_cast<float>(m_Settings.LatencyMS); m_RealUpdateIntervalMS = static_cast<float>(m_Settings.UpdateIntervalMS); m_IsPlaying = false; + m_SamplesRendered = 0; } @@ -47,6 +53,14 @@ } +void ISoundDevice::SetDevice(UINT index, const std::wstring &internalID) +//---------------------------------------------------------------------- +{ + m_Index = index; + m_InternalID = internalID; +} + + bool ISoundDevice::FillWaveFormatExtensible(WAVEFORMATEXTENSIBLE &WaveFormat) //--------------------------------------------------------------------------- { @@ -81,8 +95,8 @@ } -bool ISoundDevice::Open(UINT device, const SoundDeviceSettings &settings) -//----------------------------------------------------------------------- +bool ISoundDevice::Open(const SoundDeviceSettings &settings) +//---------------------------------------------------------- { m_Settings = settings; if(m_Settings.LatencyMS < SNDDEV_MINLATENCY_MS) m_Settings.LatencyMS = SNDDEV_MINLATENCY_MS; @@ -91,7 +105,7 @@ if(m_Settings.UpdateIntervalMS > SNDDEV_MAXUPDATEINTERVAL_MS) m_Settings.UpdateIntervalMS = SNDDEV_MAXUPDATEINTERVAL_MS; m_RealLatencyMS = static_cast<float>(m_Settings.LatencyMS); m_RealUpdateIntervalMS = static_cast<float>(m_Settings.UpdateIntervalMS); - return InternalOpen(device); + return InternalOpen(); } @@ -115,19 +129,33 @@ void ISoundDevice::SourceAudioRead(void* pData, ULONG NumSamples) //--------------------------------------------------------------- { - m_Source->AudioRead(pData, NumSamples); + if(NumSamples <= 0) + { + return; + } + m_Source->AudioRead(pData, NumSamples, m_Settings.sampleFormat); } void ISoundDevice::SourceAudioDone(ULONG NumSamples, ULONG SamplesLatency) //------------------------------------------------------------------------ { - if(HasGetStreamPosition()) + if(NumSamples <= 0) { - m_Source->AudioDone(NumSamples); + return; + } + int64 samplesRendered = 0; + { + Util::lock_guard<Util::mutex> lock(m_SamplesRenderedMutex); + m_SamplesRendered += NumSamples; + samplesRendered = m_SamplesRendered; + } + if(InternalHasGetStreamPosition()) + { + m_Source->AudioDone(NumSamples, samplesRendered); } else { - m_Source->AudioDone(NumSamples, SamplesLatency); + m_Source->AudioDone(NumSamples, samplesRendered + SamplesLatency); } } @@ -138,6 +166,10 @@ if(!IsOpen()) return; if(!IsPlaying()) { + { + Util::lock_guard<Util::mutex> lock(m_SamplesRenderedMutex); + m_SamplesRendered = 0; + } InternalStart(); m_IsPlaying = true; } @@ -152,6 +184,10 @@ { InternalStop(); m_IsPlaying = false; + { + Util::lock_guard<Util::mutex> lock(m_SamplesRenderedMutex); + m_SamplesRendered = 0; + } } } @@ -165,6 +201,20 @@ } +int64 ISoundDevice::GetStreamPositionSamples() const +//-------------------------------------------------- +{ + if(InternalHasGetStreamPosition()) + { + return InternalGetStreamPositionSamples(); + } else + { + Util::lock_guard<Util::mutex> lock(m_SamplesRenderedMutex); + return m_SamplesRendered; + } +} + + CAudioThread::CAudioThread(CSoundDeviceWithThread &SoundDevice) : m_SoundDevice(SoundDevice) //----------------------------------------------------------------------------------- { @@ -564,43 +614,79 @@ // -BOOL EnumerateSoundDevices(UINT nType, UINT nIndex, LPSTR pszDesc, UINT cbSize) -//----------------------------------------------------------------------------- +void SoundDevicesManager::ReEnumerate() +//------------------------------------- { - switch(nType) + m_SoundDevices.clear(); + for(int type = 0; type < SNDDEV_NUM_DEVTYPES; ++type) { - case SNDDEV_WAVEOUT: return CWaveDevice::EnumerateDevices(nIndex, pszDesc, cbSize); + std::vector<SoundDeviceInfo> infos; + switch(type) + { + + case SNDDEV_WAVEOUT: + infos = CWaveDevice::EnumerateDevices(); + break; + #ifndef NO_DSOUND - case SNDDEV_DSOUND: return CDSoundDevice::EnumerateDevices(nIndex, pszDesc, cbSize); -#endif // NO_DIRECTSOUND + case SNDDEV_DSOUND: + infos = CDSoundDevice::EnumerateDevices(); + break; +#endif // NO_DSOUND + #ifndef NO_ASIO - case SNDDEV_ASIO: return CASIODevice::EnumerateDevices(nIndex, pszDesc, cbSize); + case SNDDEV_ASIO: + infos = CASIODevice::EnumerateDevices(); + break; #endif // NO_ASIO + #ifndef NO_PORTAUDIO - case SNDDEV_PORTAUDIO_WASAPI: - case SNDDEV_PORTAUDIO_WDMKS: - case SNDDEV_PORTAUDIO_WMME: - case SNDDEV_PORTAUDIO_DS: - case SNDDEV_PORTAUDIO_ASIO: - return SndDevPortaudioIsInitialized() ? CPortaudioDevice::EnumerateDevices(nIndex, pszDesc, cbSize, CPortaudioDevice::SndDevTypeToHostApi(nType)) : FALSE; - break; -#endif + case SNDDEV_PORTAUDIO_WASAPI: + case SNDDEV_PORTAUDIO_WDMKS: + case SNDDEV_PORTAUDIO_WMME: + case SNDDEV_PORTAUDIO_DS: + case SNDDEV_PORTAUDIO_ASIO: + infos = CPortaudioDevice::EnumerateDevices(type); + break; +#endif // NO_PORTAUDIO + + } + std::copy(infos.begin(), infos.end(), std::back_inserter(m_SoundDevices)); } - return FALSE; } -ISoundDevice *CreateSoundDevice(UINT nType) -//----------------------------------------- +const SoundDeviceInfo * SoundDevicesManager::FindDeviceInfo(UINT type, UINT index) const +//-------------------------------------------------------------------------------------- { - switch(nType) + for(std::vector<SoundDeviceInfo>::const_iterator it = begin(); it != end(); ++it) { - case SNDDEV_WAVEOUT: return new CWaveDevice(); break; + if(it->type == type && it->index == index) + { + return &(*it); + } + } + return nullptr; +} + + +ISoundDevice * SoundDevicesManager::CreateSoundDevice(UINT type, UINT index) +//-------------------------------------------------------------------------- +{ + const SoundDeviceInfo *info = FindDeviceInfo(type, index); + if(!info) + { + return nullptr; + } + ISoundDevice *result = nullptr; + switch(type) + { + case SNDDEV_WAVEOUT: result = new CWaveDevice(); break; #ifndef NO_DSOUND - case SNDDEV_DSOUND: return new CDSoundDevice(); break; -#endif // NO_DIRECTSOUND + case SNDDEV_DSOUND: result = new CDSoundDevice(); break; +#endif // NO_DSOUND #ifndef NO_ASIO - case SNDDEV_ASIO: return new CASIODevice(); break; + case SNDDEV_ASIO: result = new CASIODevice(); break; #endif // NO_ASIO #ifndef NO_PORTAUDIO case SNDDEV_PORTAUDIO_WASAPI: @@ -608,35 +694,32 @@ case SNDDEV_PORTAUDIO_WMME: case SNDDEV_PORTAUDIO_DS: case SNDDEV_PORTAUDIO_ASIO: - return SndDevPortaudioIsInitialized() ? new CPortaudioDevice(CPortaudioDevice::SndDevTypeToHostApi(nType)) : nullptr; + result = SndDevPortaudioIsInitialized() ? new CPortaudioDevice(CPortaudioDevice::SndDevTypeToHostApi(type)) : nullptr; break; -#endif +#endif // NO_PORTAUDIO } - return nullptr; + if(result) + { + result->SetDevice(index, info->internalID); + } + return result; } -BOOL SndDevInitialize() -//--------------------- +SoundDevicesManager::SoundDevicesManager() +//---------------------------------------- { -#ifndef NO_DSOUND - SndDevDSoundInitialize(); -#endif // NO_DSOUND #ifndef NO_PORTAUDIO SndDevPortaudioInitialize(); #endif // NO_PORTAUDIO - return TRUE; + ReEnumerate(); } -BOOL SndDevUninitialize() -//----------------------- +SoundDevicesManager::~SoundDevicesManager() +//----------------------------------------- { #ifndef NO_PORTAUDIO SndDevPortaudioUnnitialize(); #endif // NO_PORTAUDIO -#ifndef NO_DSOUND - SndDevDSoundUninitialize(); -#endif // NO_DSOUND - return TRUE; } Modified: trunk/OpenMPT/sounddev/SoundDevice.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDevice.h 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/sounddev/SoundDevice.h 2013-09-28 17:58:40 UTC (rev 2789) @@ -11,6 +11,7 @@ #pragma once +#include "../common/mutex.h" #include "../soundlib/SampleFormat.h" #include <vector> @@ -42,9 +43,8 @@ { public: virtual void FillAudioBufferLocked(IFillAudioBuffer &callback) = 0; // take any locks needed while rendering audio and then call FillAudioBuffer - virtual void AudioRead(void* pData, ULONG NumSamples) = 0; - virtual void AudioDone(ULONG NumSamples, ULONG SamplesLatency) = 0; // all in samples - virtual void AudioDone(ULONG NumSamples) = 0; // all in samples + virtual void AudioRead(void* pData, ULONG NumSamples, SampleFormat sampleFormat) = 0; + virtual void AudioDone(ULONG NumSamples, int64 streamPosition) = 0; // in samples }; @@ -110,15 +110,23 @@ }; +class SoundDevicesManager; + + //============================================= class ISoundDevice : protected IFillAudioBuffer //============================================= { + friend class SoundDevicesManager; + private: ISoundSource *m_Source; protected: + UINT m_Index; + std::wstring m_InternalID; + SoundDeviceSettings m_Settings; float m_RealLatencyMS; @@ -126,6 +134,9 @@ bool m_IsPlaying; + mutable Util::mutex m_SamplesRenderedMutex; + int64 m_SamplesRendered; + protected: virtual void FillAudioBuffer() = 0; void SourceFillAudioBufferLocked(); @@ -137,7 +148,14 @@ virtual ~ISoundDevice(); void SetSource(ISoundSource *source) { m_Source = source; } ISoundSource *GetSource() const { return m_Source; } +protected: + void SetDevice(UINT index, const std::wstring &internalID); +public: + UINT GetDeviceIndex() const { return m_Index; } + UINT GetDeviceID() const { return SNDDEV_BUILD_ID(GetDeviceIndex(), GetDeviceType()); } + std::wstring GetDeviceInternalID() const { return m_InternalID; } + public: float GetRealLatencyMS() const { return m_RealLatencyMS; } float GetRealUpdateIntervalMS() const { return m_RealUpdateIntervalMS; } @@ -147,42 +165,78 @@ bool FillWaveFormatExtensible(WAVEFORMATEXTENSIBLE &WaveFormat); protected: - virtual bool InternalOpen(UINT nDevice) = 0; + virtual bool InternalOpen() = 0; virtual void InternalStart() = 0; virtual void InternalStop() = 0; virtual void InternalReset() = 0; virtual bool InternalClose() = 0; + virtual bool InternalHasGetStreamPosition() const { return false; } + virtual int64 InternalGetStreamPositionSamples() const { return 0; } public: - virtual UINT GetDeviceType() = 0; - bool Open(UINT nDevice, const SoundDeviceSettings &settings); // Open a device + virtual UINT GetDeviceType() const = 0; + bool Open(const SoundDeviceSettings &settings); // Open a device bool Close(); // Close the currently open device void Start(); void Stop(); void Reset(); - virtual SampleFormat HasFixedSampleFormat() { return SampleFormatInvalid; } + int64 GetStreamPositionSamples() const; + SampleFormat GetActualSampleFormat() { return IsOpen() ? m_Settings.sampleFormat : SampleFormatInvalid; } virtual bool IsOpen() const = 0; virtual UINT GetNumBuffers() { return 0; } virtual float GetCurrentRealLatencyMS() { return GetRealLatencyMS(); } - virtual bool HasGetStreamPosition() const { return false; } - virtual int64 GetStreamPositionSamples() const { return 0; } - virtual UINT GetCurrentSampleRate(UINT nDevice) { UNREFERENCED_PARAMETER(nDevice); return 0; } - // Return which samplerates are actually supported by the device. Currently only implemented properly for ASIO. - virtual bool CanSampleRate(UINT nDevice, const std::vector<uint32> &samplerates, std::vector<bool> &result) { UNREFERENCED_PARAMETER(nDevice); result.assign(samplerates.size(), true); return true; } ; + virtual UINT GetCurrentSampleRate() { return 0; } + // Return which samplerates are actually supported by the device. Currently only implemented properly for ASIO and PortAudio. + virtual std::vector<uint32> GetSampleRates(const std::vector<uint32> &samplerates) { return samplerates; } }; -//////////////////////////////////////////////////////////////////////////////////// -// -// Global Functions -// +struct SoundDeviceInfo +{ + UINT type; + UINT index; + std::wstring name; + std::wstring internalID; + SoundDeviceInfo() + : type(0) + , index(0) + { + return; + } + SoundDeviceInfo(UINT type, UINT index, const std::wstring &name, const std::wstring &id = std::wstring()) + : type(type) + , index(index) + , name(name) + , internalID(id) + { + return; + } +}; -// Initialization -BOOL SndDevInitialize(); -BOOL SndDevUninitialize(); -// Enumerate devices for a specific type -BOOL EnumerateSoundDevices(UINT nType, UINT nIndex, LPSTR pszDescription, UINT cbSize); -ISoundDevice *CreateSoundDevice(UINT nType); +//======================= +class SoundDevicesManager +//======================= +{ +private: + std::vector<SoundDeviceInfo> m_SoundDevices; -//////////////////////////////////////////////////////////////////////////////////// +public: + SoundDevicesManager(); + ~SoundDevicesManager(); + +public: + + void ReEnumerate(); + + std::vector<SoundDeviceInfo>::const_iterator begin() const { return m_SoundDevices.begin(); } + std::vector<SoundDeviceInfo>::const_iterator end() const { return m_SoundDevices.end(); } + const std::vector<SoundDeviceInfo> & GetDeviceInfos() const { return m_SoundDevices; } + + const SoundDeviceInfo * FindDeviceInfo(UINT type, UINT index) const; + const SoundDeviceInfo * FindDeviceInfo(UINT id) const { return FindDeviceInfo(SNDDEV_GET_TYPE(id), SNDDEV_GET_NUMBER(id)); } + + ISoundDevice * CreateSoundDevice(UINT type, UINT index); + ISoundDevice * CreateSoundDevice(UINT id) { return CreateSoundDevice(SNDDEV_GET_TYPE(id), SNDDEV_GET_NUMBER(id)); } + +}; Modified: trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2013-09-28 17:58:40 UTC (rev 2789) @@ -36,91 +36,123 @@ #ifndef NO_ASIO -#define ASIO_MAX_DRIVERS 8 -#define ASIO_MAXDRVNAMELEN 128 +#define ASIO_MAXDRVNAMELEN 1024 -typedef struct _ASIODRIVERDESC -{ - CLSID clsid; - CHAR name[80]; -} ASIODRIVERDESC; - CASIODevice *CASIODevice::gpCurrentAsio = NULL; LONG CASIODevice::gnFillBuffers = 0; int CASIODevice::baseChannel = 0; -static UINT gnNumAsioDrivers = 0; -static BOOL gbAsioEnumerated = FALSE; -static ASIODRIVERDESC gAsioDrivers[ASIO_MAX_DRIVERS]; static DWORD g_dwBuffer = 0; static int g_asio_startcount = 0; -BOOL CASIODevice::EnumerateDevices(UINT nIndex, LPSTR pszDescription, UINT cbSize) -//-------------------------------------------------------------------------------- +static std::wstring CLSIDToString(CLSID clsid) +//-------------------------------------------- { - if (!gbAsioEnumerated) + std::wstring str; + LPOLESTR tmp = nullptr; + StringFromCLSID(clsid, &tmp); + if(tmp) { - HKEY hkEnum = NULL; + str = tmp; + CoTaskMemFree(tmp); + tmp = nullptr; + } + return str; +} + + +static CLSID StringToCLSID(const std::wstring &str) +//------------------------------------------------- +{ + CLSID clsid = CLSID(); + std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1); + CLSIDFromString(&tmp[0], &clsid); + return clsid; +} + + +static bool IsCLSID(const std::wstring &str) +{ + CLSID clsid = CLSID(); + std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1); + return CLSIDFromString(&tmp[0], &clsid) == S_OK; +} + + +std::vector<SoundDeviceInfo> CASIODevice::EnumerateDevices() +//----------------------------------------------------------- +{ + std::vector<SoundDeviceInfo> devices; + + LONG cr; + + HKEY hkEnum = NULL; + cr = RegOpenKey(HKEY_LOCAL_MACHINE, "software\\asio", &hkEnum); + + for(DWORD index = 0; ; ++index) + { + CHAR keyname[ASIO_MAXDRVNAMELEN]; - CHAR s[256]; - WCHAR w[100]; - LONG cr; - DWORD index; + if((cr = RegEnumKey(hkEnum, index, keyname, ASIO_MAXDRVNAMELEN)) != ERROR_SUCCESS) + { + break; + } + #ifdef ASIO_LOG + Log("ASIO: Found \"%s\":\n", keyname); + #endif - cr = RegOpenKey(HKEY_LOCAL_MACHINE, "software\\asio", &hkEnum); - index = 0; - while ((cr == ERROR_SUCCESS) && (gnNumAsioDrivers < ASIO_MAX_DRIVERS)) + HKEY hksub = NULL; + if(RegOpenKeyEx(hkEnum, keyname, 0, KEY_READ, &hksub) != ERROR_SUCCESS) { - if ((cr = RegEnumKey(hkEnum, index, (LPTSTR)keyname, ASIO_MAXDRVNAMELEN)) == ERROR_SUCCESS) + continue; + } + + CHAR description[ASIO_MAXDRVNAMELEN]; + DWORD datatype = REG_SZ; + DWORD datasize = sizeof(description); + if(ERROR_SUCCESS == RegQueryValueEx(hksub, "description", 0, &datatype, (LPBYTE)description, &datasize)) + { + #ifdef ASIO_LOG + Log(" description =\"%s\":\n", description); + #endif + } else + { + mpt::String::Copy(description, keyname); + } + + CHAR s[256]; + datatype = REG_SZ; + datasize = sizeof(s); + if(ERROR_SUCCESS == RegQueryValueEx(hksub, "clsid", 0, &datatype, (LPBYTE)s, &datasize)) + { + const std::wstring internalID = mpt::String::Decode(s, mpt::CharsetLocale); + if(IsCLSID(internalID)) { - #ifdef ASIO_LOG - Log("ASIO: Found \"%s\":\n", keyname); - #endif - HKEY hksub; + CLSID clsid = StringToCLSID(internalID); + #ifdef ASIO_LOG + Log(" clsid=\"%s\"\n", s); + #endif - if ((RegOpenKeyEx(hkEnum, (LPCTSTR)keyname, 0, KEY_READ, &hksub)) == ERROR_SUCCESS) - { - DWORD datatype = REG_SZ; - DWORD datasize = 64; - - if (ERROR_SUCCESS == RegQueryValueEx(hksub, "description", 0, &datatype, (LPBYTE)gAsioDrivers[gnNumAsioDrivers].name, &datasize)) - { - #ifdef ASIO_LOG - Log(" description =\"%s\":\n", gAsioDrivers[gnNumAsioDrivers].name); - #endif - } else - { - lstrcpyn(gAsioDrivers[gnNumAsioDrivers].name, keyname, 64); - } - datatype = REG_SZ; - datasize = sizeof(s); - if (ERROR_SUCCESS == RegQueryValueEx(hksub, "clsid", 0, &datatype, (LPBYTE)s, &datasize)) - { - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)s,-1,(LPWSTR)w,100); - if (CLSIDFromString((LPOLESTR)w, (LPCLSID)&gAsioDrivers[gnNumAsioDrivers].clsid) == S_OK) - { - #ifdef ASIO_LOG - Log(" clsid=\"%s\"\n", s); - #endif - gnNumAsioDrivers++; - } - } - RegCloseKey(hksub); - } + // everything ok + devices.push_back(SoundDeviceInfo(SNDDEV_ASIO, devices.size(), mpt::String::Decode(description, mpt::CharsetLocale), internalID)); + } - index++; } - if (hkEnum) RegCloseKey(hkEnum); - gbAsioEnumerated = TRUE; + + RegCloseKey(hksub); + hksub = NULL; + } - if (nIndex < gnNumAsioDrivers) + + if(hkEnum) { - if (pszDescription) lstrcpyn(pszDescription, gAsioDrivers[nIndex].name, cbSize); - return TRUE; + RegCloseKey(hkEnum); + hkEnum = NULL; } - return FALSE; + + return devices; } @@ -128,7 +160,6 @@ //------------------------ { m_pAsioDrv = NULL; - m_nChannels = 0; m_nAsioBufferLen = 0; m_nAsioSampleSize = 0; m_Float = false; @@ -136,7 +167,6 @@ m_Callbacks.sampleRateDidChange = SampleRateDidChange; m_Callbacks.asioMessage = AsioMessage; m_Callbacks.bufferSwitchTimeInfo = BufferSwitchTimeInfo; - m_nCurrentDevice = (ULONG)-1; m_bMixRunning = FALSE; InterlockedExchange(&m_RenderSilence, 0); InterlockedExchange(&m_RenderingSilence, 0); @@ -151,23 +181,18 @@ } -bool CASIODevice::InternalOpen(UINT nDevice) -//------------------------------------------ +bool CASIODevice::InternalOpen() +//------------------------------ { + bool bOk = false; if (IsOpen()) Close(); - if (!gbAsioEnumerated) EnumerateDevices(nDevice, NULL, 0); - if (nDevice >= gnNumAsioDrivers) return false; - if (nDevice != m_nCurrentDevice) - { - m_nCurrentDevice = nDevice; - } #ifdef ASIO_LOG Log("CASIODevice::Open(%d:\"%s\"): %d-bit, %d channels, %dHz\n", - nDevice, gAsioDrivers[nDevice].name, (int)m_Settings.sampleFormat.GetBitsPerSample(), m_Settings.Channels, m_Settings.Samplerate); + GetDeviceIndex(), mpt::String::Encode(GetDeviceInternalID(), mpt::CharsetLocale).c_str(), (int)m_Settings.sampleFormat.GetBitsPerSample(), m_Settings.Channels, m_Settings.Samplerate); #endif - OpenDevice(nDevice); + OpenDevice(); if (IsOpen()) { @@ -178,11 +203,6 @@ { goto abort; } - if((m_Settings.sampleFormat != SampleFormatInt32) && (m_Settings.sampleFormat != SampleFormatFloat32)) - { - goto abort; - } - m_nChannels = m_Settings.Channels; m_pAsioDrv->getChannels(&nInputChannels, &nOutputChannels); #ifdef ASIO_LOG Log(" getChannels: %d inputs, %d outputs\n", nInputChannels, nOutputChannels); @@ -249,6 +269,7 @@ break; } } + m_Settings.sampleFormat = m_Float ? SampleFormatFloat32 : SampleFormatInt32; m_pAsioDrv->getBufferSize(&minSize, &maxSize, &preferredSize, &granularity); #ifdef ASIO_LOG Log(" getBufferSize(): minSize=%d maxSize=%d preferredSize=%d granularity=%d\n", @@ -287,9 +308,9 @@ #ifdef ASIO_LOG Log(" Using buffersize=%d samples\n", m_nAsioBufferLen); #endif - if (m_pAsioDrv->createBuffers(m_BufferInfo, m_nChannels, m_nAsioBufferLen, &m_Callbacks) == ASE_OK) + if (m_pAsioDrv->createBuffers(m_BufferInfo, m_Settings.Channels, m_nAsioBufferLen, &m_Callbacks) == ASE_OK) { - for (UINT iInit=0; iInit<m_nChannels; iInit++) + for (UINT iInit=0; iInit<m_Settings.Channels; iInit++) { if (m_BufferInfo[iInit].buffers[0]) { @@ -462,15 +483,15 @@ } -void CASIODevice::OpenDevice(UINT nDevice) -//---------------------------------------- +void CASIODevice::OpenDevice() +//---------------------------- { if (IsOpen()) { return; } - CLSID clsid = gAsioDrivers[nDevice].clsid; + CLSID clsid = StringToCLSID(GetDeviceInternalID()); if (CoCreateInstance(clsid,0,CLSCTX_INPROC_SERVER, clsid, (void **)&m_pAsioDrv) == S_OK) { m_pAsioDrv->init((void *)m_Settings.hWnd); @@ -517,7 +538,8 @@ { bool rendersilence = (InterlockedExchangeAdd(&m_RenderSilence, 0) == 1); - std::size_t sampleFrameSize = m_nChannels * sizeof(int32); + const int channels = m_Settings.Channels; + std::size_t sampleFrameSize = channels * sizeof(int32); const std::size_t sampleFramesGoal = m_nAsioBufferLen; std::size_t sampleFramesToRender = sampleFramesGoal; std::size_t sampleFramesRendered = 0; @@ -535,7 +557,7 @@ { SourceAudioRead(m_FrameBuffer, countChunk); } - for(int channel = 0; channel < (int)m_nChannels; ++channel) + for(int channel = 0; channel < channels; ++channel) { const int32 *src = m_FrameBuffer; const float *srcFloat = reinterpret_cast<const float*>(m_FrameBuffer); @@ -544,11 +566,11 @@ { case ASIOSTFloat32MSB: case ASIOSTFloat32LSB: - CopyInterleavedToChannel<SC::Convert<float, float> >(reinterpret_cast<float*>(dst), srcFloat, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::Convert<float, float> >(reinterpret_cast<float*>(dst), srcFloat, channels, countChunk, channel); break; case ASIOSTFloat64MSB: case ASIOSTFloat64LSB: - CopyInterleavedToChannel<SC::Convert<double, float> >(reinterpret_cast<double*>(dst), srcFloat, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::Convert<double, float> >(reinterpret_cast<double*>(dst), srcFloat, channels, countChunk, channel); break; default: ASSERT(false); @@ -557,39 +579,39 @@ { case ASIOSTInt16MSB: case ASIOSTInt16LSB: - CopyInterleavedToChannel<SC::Convert<int16, int32> >(reinterpret_cast<int16*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::Convert<int16, int32> >(reinterpret_cast<int16*>(dst), src, channels, countChunk, channel); break; case ASIOSTInt24MSB: case ASIOSTInt24LSB: - CopyInterleavedToChannel<SC::Convert<int24, int32> >(reinterpret_cast<int24*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::Convert<int24, int32> >(reinterpret_cast<int24*>(dst), src, channels, countChunk, channel); break; case ASIOSTInt32MSB: case ASIOSTInt32LSB: - CopyInterleavedToChannel<SC::Convert<int32, int32> >(reinterpret_cast<int32*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::Convert<int32, int32> >(reinterpret_cast<int32*>(dst), src, channels, countChunk, channel); break; case ASIOSTFloat32MSB: case ASIOSTFloat32LSB: - CopyInterleavedToChannel<SC::Convert<float, int32> >(reinterpret_cast<float*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::Convert<float, int32> >(reinterpret_cast<float*>(dst), src, channels, countChunk, channel); break; case ASIOSTFloat64MSB: case ASIOSTFloat64LSB: - CopyInterleavedToChannel<SC::Convert<double, int32> >(reinterpret_cast<double*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::Convert<double, int32> >(reinterpret_cast<double*>(dst), src, channels, countChunk, channel); break; case ASIOSTInt32MSB16: case ASIOSTInt32LSB16: - CopyInterleavedToChannel<SC::ConvertShift<int32, int32, 16> >(reinterpret_cast<int32*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::ConvertShift<int32, int32, 16> >(reinterpret_cast<int32*>(dst), src, channels, countChunk, channel); break; case ASIOSTInt32MSB18: case ASIOSTInt32LSB18: - CopyInterleavedToChannel<SC::ConvertShift<int32, int32, 14> >(reinterpret_cast<int32*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::ConvertShift<int32, int32, 14> >(reinterpret_cast<int32*>(dst), src, channels, countChunk, channel); break; case ASIOSTInt32MSB20: case ASIOSTInt32LSB20: - CopyInterleavedToChannel<SC::ConvertShift<int32, int32, 12> >(reinterpret_cast<int32*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::ConvertShift<int32, int32, 12> >(reinterpret_cast<int32*>(dst), src, channels, countChunk, channel); break; case ASIOSTInt32MSB24: case ASIOSTInt32LSB24: - CopyInterleavedToChannel<SC::ConvertShift<int32, int32, 8> >(reinterpret_cast<int32*>(dst), src, m_nChannels, countChunk, channel); + CopyInterleavedToChannel<SC::ConvertShift<int32, int32, 8> >(reinterpret_cast<int32*>(dst), src, channels, countChunk, channel); break; default: ASSERT(false); @@ -702,27 +724,25 @@ } -bool CASIODevice::CanSampleRate(UINT nDevice, const std::vector<uint32> &samplerates, std::vector<bool> &result) -//-------------------------------------------------------------------------------------------------------------- +std::vector<uint32> CASIODevice::GetSampleRates(const std::vector<uint32> &samplerates) +//------------------------------------------------------------------------------------- { + std::vector<uint32> results; const bool wasOpen = (m_pAsioDrv != NULL); if(!wasOpen) { - OpenDevice(nDevice); + OpenDevice(); if(m_pAsioDrv == NULL) { - return false; + return results; } } - bool foundSomething = false; // is at least one sample rate supported by the device? - result.clear(); for(size_t i = 0; i < samplerates.size(); i++) { - result.push_back((m_pAsioDrv->canSampleRate((ASIOSampleRate)samplerates[i]) == ASE_OK)); - if(result.back()) + if(m_pAsioDrv->canSampleRate((ASIOSampleRate)samplerates[i]) == ASE_OK) { - foundSomething = true; + results.push_back(samplerates[i]); } } @@ -731,18 +751,18 @@ CloseDevice(); } - return foundSomething; + return results; } // If the device is open, this returns the current sample rate. If it's not open, it returns some sample rate supported by the device. -UINT CASIODevice::GetCurrentSampleRate(UINT nDevice) -//-------------------------------------------------- +UINT CASIODevice::GetCurrentSampleRate() +//-------------------------------------- { const bool wasOpen = (m_pAsioDrv != NULL); if(!wasOpen) { - OpenDevice(nDevice); + OpenDevice(); if(m_pAsioDrv == NULL) { return 0; Modified: trunk/OpenMPT/sounddev/SoundDeviceASIO.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceASIO.h 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/sounddev/SoundDeviceASIO.h 2013-09-28 17:58:40 UTC (rev 2789) @@ -33,11 +33,11 @@ enum { ASIO_BLOCK_LEN=1024 }; protected: IASIO *m_pAsioDrv; - UINT m_nChannels, m_nAsioBufferLen, m_nAsioSampleSize; + UINT m_nAsioBufferLen; + UINT m_nAsioSampleSize; bool m_Float; BOOL m_bMixRunning; BOOL m_bPostOutput; - UINT m_nCurrentDevice; LONG m_RenderSilence; LONG m_RenderingSilence; ASIOCallbacks m_Callbacks; @@ -56,26 +56,25 @@ ~CASIODevice(); public: - UINT GetDeviceType() { return SNDDEV_ASIO; } - bool InternalOpen(UINT nDevice); + UINT GetDeviceType() const { return SNDDEV_ASIO; } + bool InternalOpen(); bool InternalClose(); void FillAudioBuffer(); void InternalReset(); void InternalStart(); void InternalStop(); bool IsOpen() const { return (m_pAsioDrv != NULL); } - SampleFormat HasFixedSampleFormat() { return m_Float ? SampleFormatFloat32 : SampleFormatInt32; } UINT GetNumBuffers() { return 2; } float GetCurrentRealLatencyMS() { return m_nAsioBufferLen * 2 * 1000.0f / m_Settings.Samplerate; } - bool CanSampleRate(UINT nDevice, const std::vector<uint32> &samplerates, std::vector<bool> &result); - UINT GetCurrentSampleRate(UINT nDevice); + std::vector<uint32> GetSampleRates(const std::vector<uint32> &samplerates); + UINT GetCurrentSampleRate(); public: - static BOOL EnumerateDevices(UINT nIndex, LPSTR pszDescription, UINT cbSize); + static std::vector<SoundDeviceInfo> EnumerateDevices(); protected: - void OpenDevice(UINT nDevice); + void OpenDevice(); void CloseDevice(); protected: Modified: trunk/OpenMPT/sounddev/SoundDeviceDirectSound.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceDirectSound.cpp 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/sounddev/SoundDeviceDirectSound.cpp 2013-09-28 17:58:40 UTC (rev 2789) @@ -17,6 +17,7 @@ #include "SoundDeviceDirectSound.h" #include "../common/misc_util.h" +#include "../common/StringFixer.h" //////////////////////////////////////////////////////////////////////////////////// @@ -26,48 +27,60 @@ #ifndef NO_DSOUND -#ifndef DSBCAPS_GLOBALFOCUS -#define DSBCAPS_GLOBALFOCUS 0x8000 -#endif -#define MAX_DSOUND_DEVICES 16 +static std::wstring GuidToString(GUID guid) +//----------------------------------------- +{ + std::wstring str; + LPOLESTR tmp = nullptr; + StringFromIID(guid, &tmp); + if(tmp) + { + str = tmp; + CoTaskMemFree(tmp); + tmp = nullptr; + } + return str; +} -static BOOL gbDSoundEnumerated = FALSE; -static UINT gnDSoundDevices = 0; -static GUID *glpDSoundGUID[MAX_DSOUND_DEVICES]; -static CHAR gszDSoundDrvNames[MAX_DSOUND_DEVICES][64]; +static GUID StringToGuid(const std::wstring &str) +//----------------------------------------------- +{ + GUID guid = GUID(); + std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1); + IIDFromString(&tmp[0], &guid); + return guid; +} -static BOOL WINAPI DSEnumCallback(GUID * lpGuid, LPCSTR lpstrDescription, LPCSTR, LPVOID) -//--------------------------------------------------------------------------------------- + +static BOOL WINAPI DSEnumCallbackW(GUID * lpGuid, LPCWSTR lpstrDescription, LPCWSTR, LPVOID lpContext) +//---------------------------------------------------------------------------------------------------- { - if (gnDSoundDevices >= MAX_DSOUND_DEVICES) return FALSE; - if ((lpstrDescription)) + std::vector<SoundDeviceInfo> &devices = *(std::vector<SoundDeviceInfo>*)lpContext; + if(!lpstrDescription) { - if (lpGuid) - { - //if ((gnDSoundDevices) && (!glpDSoundGUID[gnDSoundDevices-1])) gnDSoundDevices--; - glpDSoundGUID[gnDSoundDevices] = new GUID; - *glpDSoundGUID[gnDSoundDevices] = *lpGuid; - } else glpDSoundGUID[gnDSoundDevices] = NULL; - lstrcpyn(gszDSoundDrvNames[gnDSoundDevices], lpstrDescription, 64); - gnDSoundDevices++; - gbDSoundEnumerated = TRUE; + return TRUE; } + SoundDeviceInfo info; + info.type = SNDDEV_DSOUND; + info.index = devices.size(); + info.name = lpstrDescription; + if(lpGuid) + { + info.internalID = GuidToString(*lpGuid); + } + devices.push_back(info); return TRUE; } -BOOL CDSoundDevice::EnumerateDevices(UINT nIndex, LPSTR pszDescription, UINT cbSize) -//---------------------------------------------------------------------------------- +std::vector<SoundDeviceInfo> CDSoundDevice::EnumerateDevices() +//------------------------------------------------------------ { - if(!gbDSoundEnumerated) - { - DirectSoundEnumerate(DSEnumCallback, NULL); - } - if (nIndex >= gnDSoundDevices) return FALSE; - lstrcpyn(pszDescription, gszDSoundDrvNames[nIndex], cbSize); - return TRUE; + std::vector<SoundDeviceInfo> devices; + DirectSoundEnumerateW(DSEnumCallbackW, &devices); + return devices; } @@ -91,8 +104,8 @@ } -bool CDSoundDevice::InternalOpen(UINT nDevice) -//-------------------------------------------- +bool CDSoundDevice::InternalOpen() +//-------------------------------- { WAVEFORMATEXTENSIBLE wfext; if(!FillWaveFormatExtensible(wfext)) return false; @@ -103,9 +116,9 @@ UINT nPriorityLevel = (m_Settings.fulCfgOptions & SNDDEV_OPTIONS_EXCLUSIVE) ? DSSCL_WRITEPRIMARY : DSSCL_PRIORITY; if(m_piDS) return true; - if(!gbDSoundEnumerated) DirectSoundEnumerate(DSEnumCallback, NULL); - if(nDevice >= gnDSoundDevices) return false; - if(DirectSoundCreate(glpDSoundGUID[nDevice], &m_piDS, NULL) != DS_OK) return false; + const std::wstring internalID = GetDeviceInternalID(); + GUID guid = internalID.empty() ? GUID() : StringToGuid(internalID); + if(DirectSoundCreate(internalID.empty() ? NULL : &guid, &m_piDS, NULL) != DS_OK) return false; if(!m_piDS) return false; m_piDS->SetCooperativeLevel(m_Settings.hWnd, nPriorityLevel); m_bMixRunning = FALSE; @@ -345,30 +358,5 @@ } -BOOL SndDevDSoundInitialize() -//--------------------------- -{ - MemsetZero(glpDSoundGUID); - return TRUE; -} - - -BOOL SndDevDSoundUninitialize() -//----------------------------- -{ - for (UINT i=0; i<MAX_DSOUND_DEVICES; i++) - { - if (glpDSoundGUID[i]) - { - delete glpDSoundGUID[i]; - glpDSoundGUID[i] = NULL; - } - } - gbDSoundEnumerated = FALSE; - gnDSoundDevices = 0; - return TRUE; -} - - #endif // NO_DIRECTSOUND Modified: trunk/OpenMPT/sounddev/SoundDeviceDirectSound.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceDirectSound.h 2013-09-28 05:54:38 UTC (rev 2788) +++ trunk/OpenMPT/sounddev/SoundDeviceDirectSound.h 2013-09-28 17:58:40 UTC (rev 2789) @@ -45,8 +45,8 @@ ~CDSoundDevice(); public: - UINT GetDeviceType() { return SNDDEV_DSOUND; } - bool InternalOpen(UINT nDevice); + UINT GetDeviceType() const { return SNDDEV_DSOUND; } + bool Interna... [truncated message content] |