📄 audio.c
字号:
#include "windows.h"
#include "dsound.h"
#include "dinput.h"
#include "shared.h"
#include "audio.h"
#include "input.h"
#include "main.h"
#include "registry.h"
static LPDIRECTSOUND pDirectSound = NULL;
static LPDIRECTSOUNDBUFFER pPrimaryBuffer = NULL;
static LPDIRECTSOUNDBUFFER pSoundBuffer = NULL;
static void *pSimpleSoundBuffer = NULL;
static HWAVEOUT hWaveOut;
static WAVEHDR WaveHeader;
static HANDLE RecordFileHandle = INVALID_HANDLE_VALUE;
static BOOL RecordInProgress = FALSE;
static unsigned int RecordedBytes = 0;
static WAV_HEADER WavFileHeader = { {"RIFF", 0},
{"WAVE"},
{"fmt ", sizeof(WAVEFORMATEX)},
{WAVE_FORMAT_PCM, 2, 0, 0, 4, 16, 0},
{"data", 0} };
BOOL InitAudio(HWND hwnd, int Frequency, int UpdateFrequency)
{
DSBUFFERDESC SoundBufferDesc;
WAVEFORMATEX WaveFormat;
RecordInProgress = FALSE;
SetWavHeaderInfo(0, Frequency, UpdateFrequency);
// Create the direct sound interface
if (DirectSoundCreate(NULL, &pDirectSound, NULL) != DS_OK)
{
TidyAudio();
// Try simple audio for windows NT
return InitSimpleAudio(hwnd, Frequency, UpdateFrequency);
}
// Set the cooperative level
if (IDirectSound_SetCooperativeLevel(pDirectSound, hwnd, DSSCL_EXCLUSIVE) != DS_OK)
{
TidyAudio();
// Try simple audio for windows NT
return InitSimpleAudio(hwnd, Frequency, UpdateFrequency);
}
// Set the speaker configuration
IDirectSound_SetSpeakerConfig(pDirectSound, DSSPEAKER_STEREO);
// Initialise the sound buffer description
memset(&SoundBufferDesc, 0, sizeof(DSBUFFERDESC));
// Set the size of the structure
SoundBufferDesc.dwSize = sizeof(DSBUFFERDESC);
// We require a primary buffer
SoundBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
// Create the sound buffer
if (IDirectSound_CreateSoundBuffer(pDirectSound, &SoundBufferDesc, &pPrimaryBuffer, NULL) != DS_OK)
{
TidyAudio();
// Try simple audio for windows NT
return InitSimpleAudio(hwnd, Frequency, UpdateFrequency);
}
WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
WaveFormat.nChannels = 2;
WaveFormat.nSamplesPerSec = Frequency;
WaveFormat.nAvgBytesPerSec = Frequency * 4;
WaveFormat.nBlockAlign = 4;
WaveFormat.wBitsPerSample = 16;
WaveFormat.cbSize = 0;
SoundBufferDesc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME;
SoundBufferDesc.dwBufferBytes = (Frequency / UpdateFrequency) * 4 * NO_OF_AUDIO_BUFFERS;
SoundBufferDesc.lpwfxFormat = &WaveFormat;
if (IDirectSoundBuffer_SetFormat(pPrimaryBuffer, &WaveFormat) != DS_OK)
{
TidyAudio();
return FALSE;
}
if (IDirectSound_CreateSoundBuffer(pDirectSound, &SoundBufferDesc, &pSoundBuffer, NULL) != DS_OK)
{
TidyAudio();
return FALSE;
}
return TRUE;
}
BOOL InitSimpleAudio(HWND hwnd, int Frequency, int UpdateFrequency)
{
unsigned int WavSize = sizeof(WAV_HEADER) + ((Frequency / UpdateFrequency) * 4 * NO_OF_AUDIO_BUFFERS);
// Allocate the wave buffer
pSimpleSoundBuffer = malloc(WavSize);
if (!pSimpleSoundBuffer) return FALSE;
SetWavHeaderInfo(WavSize, Frequency, UpdateFrequency);
memset(pSimpleSoundBuffer, 0, WavSize);
memcpy(pSimpleSoundBuffer, &WavFileHeader, sizeof(WAV_HEADER));
waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, (LPWAVEFORMATEX)&WavFileHeader.WaveFormat, (LONG)hwnd, 0, CALLBACK_WINDOW);
memset(&WaveHeader, 0, sizeof(WAVEHDR));
WaveHeader.lpData = (char *)((int)pSimpleSoundBuffer + sizeof(WAV_HEADER));
WaveHeader.dwBufferLength = (Frequency / UpdateFrequency) * 4 * NO_OF_AUDIO_BUFFERS;
WaveHeader.dwLoops = 0x7FFFFFFF;
WaveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
return TRUE;
}
void SetWavHeaderInfo(unsigned int WavSize, int Frequency, int UpdateFrequency)
{
WavFileHeader.RiffHeader.Length = WavSize - sizeof(RIFF_HEADER);
WavFileHeader.WaveFormat.nSamplesPerSec = Frequency;
WavFileHeader.WaveFormat.nAvgBytesPerSec = Frequency * 4;
WavFileHeader.DataChunk.Length = (Frequency / UpdateFrequency) * 4 * NO_OF_AUDIO_BUFFERS;
}
void StopAudio(void)
{
if (pSimpleSoundBuffer) waveOutReset(hWaveOut);
if (pSoundBuffer) IDirectSoundBuffer_Stop(pSoundBuffer);
}
void UpdateAudio(short *pBuffer, int BufferSize, int Frame)
{
LPVOID pAudio1;
int AudioBytes1;
LPVOID pAudio2;
int AudioBytes2;
DWORD WritePos;
BufferSize *= 4;
WritePos = ((Frame + (NO_OF_AUDIO_BUFFERS >> 1)) % NO_OF_AUDIO_BUFFERS) * BufferSize;
if (pSimpleSoundBuffer)
{
memcpy((char *)((int)pSimpleSoundBuffer + sizeof(WAV_HEADER) + WritePos), pBuffer, BufferSize);
if (Frame == 0)
{
waveOutReset(hWaveOut);
while (waveOutUnprepareHeader(hWaveOut, &WaveHeader, sizeof(WAVEHDR)) == WAVERR_STILLPLAYING);
waveOutPrepareHeader(hWaveOut, &WaveHeader, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, &WaveHeader, sizeof(WAVEHDR));
}
}
else if (pSoundBuffer)
{
// Lock the sound buffer
if (IDirectSoundBuffer_Lock(pSoundBuffer, WritePos, BufferSize, &pAudio1, &AudioBytes1, &pAudio2, &AudioBytes2, 0) == DS_OK)
{
// Buffer is now locked, write first block
memcpy(pAudio1, (char *)pBuffer, AudioBytes1);
// See if we need to write a second block
if (AudioBytes2)
{
// Yes, so write second block
memcpy(pAudio2, (char *)((int)pBuffer + AudioBytes1), AudioBytes2);
}
// Unlock buffer
IDirectSoundBuffer_Unlock(pSoundBuffer, pAudio1, AudioBytes1, pAudio2, AudioBytes2);
}
if (Frame == 0)
{
IDirectSoundBuffer_SetCurrentPosition(pSoundBuffer, 0);
IDirectSoundBuffer_Play(pSoundBuffer, 0, 0, DSBPLAY_LOOPING);
}
}
}
void TidyAudio(void)
{
if (RecordInProgress) CloseSoundRecording();
if (pSimpleSoundBuffer)
{
waveOutReset(hWaveOut);
while (waveOutUnprepareHeader(hWaveOut, &WaveHeader, sizeof(WAVEHDR)) == WAVERR_STILLPLAYING);
waveOutClose(hWaveOut);
free(pSimpleSoundBuffer);
pSimpleSoundBuffer = NULL;
}
if (pSoundBuffer)
{
IDirectSoundBuffer_Stop(pSoundBuffer);
IDirectSoundBuffer_Release(pSoundBuffer);
pSoundBuffer = NULL;
}
if (pPrimaryBuffer)
{
IDirectSoundBuffer_Stop(pPrimaryBuffer);
IDirectSoundBuffer_Release(pPrimaryBuffer);
pPrimaryBuffer = NULL;
}
if (pDirectSound)
{
IDirectSound_Release(pDirectSound);
pDirectSound = NULL;
}
}
BOOL CreateSoundRecording(void)
{
char Filename[MAX_PATH];
RecordInProgress = TRUE;
wsprintf(Filename, "%s%s.gym", RegistryInfo.SoundRecordPath, GetGameName());
RecordFileHandle = CreateFile(Filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (RecordFileHandle == INVALID_HANDLE_VALUE) return FALSE;
snd.log = TRUE;
return TRUE;
}
void UpdateSoundRecording(int Data)
{
unsigned int BytesWritten;
if (RecordFileHandle != INVALID_HANDLE_VALUE)
{
WriteFile(RecordFileHandle, &Data, 1, &BytesWritten, NULL);
}
}
void CloseSoundRecording(void)
{
snd.log = FALSE;
CloseHandle(RecordFileHandle);
RecordFileHandle = INVALID_HANDLE_VALUE;
RecordInProgress = FALSE;
MessageBox(NULL, "Sound recording complete.", "", MB_OK);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -