+ -
当前位置:首页 → 问答吧 → DirectSound

DirectSound

时间:2014-04-18

来源:互联网

正在写DirectSound...
汪汪不知道...为何每次Call SoundStream::Write时....声音都会断开的(爆音)...
复制内容到剪贴板代码:class SoundDevice;

class SoundStream
{

IDirectSoundBuffer8 * soundbuffer;
const WORD channel, bits, validBits;
const DWORD frequency, blockBytes;

uint8_t * buffer;
size_t bufferBytes;
std::thread thread;
std::mutex mutex;
HANDLE flag;

bool decompose;

SoundStream(IDirectSoundBuffer8 * pDsb8, WORD getChannel, WORD getBits, WORD getValidBits, DWORD getFrequency, DWORD getBlockBytes);

public:
friend SoundDevice;

~SoundStream();

DWORD PlayCursor();
DWORD WriteCursor();
DWORD CursorDiff();
DWORD RemainTime();

void Write(const multiarray<double, 2> &data);
void Clear();
void Sync();

private:

DWORD _diff(DWORD first, DWORD second);

};

class SoundDevice
{

IDirectSound8 * device;

public:

SoundDevice(HWND hWnd);
~SoundDevice();

SoundStream * Channel_1(DWORD fq);
SoundStream * Channel_2(DWORD fq);
SoundStream * Channel_4(DWORD fq);
SoundStream * Channel_5_1(DWORD fq);

private:

SoundStream * CreateBuffer(LPWAVEFORMATEX wfx, WORD validBits, DWORD frequency);

};
void SoundStream::Write(const multiarray<double, 2> &data)
{
if (data.size(0) != channel || data.size(1) == 0) return;

std::lock_guard<std::mutex> lock(mutex);

const int64_t max = 1 << ((int64_t)validBits - 1), min = ~max;
const size_t oldBytes = bufferBytes;

uint8_t * _buffer = buffer;
bufferBytes = data.size() * (bits >> 3) + oldBytes;
buffer = new uint8_t[(size_t)(bufferBytes + ((bits >> 3) % 8 ? 8 - ((bits >> 3) % 8) : 0))];
if (_buffer != nullptr)
{
memcpy(buffer, _buffer, (size_t)oldBytes);
delete[] _buffer;
}

for (size_t i = 0; i < data.size(1); ++i)
{
for (size_t j = 0; j < channel; ++j)
{
int64_t *ptr = (int64_t*)(buffer + oldBytes + (i * channel + j) * (bits >> 3));
*ptr = (int64_t)bound(data[(size_t)j][(size_t)i], (double)max, (double)min);
}
}

SetEvent(flag);

}
void SoundStream::Sync()
{

static DWORD CursorRecord = 0;
std::lock_guard<std::mutex> lock(mutex);

DWORD Cursor = WriteCursor(), MaxWriteBytes = blockBytes * 2 - (Cursor % blockBytes);

LPVOID bufferPtr[2];
DWORD _bufferBytes[2];

HResult(soundbuffer->Lock(Cursor, MaxWriteBytes, &bufferPtr[0], &_bufferBytes[0], &bufferPtr[1], &_bufferBytes[1], 0));

DWORD ChoppedBytes[2];
ChoppedBytes[0] = min(_bufferBytes[0], (DWORD)bufferBytes);
ChoppedBytes[1] = min(_bufferBytes[1], (DWORD)bufferBytes - ChoppedBytes[0]);

memcpy(bufferPtr[0], buffer, ChoppedBytes[0]);
memcpy(bufferPtr[1], buffer + _bufferBytes[0], ChoppedBytes[1]);
memset((uint8_t*)bufferPtr[0] + ChoppedBytes[0], 0, _bufferBytes[0] - ChoppedBytes[0]);
memset((uint8_t*)bufferPtr[1] + ChoppedBytes[1], 0, _bufferBytes[1] - ChoppedBytes[1]);
HResult(soundbuffer->Unlock(bufferPtr[0], _bufferBytes[0], bufferPtr[1], _bufferBytes[1]));

uint8_t * _buffer = buffer;
DWORD offset = min(_diff(Cursor, CursorRecord), ChoppedBytes[0] + ChoppedBytes[1]);
CursorRecord = Cursor;
bufferBytes -= offset;
if (bufferBytes)
buffer = new uint8_t[(size_t)bufferBytes];
else
buffer = nullptr;
if (_buffer != nullptr)
{
if (buffer != nullptr)
memcpy(buffer, _buffer + offset, (size_t)bufferBytes);
delete[] _buffer;
}

}

作者: Susan﹏汪汪   发布时间: 2014-04-18

点解重用 DirectSound?DirectSound 已经被 WASAPI 所取代。

