+#include "pch.h"
+#include "sf_memory.h"
+#include "SoundDriver.h"
+
+using namespace std;
+using namespace Windows::Foundation;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::Media::Devices;
+using namespace Concurrency;
+using namespace Platform;
+#pragma comment(lib, "mmdevapi.lib")
+
+namespace sf {
+
+ void makeWaveFormat(WAVEFORMATEXTENSIBLE& format,
+ int sample_rate = 44100,int channels = 2,int bits_per_sample = 32,int valid_bits_per_sample = 32,
+ uint32_t type = WAVE_FORMAT_EXTENSIBLE,
+ const GUID& sub_type = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
+ {
+ ZeroMemory(&format,sizeof(WAVEFORMATEXTENSIBLE));
+ format.Format.wFormatTag = type;
+ format.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+ format.SubFormat = sub_type;
+ format.Format.nSamplesPerSec = sample_rate;
+ format.Format.nChannels = channels;
+ format.Format.wBitsPerSample = bits_per_sample;
+ format.Format.nBlockAlign = (format.Format.wBitsPerSample / 8) * format.Format.nChannels;
+ format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec * format.Format.nBlockAlign;
+ format.Samples.wValidBitsPerSample = valid_bits_per_sample;
+ format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
+ }
+
+ void makeWaveFormat(WAVEFORMATEX& format,int sample_rate = 44100,int channels = 2,int bits = 16,uint32_t type = WAVE_FORMAT_PCM)
+ {
+ ZeroMemory(&format,sizeof(WAVEFORMATEX));
+ format.wFormatTag = type;
+ format.nSamplesPerSec = sample_rate;
+ format.nChannels = channels;
+ format.wBitsPerSample = bits;
+ format.nBlockAlign = (format.wBitsPerSample / 8) * format.nChannels;
+ format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
+ };
+
+
+SoundDriver::SoundDriver() : rateConvert_(false)
+{
+ //::AvMMAvSetMmThreadCharacteristics
+ String^ deviceID = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
+ ActivateAudioInterface(deviceID->Data(),__uuidof(IAudioClient2),&audioClient_);
+ if(!audioClient_)
+ {
+ throw AudioClientNullException(L"\8aù\92è\82ÌAudioClient\82ð\83A\83N\83e\83B\83x\81[\83g\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B");
+ }
+
+ // \83I\81[\83f\83B\83I\83t\83H\81[\83}\83b\83g\82Ì\83`\83F\83b\83N
+ // KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,2CH\83X\83e\83\8c\83I,44100KHz\82ð\95W\8f\80\82Æ\82·\82é
+ WAVEFORMATEXTENSIBLE format;
+ makeWaveFormat(format);
+ sf::co_task_memory<WAVEFORMATEXTENSIBLE> mix_format;
+ audioClient_->GetMixFormat(reinterpret_cast<WAVEFORMATEX**>(&mix_format));
+
+ sf::co_task_memory<WAVEFORMATEXTENSIBLE> alt_format;
+ HRESULT hr = audioClient_->IsFormatSupported(
+ AUDCLNT_SHAREMODE_SHARED,
+ reinterpret_cast<WAVEFORMATEX*>(&format),
+ reinterpret_cast<WAVEFORMATEX**>(&alt_format));
+ int sample_rate_backup = 0;
+ if(hr == S_FALSE) // FALSE\82Ì\8e\9e\82Í\82¨\82»\82ç\82\83T\83\93\83v\83\8a\83\93\83O\83\8c\81[\83g\82ª\88á\82¤
+ {
+ // \83T\83\93\83v\83\8a\83\93\83O\83\8c\81[\83g\82Ì\82Ý\82ª\88Ù\82È\82é\82©\83`\83F\83b\83N\82·\82é
+ if( alt_format->Format.wFormatTag == format.Format.wFormatTag &&
+ alt_format->Format.nChannels == format.Format.nChannels &&
+ alt_format->Format.wBitsPerSample == format.Format.wBitsPerSample &&
+ alt_format->Samples.wValidBitsPerSample == format.Samples.wValidBitsPerSample &&
+ alt_format->Format.nSamplesPerSec != format.Format.nSamplesPerSec
+ )
+ {
+ sample_rate_backup = format.Format.nSamplesPerSec;
+ // \91ã\91Ö\83t\83H\81[\83}\83b\83g\82Ì\83T\83\93\83v\83\8b\83\8c\81[\83g\82ð\83Z\83b\83g\82·\82é
+ format.Format.nSamplesPerSec = alt_format->Format.nSamplesPerSec;
+ // \8dÄ\8cv\8eZ\82·\82é
+ format.Format.nAvgBytesPerSec = alt_format->Format.nSamplesPerSec * format.Format.nBlockAlign;
+ // \82à\82¤\88ê\89ñ\83`\83F\83b\83N\82·\82é\81B
+ // \83T\83\93\83v\83\8b\83\8c\81[\83g\88È\8aO\82Å\83T\83|\81[\83g\82µ\82Ä\82¢\82È\82¢\93_\82ª\82 \82ê\82Î\97á\8aO\82ª\94\90¶\82·\82é\81B
+ alt_format.reset();
+ ThrowIfErr(audioClient_->IsFormatSupported(
+ AUDCLNT_SHAREMODE_SHARED,
+ reinterpret_cast<WAVEFORMATEX*>(&format),
+ reinterpret_cast<WAVEFORMATEX**>(&alt_format)));
+ rateConvert_ = true;
+ } else {
+ throw AudioFormatNotSupportedException(L"\82±\82Ì\83I\81[\83f\83B\83I\83f\83o\83C\83X\82Å\90Ý\92è\82µ\82Ä\82¢\82é\83t\83H\81[\83}\83b\83g\82Í\91Î\89\9e\82µ\82Ä\82¢\82Ü\82¹\82ñ\81B");
+ }
+ }
+
+ // Audio Client\82Ì\8f\89\8aú\89»
+
+ REFERENCE_TIME defaultDevicePeriod,minDevicePriod;
+ audioClient_->GetDevicePeriod(&defaultDevicePeriod,&minDevicePriod);
+ hr = audioClient_->Initialize(
+ AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_NOPERSIST |
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
+ rateConvert_?AUDCLNT_STREAMFLAGS_RATEADJUST:0 ,
+ minDevicePriod,0,
+ reinterpret_cast<WAVEFORMATEX*>(&format),NULL);
+ if(hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
+ {
+ ThrowIfErr(audioClient_->GetBufferSize(&bufferSize_));
+ latency_ = (double)10000000 * (bufferSize_) / format.Format.nSamplesPerSec;
+ audioClient_.Reset();
+ ActivateAudioInterface(deviceID->Data(),__uuidof(IAudioClient2),&audioClient_);
+ if(!audioClient_)
+ {
+ throw AudioClientNullException(L"\8aù\92è\82ÌAudioClient\82ð\83A\83N\83e\83B\83x\81[\83g\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B");
+ }
+ ThrowIfErr(audioClient_->Initialize(
+ AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_NOPERSIST |
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
+ rateConvert_?AUDCLNT_STREAMFLAGS_RATEADJUST:0,
+ latency_,0,
+ reinterpret_cast<WAVEFORMATEX*>(&format),NULL));
+ } else {
+ throw Platform::Exception::CreateException(hr);
+ }
+
+ ThrowIfErr(audioClient_->GetBufferSize(&bufferSize_));
+
+ //// \83T\83\93\83v\83\8b\83\8c\81[\83g\83R\83\93\83o\81[\83^
+ //if(rateConvert_)
+ //{
+ // ThrowIfErr(audioClient_->GetService(__uuidof(IAudioClockAdjustment),&audioClockAdjustment_));
+ // // \96{\97\88\82Ì\83T\83\93\83v\83\8b\83\8c\81[\83g\82ð\83Z\83b\83g\82·\82é
+ // audioClockAdjustment_->SetSampleRate(sample_rate_backup);
+ //}
+
+ audioClient_->GetStreamLatency(&latency_);
+ ThrowIfErr(audioClient_->GetService(__uuidof(IAudioRenderClient),&audioRenderClient_));
+}
+
+SoundDriver::~SoundDriver()
+{
+ audioClient_->Stop();
+ audioRenderClient_.Reset();
+ audioClient_->Reset();
+}
+}