Show More
Commit Description:
Handle the chosen range.
Commit Description:
Handle the chosen range.
References:
File last commit:
Show/Diff file:
Action:
FNA/lib/FAudio/utils/testxwma/testxwma.cpp
246 lines | 6.5 KiB | text/x-c | CppLexer
246 lines | 6.5 KiB | text/x-c | CppLexer
r0 | #include <stdio.h> | |||
#include <SDL.h> | ||||
#include <FAudio.h> | ||||
float argPlayBegin = 0.0f; | ||||
float argPlayLength = 0.0f; | ||||
float argLoopBegin = 0.0f; | ||||
float argLoopLength = 0.0f; | ||||
uint32_t argLoopCount = 0; | ||||
FAudio *faudio = NULL; | ||||
FAudioMasteringVoice *mastering_voice = NULL; | ||||
FAudioSourceVoice *source_voice = NULL; | ||||
FAudioWaveFormatExtensible *wfx = NULL; | ||||
FAudioBuffer buffer = {0}; | ||||
FAudioBufferWMA buffer_wma = {0}; | ||||
/* based on https://docs.microsoft.com/en-us/windows/desktop/xaudio2/how-to--load-audio-data-files-in-xaudio2 */ | ||||
#define fourccRIFF *((uint32_t *) "RIFF") | ||||
#define fourccDATA *((uint32_t *) "data") | ||||
#define fourccFMT *((uint32_t *) "fmt ") | ||||
#define fourccWAVE *((uint32_t *) "WAVE") | ||||
#define fourccXWMA *((uint32_t *) "XWMA") | ||||
#define fourccDPDS *((uint32_t *) "dpds") | ||||
uint32_t FindChunk(FILE *hFile, uint32_t fourcc, uint32_t *dwChunkSize, uint32_t *dwChunkDataPosition) | ||||
{ | ||||
uint32_t hr = 0; | ||||
if (fseek(hFile, 0, SEEK_SET) != 0) | ||||
{ | ||||
return -1; | ||||
} | ||||
uint32_t dwChunkType; | ||||
uint32_t dwChunkDataSize; | ||||
uint32_t dwRIFFDataSize = 0; | ||||
uint32_t dwFileType; | ||||
uint32_t bytesRead = 0; | ||||
uint32_t dwOffset = 0; | ||||
while (hr == 0) | ||||
{ | ||||
if (fread(&dwChunkType, sizeof(uint32_t), 1, hFile) < 1) | ||||
hr = 1; | ||||
if (fread(&dwChunkDataSize, sizeof(uint32_t), 1, hFile) < 1) | ||||
hr = 1; | ||||
if (dwChunkType == fourccRIFF) | ||||
{ | ||||
dwRIFFDataSize = dwChunkDataSize; | ||||
dwChunkDataSize = 4; | ||||
if (fread(&dwFileType, sizeof(uint32_t), 1, hFile) < 1) | ||||
hr = 1; | ||||
} | ||||
else | ||||
{ | ||||
if (fseek(hFile, dwChunkDataSize, SEEK_CUR) != 0) | ||||
return 1; | ||||
} | ||||
dwOffset += sizeof(uint32_t) * 2; | ||||
if (dwChunkType == fourcc) | ||||
{ | ||||
*dwChunkSize = dwChunkDataSize; | ||||
*dwChunkDataPosition = dwOffset; | ||||
return 0; | ||||
} | ||||
dwOffset += dwChunkDataSize; | ||||
if (bytesRead >= dwRIFFDataSize) | ||||
return 1; | ||||
} | ||||
return 1; | ||||
} | ||||
uint32_t ReadChunkData(FILE *hFile, void * buffer, uint32_t buffersize, uint32_t bufferoffset) | ||||
{ | ||||
uint32_t hr = 0; | ||||
if (fseek(hFile, bufferoffset, SEEK_SET) != 0) | ||||
return 1; | ||||
if (fread(buffer, buffersize, 1, hFile) < 1) | ||||
hr = 1; | ||||
return hr; | ||||
} | ||||
uint32_t load_data(const char *filename) | ||||
{ | ||||
/* open the audio file */ | ||||
FILE *hFile = fopen(filename, "rb"); | ||||
if (!hFile) | ||||
return 1; | ||||
fseek(hFile, 0, SEEK_SET); | ||||
/* Locate the 'RIFF' chunk in the audio file, and check the file type. */ | ||||
uint32_t dwChunkSize; | ||||
uint32_t dwChunkPosition; | ||||
uint32_t filetype; | ||||
FindChunk(hFile,fourccRIFF, &dwChunkSize, &dwChunkPosition); | ||||
ReadChunkData(hFile, &filetype, sizeof(uint32_t), dwChunkPosition); | ||||
if (filetype != fourccWAVE && filetype != fourccXWMA) | ||||
return 1; | ||||
/* Locate the 'fmt ' chunk, and copy its contents into a WAVEFORMATEXTENSIBLE structure. */ | ||||
FindChunk(hFile,fourccFMT, &dwChunkSize, &dwChunkPosition ); | ||||
if (dwChunkSize > sizeof(FAudioWaveFormatExtensible)) | ||||
{ | ||||
wfx = (FAudioWaveFormatExtensible *) malloc(dwChunkSize); | ||||
printf("chunk-size exceeds wfx size, allocating more: %u > %u\n", dwChunkSize, sizeof(FAudioWaveFormatExtensible)); | ||||
} | ||||
else | ||||
{ | ||||
wfx = (FAudioWaveFormatExtensible *) malloc(sizeof(FAudioWaveFormatExtensible)); | ||||
printf("chunk-size equal or less than wfx size, capping: %u <= %u\n", dwChunkSize, sizeof(FAudioWaveFormatExtensible)); | ||||
} | ||||
ReadChunkData(hFile, wfx, dwChunkSize, dwChunkPosition ); | ||||
/* Locate the 'data' chunk, and read its contents into a buffer. */ | ||||
FindChunk(hFile, fourccDATA, &dwChunkSize, &dwChunkPosition); | ||||
uint8_t *pDataBuffer = (uint8_t *) malloc(dwChunkSize); | ||||
ReadChunkData(hFile, pDataBuffer, dwChunkSize, dwChunkPosition); | ||||
printf("data chunk size: %u\n", dwChunkSize); | ||||
buffer.AudioBytes = dwChunkSize; //buffer containing audio data | ||||
buffer.pAudioData = pDataBuffer; //size of the audio buffer in bytes | ||||
buffer.Flags = FAUDIO_END_OF_STREAM; // tell the source voice not to expect any data after this buffer | ||||
/* Locate the 'dpds' chunk, and read its contents into a buffer. */ | ||||
if (FindChunk(hFile, fourccDPDS, &dwChunkSize, &dwChunkPosition) == 0) | ||||
{ | ||||
uint32_t *cumulBytes = (uint32_t *) malloc(dwChunkSize); | ||||
ReadChunkData(hFile, cumulBytes, dwChunkSize, dwChunkPosition); | ||||
buffer_wma.pDecodedPacketCumulativeBytes = cumulBytes; | ||||
buffer_wma.PacketCount = dwChunkSize / sizeof(uint32_t); | ||||
} | ||||
fclose(hFile); | ||||
return 0; | ||||
} | ||||
void faudio_setup() { | ||||
uint32_t hr = FAudioCreate(&faudio, 0, FAUDIO_DEFAULT_PROCESSOR); | ||||
if (hr != 0) { | ||||
return; | ||||
} | ||||
hr = FAudio_CreateMasteringVoice(faudio, &mastering_voice, 2, 44100, 0, 0, NULL); | ||||
if (hr != 0) { | ||||
return; | ||||
} | ||||
hr = FAudio_CreateSourceVoice( | ||||
faudio, | ||||
&source_voice, | ||||
(FAudioWaveFormatEx *) wfx, | ||||
FAUDIO_VOICE_USEFILTER, | ||||
FAUDIO_MAX_FREQ_RATIO, | ||||
NULL, NULL, NULL | ||||
); | ||||
} | ||||
void play(void) { | ||||
buffer.PlayBegin = argPlayBegin * wfx->Format.nSamplesPerSec; | ||||
buffer.PlayLength = argPlayLength * wfx->Format.nSamplesPerSec; | ||||
buffer.LoopBegin = argLoopBegin * wfx->Format.nSamplesPerSec; | ||||
buffer.LoopLength = argLoopLength * wfx->Format.nSamplesPerSec; | ||||
buffer.LoopCount = argLoopCount; | ||||
if (buffer_wma.pDecodedPacketCumulativeBytes != NULL) | ||||
FAudioSourceVoice_SubmitSourceBuffer(source_voice, &buffer, &buffer_wma); | ||||
else | ||||
FAudioSourceVoice_SubmitSourceBuffer(source_voice, &buffer, NULL); | ||||
uint32_t hr = FAudioSourceVoice_Start(source_voice, 0, FAUDIO_COMMIT_NOW); | ||||
int is_running = 1; | ||||
while (hr == 0 && is_running) { | ||||
FAudioVoiceState state; | ||||
FAudioSourceVoice_GetState(source_voice, &state, 0); | ||||
is_running = (state.BuffersQueued > 0) != 0; | ||||
SDL_Delay(10); | ||||
} | ||||
FAudioVoice_DestroyVoice(source_voice); | ||||
/* free allocated space for FAudioWafeFormatExtensible */ | ||||
free(wfx); | ||||
} | ||||
int main(int argc, char *argv[]) { | ||||
/* process command line arguments. This is just a test program, didn't go too nuts with validation. */ | ||||
if (argc < 2 || (argc > 4 && argc != 7)) { | ||||
printf("Usage: %s filename [PlayBegin] [PlayLength] [LoopBegin LoopLength LoopCount]\n", argv[0]); | ||||
printf(" - filename (required): can be either a WAV or xWMA audio file.\n"); | ||||
printf(" - PlayBegin (optional): start playing at this offset. (in seconds)\n"); | ||||
printf(" - PlayLength (optional): duration of the region to be played. (in seconds)\n"); | ||||
printf(" - LoopBegin (optional): start looping at this offset. (in seconds)\n"); | ||||
printf(" - LoopLength (optional): duration of the loop (in seconds)\n"); | ||||
printf(" - LoopCount (optional): number of times to loop\n"); | ||||
return -1; | ||||
} | ||||
switch (argc) | ||||
{ | ||||
case 7: | ||||
sscanf(argv[6], "%d", &argLoopCount); | ||||
sscanf(argv[5], "%f", &argLoopLength); | ||||
sscanf(argv[4], "%f", &argLoopBegin); | ||||
case 4: | ||||
sscanf(argv[3], "%f", &argPlayLength); | ||||
case 3: | ||||
sscanf(argv[2], "%f", &argPlayBegin); | ||||
} | ||||
if (load_data(argv[1]) != 0) | ||||
{ | ||||
printf("Error loading data\n"); | ||||
return -1; | ||||
} | ||||
faudio_setup(); | ||||
play(); | ||||
return 0; | ||||
} | ||||