我无用过 DirectSound,根据我用过 Allegro 嘅经验,以下系一尐可能性:
1. buffer size 计算有误(过长或过短)
2. 时间性出错
3. 计算 buffer 内容有偏差,如用咗 real numbers,又或整数计算时,出现 overflow 或 underflow

作者: fitcat07   发布时间: 2014-04-18

引用:原帖由 fitcat07 於 2014-3-20 01:03 PM 发表
点解重用 DirectSound?DirectSound 已经被 WASAPI 所取代。

我无用过 DirectSound,根据我用过 Allegro 嘅经验,以下系一尐可能性:
1. buffer size 计算有误(过长或过短)
2. 时间性出错
3. 计算 buf ...
今晚换wasapi吧

作者: Susan﹏汪汪   发布时间: 2014-04-18

汪汪不知道为甚么会完全冇声
复制内容到剪贴板代码:class SoundStream
{
IAudioClient * pAudioClient;

std::thread thread;
std::mutex mtx;

HANDLE hEvent;

BYTE * buffer;
size_t bufferSize;
UINT32 bufferFrameCount, channel, bits, validBits, frequency;

bool distroy;

void _writebuffer();

public:

SoundStream(_AUDCLNT_SHAREMODE ShareMode = AUDCLNT_SHAREMODE_SHARED);
~SoundStream();

UINT32 Channel()
{
return channel;
}
UINT32 Frequency()
{
return frequency;
}
UINT32 Bits()
{
return bits;
}
UINT32 ValidBits()
{
return validBits;
}
void Write(const multiarray<double, 2> &data);
void Sync();

};

// REFERENCE_TIME time units per second and per millisecond
#define REFTIMES_PER_SEC 10000000
#define REFTIMES_PER_MILLISEC 10000

SoundStream::SoundStream(_AUDCLNT_SHAREMODE ShareMode) : buffer(nullptr), bufferSize(0), distroy(false)
{

IMMDeviceEnumerator * pEnumerator = nullptr;
HResult(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, IID_PPV_ARGS(&pEnumerator)));

IMMDevice * pDevice = nullptr;
HResult(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice));
SafeRelease(&pEnumerator);

HResult(pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient));
SafeRelease(&pDevice);

WAVEFORMATEXTENSIBLE * pwfx = nullptr;

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

if (ShareMode == AUDCLNT_SHAREMODE_SHARED)
{

REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;

HResult(pAudioClient->GetMixFormat((WAVEFORMATEX**)&pwfx));

HResult(pAudioClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
0,
hnsRequestedDuration,
0,
(WAVEFORMATEX*)pwfx,
NULL));

} else
{

REFERENCE_TIME hnsRequestedDuration;

HResult(GetStreamFormat(pAudioClient, &pwfx));

HResult(pAudioClient->GetDevicePeriod(NULL, &hnsRequestedDuration));

HResult(pAudioClient->Initialize(
AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
hnsRequestedDuration,
hnsRequestedDuration,
(WAVEFORMATEX*)pwfx,
NULL));

HResult(pAudioClient->SetEventHandle(hEvent));

}

channel = (size_t)pwfx->Format.nChannels;
bits = (size_t)pwfx->Format.wBitsPerSample;
validBits = (size_t)pwfx->Samples.wValidBitsPerSample;
frequency = (size_t)pwfx->Format.nSamplesPerSec;

CoTaskMemFree(pwfx);

HResult(pAudioClient->GetBufferSize(&bufferFrameCount));
HResult(pAudioClient->Start());

if (pAudioClient)
{
thread = std::thread([&]()
{
this->Sync();
});
}

}
SoundStream::~SoundStream()
{

if (pAudioClient)
{

distroy = true;
SetEvent(hEvent);
thread.join();

HResult(pAudioClient->Stop());

SafeRelease(&pAudioClient);

}

if (hEvent != NULL)
CloseHandle(hEvent);

if (bufferSize)
delete[] buffer;

}

