fix sound playing, we are actually playing an audio file :)

This commit is contained in:
Dennis Eichhorn 2024-09-22 00:10:34 +02:00
parent f7b67e4116
commit 44ebefd06a
11 changed files with 168 additions and 75 deletions

View File

@ -55,7 +55,7 @@ void ams_create(AssetManagementSystem* ams, BufferMemory* buf, int chunk_size, i
ams->asset_data_memory.chunk_size = chunk_size;
ams->asset_data_memory.last_pos = -1;
ams->asset_data_memory.alignment = 1;
ams->asset_data_memory.memory = buffer_get_memory(buf, chunk_size * count);
ams->asset_data_memory.memory = buffer_get_memory(buf, chunk_size * count, 64);
ams->asset_data_memory.free = (uint64 *) buffer_get_memory(buf, CEIL_DIV(count, 64) * sizeof(uint64));
ams->first = NULL;

34
audio/Audio.cpp Normal file
View File

@ -0,0 +1,34 @@
/**
* Jingga
*
* @copyright Jingga
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
#ifndef TOS_AUDIO_C
#define TOS_AUDIO_C
#include "../utils/StringUtils.h"
#include "../memory/RingMemory.h"
#if _WIN32
#include "../platform/win32/UtilsWin32.h"
#else
#include "../platform/linux/UtilsLinux.h"
#endif
#include "Audio.h"
#include "Wav.h"
void audio_from_file(RingMemory* ring, const char* path, Audio* audio)
{
FileBody file;
file_read(path, &file, ring);
if (str_ends_with(path, ".wav")) {
wav_audio_generate(&file, audio);
}
}
#endif

View File

@ -10,14 +10,37 @@
#define TOS_AUDIO_H
#include "../stdlib/Types.h"
#include "../utils/StringUtils.h"
#include "../memory/RingMemory.h"
#if _WIN32
#include "../platform/win32/UtilsWin32.h"
#else
#include "../platform/linux/UtilsLinux.h"
#endif
#include "Audio.h"
struct Audio {
uint32 sample_rate; // bits_per_sample
uint32 sample_size; // byte_per_bloc
uint32 frequency;
// bits per sample
// usually 48000 or 44100
uint32 sample_rate;
// bytes per bloc
// channel count * bit
// usually 2 * 16 = 4
uint32 sample_size;
// audio channels
// usually 2
uint32 channels;
// usually 16 = 2
uint32 bloc_size;
// sample_rate * sample_size
uint32 byte_per_sec;
uint32 size;
byte* data; // owner of data
};

View File

@ -15,13 +15,28 @@
#define SOUND_API_XAUDIO2 1
struct AudioSetting {
// bits per sample
// usually 48000 or 44100
uint32 sample_rate;
// bytes per bloc
// channel count * bit
// usually 2 * 16 = 4
uint32 sample_size;
// position in the audio data
// WARNING: not the byte position, but the index based on the sample size
uint32 sample_index;
uint32 latency;
// how often has the audio_play been called (required for xaudio)
uint32 sample_output;
// 0 - 100
int16 volume;
// max buffer content/size
uint32 buffer_size;
// Actual samples inside the buffer
@ -31,6 +46,8 @@ struct AudioSetting {
bool is_playing = false;
byte type = SOUND_API_DIRECT_SOUND;
// @todo add more settings e.g. repeat etc
};
#endif

View File

@ -64,7 +64,7 @@ void generate_default_wav_references(const FileBody* file, Wav* wav)
// Check if we can copy memory directly
// The struct layout and header size should match on x86, but we still check it
if (sizeof(WavHeader) == WAV_HEADER_SIZE) {
if constexpr (sizeof(WavHeader) == WAV_HEADER_SIZE) {
memcpy(&wav->header, file->content, WAV_HEADER_SIZE);
// swap endian if we are on big endian system
@ -129,23 +129,26 @@ void generate_default_wav_references(const FileBody* file, Wav* wav)
wav->header.data_size = SWAP_ENDIAN_LITTLE(*((uint32 *) *(wav->data + 40)));
}
wav->sample_data = wav->data + WAV_HEADER_SIZE;
wav->sample_data = wav->data + WAV_HEADER_SIZE;
}
void generate_wav_audio(const FileBody* src_data, Audio* audio)
void wav_audio_generate(const FileBody* src_data, Audio* audio)
{
// @performance We are generating the struct and then filling the data.
// There is some asignment/copy overhead
Wav src = {};
generate_default_wav_references(src_data, &src);
audio->sample_rate = src.header.bits_per_sample;
audio->sample_size = src.header.byte_per_bloc;
audio->frequency = src.header.frequency;
if (!src.size) {
return;
}
audio->sample_rate = src.header.frequency;
audio->sample_size = (src.header.bits_per_sample / 8) * src.header.nbr_channels;
audio->channels = src.header.nbr_channels;
audio->byte_per_sec = src.header.byte_per_sec;
audio->bloc_size = src.header.bloc_size;
audio->size = src.size - WAV_HEADER_SIZE;
audio->size = src.header.data_size;
memcpy((void *) audio->data, src.sample_data, audio->size);
}

View File

@ -54,7 +54,7 @@ camera_update_vectors(Camera* camera)
vec3_normalize_f32(&camera->up);
}
void camera_rotate(Camera* camera, float dx, float dy, float dt)
void camera_rotate(Camera* camera, int32 dx, int32 dy, float dt)
{
camera->orientation.x += dy * camera->sensitivity;
camera->orientation.y -= dx * camera->sensitivity;

View File

@ -12,6 +12,8 @@
#include <stdio.h>
#include <string.h>
// @todo Make this file not rely on any other header except Types.
#include "../stdlib/Types.h"
#include "../platform/win32/UtilsWin32.h"
#include "../memory/RingMemory.h"

View File

@ -77,7 +77,6 @@ void debug_memory_add_range(DebugMemory* mem, uint64 start, uint64 end)
inline
void debug_memory_reset(DebugMemory* mem)
{
mem->size = 0;
mem->usage = 0;
mem->debug_range_idx = 0;

View File

@ -76,7 +76,7 @@ bool library_load(Library* lib)
lib->is_valid = true;
for (int c = 0; c < lib->function_count; ++c) {
void* function = GetProcAddress(lib->handle, lib->function_names[c]);
void* function = (void *) GetProcAddress(lib->handle, (LPCSTR) lib->function_names[c]);
if (function) {
lib->functions[c] = function;
} else {

View File

@ -15,9 +15,10 @@
#include "../../../stdlib/Types.h"
#include "../../../audio/AudioSetting.h"
#include "../../../utils/MathUtils.h"
#include "../../../log/Log.h"
struct DirectSoundSetting {
LPDIRECTSOUND8 direct_sound;
LPDIRECTSOUND8 audio_handle;
LPDIRECTSOUNDBUFFER primary_buffer;
LPDIRECTSOUNDBUFFER secondary_buffer;
};
@ -32,19 +33,21 @@ HRESULT WINAPI DirectSoundCreate8Stub(LPCGUID, LPDIRECTSOUND8*, LPUNKNOWN) {
void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_setting) {
HMODULE lib = LoadLibraryExA((LPCSTR) "dsound.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!lib) {
// @todo Log
LOG(log_memory, "DirectSound: Couldn't load dsound.dll\n", log_fp, true, true);
return;
}
audio_create* DirectSoundCreate8 = (audio_create *) GetProcAddress(lib, "DirectSoundCreate8");
if (!DirectSoundCreate8 || !SUCCEEDED(DirectSoundCreate8(0, &api_setting->direct_sound, 0))) {
// @todo Log
if (!DirectSoundCreate8 || !SUCCEEDED(DirectSoundCreate8(0, &api_setting->audio_handle, 0))) {
LOG(log_memory, "DirectSound: DirectSoundCreate8 failed\n", log_fp, true, true);
return;
}
if(!SUCCEEDED(api_setting->direct_sound->SetCooperativeLevel(hwnd, DSSCL_PRIORITY))) {
// @todo Log
if(!SUCCEEDED(api_setting->audio_handle->SetCooperativeLevel(hwnd, DSSCL_PRIORITY))) {
LOG(log_memory, "DirectSound: SetCooperativeLevel failed.\n", log_fp, true, true);
return;
}
@ -59,35 +62,36 @@ void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_settin
wf.cbSize = 0;
// Create primary buffer
DSBUFFERDESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DSBUFFERDESC));
DSBUFFERDESC buffer_desc;
ZeroMemory(&buffer_desc, sizeof(DSBUFFERDESC));
bufferDesc.dwSize = sizeof(DSBUFFERDESC);
bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
buffer_desc.dwSize = sizeof(DSBUFFERDESC);
buffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER;
if(!SUCCEEDED(api_setting->direct_sound->CreateSoundBuffer(&bufferDesc, &api_setting->primary_buffer, 0))) {
// @todo Log
if(!SUCCEEDED(api_setting->audio_handle->CreateSoundBuffer(&buffer_desc, &api_setting->primary_buffer, 0))) {
LOG(log_memory, "DirectSound: CreateSoundBuffer1 failed.\n", log_fp, true, true);
return;
}
if (!SUCCEEDED(api_setting->primary_buffer->SetFormat(&wf))) {
// @todo Log
LOG(log_memory, "DirectSound: SetFormat failed.\n", log_fp, true, true);
return;
}
// Create secondary buffer
DSBUFFERDESC bufferDesc2;
ZeroMemory(&bufferDesc2, sizeof(DSBUFFERDESC));
DSBUFFERDESC buffer_desc2;
ZeroMemory(&buffer_desc2, sizeof(DSBUFFERDESC));
bufferDesc2.dwSize = sizeof(DSBUFFERDESC);
bufferDesc2.dwFlags = 0;
bufferDesc2.dwBufferBytes = setting->buffer_size;
bufferDesc2.lpwfxFormat = &wf;
buffer_desc2.dwSize = sizeof(DSBUFFERDESC);
// @todo check alterntaive flags
buffer_desc2.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLFX | DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2;
buffer_desc2.dwBufferBytes = setting->buffer_size;
buffer_desc2.lpwfxFormat = &wf;
if(!SUCCEEDED(api_setting->direct_sound->CreateSoundBuffer(&bufferDesc2, &api_setting->secondary_buffer, 0))) {
// @todo Log
if(!SUCCEEDED(api_setting->audio_handle->CreateSoundBuffer(&buffer_desc2, &api_setting->secondary_buffer, 0))) {
LOG(log_memory, "DirectSound: CreateSoundBuffer2 failed.\n", log_fp, true, true);
return;
}
@ -107,8 +111,8 @@ void audio_play(AudioSetting* setting, DirectSoundSetting* api_setting)
inline
void audio_free(AudioSetting*, DirectSoundSetting* api_setting)
{
if (api_setting->direct_sound) {
api_setting->direct_sound->Release();
if (api_setting->audio_handle) {
api_setting->audio_handle->Release();
}
if (api_setting->primary_buffer) {
@ -129,7 +133,8 @@ uint32 audio_buffer_fillable(const AudioSetting* setting, const DirectSoundSetti
DWORD player_cursor;
DWORD write_cursor;
if (!SUCCEEDED(api_setting->secondary_buffer->GetCurrentPosition(&player_cursor, &write_cursor))) {
// @todo Log
LOG(log_memory, "DirectSound: GetCurrentPosition failed.\n", log_fp, true, true);
return 0;
}
@ -151,12 +156,16 @@ uint32 audio_buffer_fillable(const AudioSetting* setting, const DirectSoundSetti
}
inline
void audio_play_buffer(AudioSetting* setting, DirectSoundSetting* api_setting, uint32 bytes_to_write)
void audio_play_buffer(AudioSetting* setting, DirectSoundSetting* api_setting)
{
if (bytes_to_write == 0) {
if (setting->sample_buffer_size == 0) {
return;
}
if (!setting->is_playing) {
audio_play(setting, api_setting);
}
void *region1;
DWORD region1_size;
@ -166,16 +175,12 @@ void audio_play_buffer(AudioSetting* setting, DirectSoundSetting* api_setting, u
DWORD bytes_to_lock = (setting->sample_index * setting->sample_size) % setting->buffer_size;
api_setting->secondary_buffer->Lock(
bytes_to_lock, bytes_to_write,
bytes_to_lock, setting->sample_buffer_size,
&region1, &region1_size,
&region2, &region2_size,
0
);
// @question Do we even need to use memcpy? Can't we use the buffer directly?
// Probably depends on what lock actually does to region1/region2
// Of course we would than need some mechanism to check when we can write into the buffer
// See XAudio2 for this, we would probably need a second buffer as well
memcpy(
(void *) region1,
(void *) setting->buffer,
@ -192,7 +197,7 @@ void audio_play_buffer(AudioSetting* setting, DirectSoundSetting* api_setting, u
api_setting->secondary_buffer->Unlock(region1, region1_size, region2, region2_size);
setting->sample_index += bytes_to_write / setting->sample_size;
setting->sample_index += setting->sample_buffer_size / setting->sample_size;
setting->sample_buffer_size = 0;
}

View File

@ -11,13 +11,15 @@
#include <xaudio2.h>
#include <windows.h>
#include <objbase.h>
#include "../../../stdlib/Types.h"
#include "../../../audio/AudioSetting.h"
#include "../../../utils/MathUtils.h"
#include "../../../log/Log.h"
struct XAudio2Setting {
IXAudio2* xaudio2;
IXAudio2* audio_handle;
IXAudio2SourceVoice* source_voice;
IXAudio2MasteringVoice* mastering_voice;
@ -32,31 +34,37 @@ HRESULT WINAPI XAudio2CreateStub(IXAudio2**, UINT32, XAUDIO2_PROCESSOR) {
// END: Dynamically load XAudio2
void audio_load(HWND hwnd, AudioSetting* setting, XAudio2Setting* api_setting) {
CoInitialize(NULL);
HMODULE lib = LoadLibraryExA((LPCSTR) "xaudio2_9.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!lib) {
// @todo Log
LOG(log_memory, "Xaudio2: Couldn't load xaudio2_9.dll\n", log_fp, true, true);
lib = LoadLibraryExA((LPCSTR) "xaudio2_8.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if (!lib) {
// @todo Log
LOG(log_memory, "Xaudio2: Couldn't load xaudio2_8.dll\n", log_fp, true, true);
return;
}
audio_create* XAudio2Create = (audio_create *) GetProcAddress(lib, "XAudio2Create");
if (!XAudio2Create || !SUCCEEDED(XAudio2Create(&api_setting->xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR))) {
// @todo Log
if (!XAudio2Create || !SUCCEEDED(XAudio2Create(&api_setting->audio_handle, 0, XAUDIO2_DEFAULT_PROCESSOR))) {
LOG(log_memory, "Xaudio2: XAudio2Create failed\n", log_fp, true, true);
return;
}
if (!SUCCEEDED(api_setting->xaudio2->CreateMasteringVoice(
HRESULT hr;
if (!SUCCEEDED(hr = api_setting->audio_handle->CreateMasteringVoice(
&api_setting->mastering_voice,
XAUDIO2_DEFAULT_CHANNELS,
setting->sample_rate,
0,
NULL
))) {
// @todo Log
NULL))
) {
LOG(log_memory, "Xaudio2: CreateMasteringVoice failed\n", log_fp, true, true);
return;
}
@ -69,15 +77,16 @@ void audio_load(HWND hwnd, AudioSetting* setting, XAudio2Setting* api_setting) {
wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; // = buffer_size
wf.cbSize = 0;
if (!SUCCEEDED(api_setting->xaudio2->CreateSourceVoice(&api_setting->source_voice, &wf))) {
// @todo Log
if (!SUCCEEDED(api_setting->audio_handle->CreateSourceVoice(&api_setting->source_voice, &wf))) {
LOG(log_memory, "Xaudio2: CreateSourceVoice failed\n", log_fp, true, true);
return;
}
// @todo consider to remove mallocs/callocs
setting->buffer_size = setting->sample_rate * setting->sample_size;
setting->buffer = (int16 *) calloc(setting->sample_rate, setting->sample_size);
// @question Consider to move to the heap?
api_setting->internal_buffer[0].Flags = 0;
api_setting->internal_buffer[0].AudioBytes = setting->buffer_size;
api_setting->internal_buffer[0].pAudioData = (byte *) malloc(setting->buffer_size * sizeof(byte));
@ -104,13 +113,15 @@ void audio_load(HWND hwnd, AudioSetting* setting, XAudio2Setting* api_setting) {
inline
void audio_play(AudioSetting* setting, XAudio2Setting* api_setting) {
if (!api_setting->source_voice) {
// @todo Log
return;
}
api_setting->source_voice->Start(0, XAUDIO2_COMMIT_NOW);
setting->is_playing = true;
if (setting->sample_index > 1) {
setting->sample_index = 0;
}
}
inline
@ -136,8 +147,8 @@ void audio_free(AudioSetting* setting, XAudio2Setting* api_setting)
api_setting->mastering_voice->DestroyVoice();
}
if (api_setting->xaudio2) {
api_setting->xaudio2->Release();
if (api_setting->audio_handle) {
api_setting->audio_handle->Release();
}
}
@ -151,8 +162,6 @@ inline
uint32 audio_buffer_fillable(const AudioSetting* setting, const XAudio2Setting* api_setting)
{
if (!api_setting->source_voice) {
// @todo Log
return 0;
}
@ -166,29 +175,30 @@ uint32 audio_buffer_fillable(const AudioSetting* setting, const XAudio2Setting*
}
inline
void audio_play_buffer(AudioSetting* setting, XAudio2Setting* api_setting, uint32 bytes_to_write) {
if (!api_setting->source_voice) {
// @todo Log
void audio_play_buffer(AudioSetting* setting, XAudio2Setting* api_setting) {
if (!api_setting->source_voice || setting->sample_buffer_size == 0) {
return;
}
if (bytes_to_write == 0) {
return;
if (!setting->is_playing) {
audio_play(setting, api_setting);
}
uint32 idx = setting->sample_output % 2;
memcpy(
(void *) api_setting->internal_buffer[setting->sample_index].pAudioData,
(void *) api_setting->internal_buffer[idx].pAudioData,
setting->buffer,
bytes_to_write
setting->sample_buffer_size
);
if (!SUCCEEDED(api_setting->source_voice->SubmitSourceBuffer(&api_setting->internal_buffer[setting->sample_index]))) {
// @todo Log
if (!SUCCEEDED(api_setting->source_voice->SubmitSourceBuffer(&api_setting->internal_buffer[idx]))) {
LOG(log_memory, "Xaudio2: SubmitSourceBuffer failed\n", log_fp, true, true);
return;
}
setting->sample_index = (setting->sample_index + 1) % 2;
setting->sample_index += setting->sample_buffer_size / setting->sample_size;
setting->sample_buffer_size = 0;
}