void SoundStream::Write(const multiarray<double, 2> &data)
{
std::lock_guard<std::mutex> lck(mtx);

const int64_t min = 1 << ((int64_t)validBits - 1), max = ~min;
size_t blockSize = channel * (bits >> 3), oldBufferSize = bufferSize;
bufferSize += data.size(1) * blockSize;
if (oldBufferSize)
{
BYTE * _buffer = buffer;
buffer = new BYTE[bufferSize + ((bits >> 3) % 8 ? 8 - (bits >> 3) % 8 : 0)];
memcpy(buffer, _buffer, oldBufferSize);
delete[] _buffer;
} else
buffer = new BYTE[bufferSize + ((bits >> 3) % 8 ? 8 - (bits >> 3) % 8 : 0)];

for (size_t i = 0; i < data.size(1); ++i)
{
for (size_t j = 0; j < data.size(0) && j < channel; ++j)
{
int64_t * ptr = (int64_t*)(buffer + oldBufferSize + i * blockSize + j * (bits >> 3));

if (data[j][i] > 1)
*ptr = (int64_t)bound(1, (double)max, (double)min);
else if (data[j][i] < -1)
*ptr = (int64_t)bound(-1, (double)max, (double)min);
else
*ptr = (int64_t)bound(data[j][i], (double)max, (double)min);
}
}

SetEvent(hEvent);

}
void SoundStream::Sync()
{

const REFERENCE_TIME hnsActualDuration = (REFERENCE_TIME)(REFTIMES_PER_SEC * bufferFrameCount / frequency);

while (!distroy)
{
WaitForSingleObject(hEvent, (DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2));

if (!distroy) _writebuffer();
}

}
void SoundStream::_writebuffer()
{

std::lock_guard<std::mutex> lck(mtx);

UINT32 numFramesPadding;
HResult(pAudioClient->GetCurrentPadding(&numFramesPadding));

size_t blockSize = channel * (bits >> 3),
ChoppedBytes = min(blockSize * (size_t)(bufferFrameCount - numFramesPadding), bufferSize);

if (ChoppedBytes)
{

IAudioRenderClient * pRenderClient = nullptr;
HResult(pAudioClient->GetService(IID_PPV_ARGS(&pRenderClient)));

BYTE * pData = nullptr;
HResult(pRenderClient->GetBuffer((UINT32)(ChoppedBytes / blockSize), &pData));

memcpy(pData, buffer, ChoppedBytes);

HResult(pRenderClient->ReleaseBuffer((UINT32)(ChoppedBytes / blockSize), 0));

SafeRelease(&pRenderClient);

if (bufferSize -= ChoppedBytes)
{
BYTE * _buffer = buffer;
buffer = new BYTE[bufferSize];
memcpy(buffer, _buffer + ChoppedBytes, bufferSize);
delete[] _buffer;
} else
{
if (buffer != nullptr)
{
delete[] buffer;
buffer = nullptr;
}
}

}

}
[ 本帖最后由 Susan﹏汪汪 於 2014-3-21 03:16 AM 编辑 ]

作者: Susan﹏汪汪   发布时间: 2014-04-18

GetStreamFormat
复制内容到剪贴板代码:HRESULT GetStreamFormat(IAudioClient * pAudioClient, WAVEFORMATEXTENSIBLE ** pwfx)
{

HRESULT hr;

WAVEFORMATEXTENSIBLE wfx;

wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nChannels = 6;
wfx.Format.wBitsPerSample = 24;
wfx.Samples.wValidBitsPerSample = 20;
wfx.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

wfx.Format.nSamplesPerSec = 48000;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 34;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nChannels = 6;
wfx.Format.wBitsPerSample = 24;
wfx.Samples.wValidBitsPerSample = 20;
wfx.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

wfx.Format.nSamplesPerSec = 44100;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 34;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nChannels = 4;
wfx.Format.wBitsPerSample = 16;
wfx.Samples.wValidBitsPerSample = 16;
wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

wfx.Format.nSamplesPerSec = 48000;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 34;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nChannels = 4;
wfx.Format.wBitsPerSample = 16;
wfx.Samples.wValidBitsPerSample = 16;
wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

wfx.Format.nSamplesPerSec = 44100;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 34;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nChannels = 2;
wfx.Format.wBitsPerSample = 24;
wfx.Samples.wValidBitsPerSample = 20;
wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

wfx.Format.nSamplesPerSec = 48000;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 34;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nChannels = 2;
wfx.Format.wBitsPerSample = 24;
wfx.Samples.wValidBitsPerSample = 20;
wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

wfx.Format.nSamplesPerSec = 44100;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 34;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
wfx.Format.nChannels = 2;
wfx.Format.wBitsPerSample = 16;

wfx.Format.nSamplesPerSec = 48000;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 22;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
wfx.Format.nChannels = 2;
wfx.Format.wBitsPerSample = 16;

wfx.Format.nSamplesPerSec = 44100;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 22;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
wfx.Format.nChannels = 1;
wfx.Format.wBitsPerSample = 16;

wfx.Format.nSamplesPerSec = 48000;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 22;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
wfx.Format.nChannels = 1;
wfx.Format.wBitsPerSample = 16;

wfx.Format.nSamplesPerSec = 44100;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
wfx.Format.cbSize = 22;

hr = pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wfx, (WAVEFORMATEX**)pwfx);
if (hr == S_OK)
{
*pwfx = (WAVEFORMATEXTENSIBLE*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
memcpy(*pwfx, &wfx, sizeof(WAVEFORMATEXTENSIBLE));
return hr;
} else if (hr == S_FALSE) return hr;

// Fail
return -1;
}

作者: Susan﹏汪汪   发布时间: 2014-04-18