Skip to content

Commit

Permalink
Merge branch 'separate_audio_channels'
Browse files Browse the repository at this point in the history
  • Loading branch information
RobDangerous committed Feb 3, 2024
2 parents 81f1c87 + cba4b0c commit 52e557a
Show file tree
Hide file tree
Showing 26 changed files with 371 additions and 222 deletions.
74 changes: 44 additions & 30 deletions Backends/Audio2/DirectSound/Sources/kinc/backend/DirectSound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <dsound.h>

#include <assert.h>

namespace {
IDirectSound8 *dsound = nullptr;
IDirectSoundBuffer *dbuffer = nullptr;
Expand All @@ -19,7 +21,7 @@ namespace {
const int gap = 10 * 1024;
DWORD writePos = gap;

void (*a2_callback)(kinc_a2_buffer_t *buffer, int samples, void *userdata) = nullptr;
void (*a2_callback)(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata) = nullptr;
void *a2_userdata = nullptr;
kinc_a2_buffer_t a2_buffer;
}
Expand All @@ -36,7 +38,9 @@ void kinc_a2_init() {
a2_buffer.read_location = 0;
a2_buffer.write_location = 0;
a2_buffer.data_size = 128 * 1024;
a2_buffer.data = new uint8_t[a2_buffer.data_size];
a2_buffer.channel_count = 2;
a2_buffer.channels[0] = new float[a2_buffer.data_size];
a2_buffer.channels[1] = new float[a2_buffer.data_size];

kinc_microsoft_affirm(DirectSoundCreate8(nullptr, &dsound, nullptr));
// TODO (DK) only for the main window?
Expand All @@ -62,26 +66,34 @@ void kinc_a2_init() {
kinc_microsoft_affirm(dsound->CreateSoundBuffer(&bufferDesc, &dbuffer, nullptr));

DWORD size1;
uint8_t *buffer1;
uint8_t *buffer1 = NULL;
kinc_microsoft_affirm(dbuffer->Lock(writePos, gap, (void **)&buffer1, &size1, nullptr, nullptr, 0));
for (int i = 0; i < gap; ++i)
assert(buffer1 != NULL);
for (DWORD i = 0; i < size1; ++i) {
buffer1[i] = 0;
}
kinc_microsoft_affirm(dbuffer->Unlock(buffer1, size1, nullptr, 0));

kinc_microsoft_affirm(dbuffer->Play(0, 0, DSBPLAY_LOOPING));
}

void kinc_a2_set_callback(void (*kinc_a2_audio_callback)(kinc_a2_buffer_t *buffer, int samples, void *userdata), void *userdata) {
uint32_t kinc_a2_samples_per_second(void) {
return samplesPerSecond;
}

void kinc_a2_set_callback(void (*kinc_a2_audio_callback)(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata), void *userdata) {
a2_callback = kinc_a2_audio_callback;
a2_userdata = userdata;
}

namespace {
void copySample(uint8_t *buffer, DWORD &index) {
float value = *(float *)&a2_buffer.data[a2_buffer.read_location];
a2_buffer.read_location += 4;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
void copySample(uint8_t *buffer, DWORD &index, bool left) {
float value = *(float *)&a2_buffer.channels[left ? 0 : 1][a2_buffer.read_location];
if (!left) {
a2_buffer.read_location += 1;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
}
}
*(int16_t *)&buffer[index] = static_cast<int16_t>(value * 32767);
index += 2;
Expand All @@ -94,47 +106,49 @@ void kinc_a2_update() {
kinc_microsoft_affirm(dbuffer->GetCurrentPosition(&playPosition, &writePosition));

int dif;
if (writePos >= writePosition)
if (writePos >= writePosition) {
dif = writePos - writePosition;
else
}
else {
dif = dsize - writePosition + writePos;
}

if (dif < gap)
if (dif < gap) {
return;
}
if (writePos + gap >= dsize) {
if (playPosition >= writePos || playPosition <= gap)
if (playPosition >= writePos || playPosition <= gap) {
return;
if (writePosition >= writePos || writePosition <= gap)
}
if (writePosition >= writePos || writePosition <= gap) {
return;
}
}
else {
if (playPosition >= writePos && playPosition <= writePos + gap)
if (playPosition >= writePos && playPosition <= writePos + gap) {
return;
if (writePosition >= writePos && writePosition <= writePos + gap)
}
if (writePosition >= writePos && writePosition <= writePos + gap) {
return;
}
}

a2_callback(&a2_buffer, gap / 2, a2_userdata);
a2_callback(&a2_buffer, (uint32_t)(gap / 4), a2_userdata);

DWORD size1, size2;
uint8_t *buffer1, *buffer2;
kinc_microsoft_affirm(dbuffer->Lock(writePos, gap, (void **)&buffer1, &size1, (void **)&buffer2, &size2, 0));
DWORD size1;
uint8_t *buffer1;
kinc_microsoft_affirm(dbuffer->Lock(writePos, gap, (void **)&buffer1, &size1, NULL, NULL, 0));

for (DWORD i = 0; i < size1 - (bitsPerSample / 8 - 1);) {
copySample(buffer1, i);
copySample(buffer1, i, ((writePos + i) / 2) % 2 == 0);
}
writePos += size1;
if (buffer2 != nullptr) {
for (DWORD i = 0; i < size2 - (bitsPerSample / 8 - 1);) {
copySample(buffer2, i);
}
writePos = size2;
}

kinc_microsoft_affirm(dbuffer->Unlock(buffer1, size1, buffer2, size2));
kinc_microsoft_affirm(dbuffer->Unlock(buffer1, size1, NULL, 0));

if (writePos >= dsize)
if (writePos >= dsize) {
writePos -= dsize;
}
}

void kinc_a2_shutdown() {
Expand Down
70 changes: 45 additions & 25 deletions Backends/Audio2/WASAPI/Sources/kinc/backend/wasapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#define NOCTLMGR
#define NODEFERWINDOWPOS
#define NODRAWTEXT
//#define NOGDI
// #define NOGDI
#define NOGDICAPMASKS
#define NOHELP
#define NOICONS
Expand All @@ -28,7 +28,7 @@
#define NOMENUS
#define NOMETAFILE
#define NOMINMAX
//#define NOMSG
// #define NOMSG
#define NONLS
#define NOOPENFILE
#define NOPROFILER
Expand All @@ -40,7 +40,7 @@
#define NOSYSCOMMANDS
#define NOSYSMETRICS
#define NOTEXTMETRIC
//#define NOUSER
// #define NOUSER
#define NOVIRTUALKEYCODES
#define NOWH
#define NOWINMESSAGES
Expand All @@ -63,7 +63,7 @@ DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xD
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);

// based on the implementation in soloud and Microsoft sample code
static volatile void (*a2_callback)(kinc_a2_buffer_t *buffer, int samples, void *userdata) = NULL;
static volatile void (*a2_callback)(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata) = NULL;
static void *a2_userdata = NULL;
static kinc_a2_buffer_t a2_buffer;

Expand All @@ -77,6 +77,18 @@ static UINT32 bufferFrames;
static WAVEFORMATEX requestedFormat;
static WAVEFORMATEX *closestFormat;
static WAVEFORMATEX *format;
static uint32_t samples_per_second = 44100;
static void (*sample_rate_callback)(void *userdata) = NULL;
static void *sample_rate_callback_userdata = NULL;

uint32_t kinc_a2_samples_per_second(void) {
return samples_per_second;
}

void kinc_a2_set_sample_rate_callback(void (*kinc_a2_sample_rate_callback)(void *userdata), void *userdata) {
sample_rate_callback_userdata = userdata;
sample_rate_callback = kinc_a2_sample_rate_callback;
}

static bool initDefaultDevice() {
if (renderClient != NULL) {
Expand Down Expand Up @@ -131,10 +143,12 @@ static bool initDefaultDevice() {
return false;
}

kinc_a2_samples_per_second = format->nSamplesPerSec;
a2_buffer.format.samples_per_second = kinc_a2_samples_per_second;
a2_buffer.format.bits_per_sample = 16;
a2_buffer.format.channels = 2;
uint32_t old_samples_per_second = samples_per_second;
samples_per_second = format->nSamplesPerSec;
if (samples_per_second != old_samples_per_second && sample_rate_callback != NULL) {
sample_rate_callback(sample_rate_callback_userdata);
}
a2_buffer.channel_count = 2;

bufferFrames = 0;
kinc_microsoft_affirm(audioClient->lpVtbl->GetBufferSize(audioClient, &bufferFrames));
Expand All @@ -153,20 +167,26 @@ static bool initDefaultDevice() {
}
}

static void copyS16Sample(int16_t *buffer) {
float value = *(float *)&a2_buffer.data[a2_buffer.read_location];
a2_buffer.read_location += 4;
if (a2_buffer.read_location >= a2_buffer.data_size)
static void copyS16Sample(int16_t *left, int16_t *right) {
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
a2_buffer.read_location += 1;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
*buffer = (int16_t)(value * 32767);
}
*left = (int16_t)(left_value * 32767);
*right = (int16_t)(right_value * 32767);
}

static void copyFloatSample(float *buffer) {
float value = *(float *)&a2_buffer.data[a2_buffer.read_location];
a2_buffer.read_location += 4;
if (a2_buffer.read_location >= a2_buffer.data_size)
static void copyFloatSample(float *left, float *right) {
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
a2_buffer.read_location += 1;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
*buffer = value;
}
*left = left_value;
*right = right_value;
}

static void submitEmptyBuffer(unsigned frames) {
Expand Down Expand Up @@ -194,18 +214,16 @@ static void submitBuffer(unsigned frames) {
}

if (a2_callback != NULL) {
a2_callback(&a2_buffer, frames * 2, a2_userdata);
a2_callback(&a2_buffer, frames, a2_userdata);
memset(buffer, 0, frames * format->nBlockAlign);
if (format->wFormatTag == WAVE_FORMAT_PCM) {
for (UINT32 i = 0; i < frames; ++i) {
copyS16Sample((int16_t *)&buffer[i * format->nBlockAlign]);
copyS16Sample((int16_t *)&buffer[i * format->nBlockAlign + 2]);
copyS16Sample((int16_t *)&buffer[i * format->nBlockAlign], (int16_t *)&buffer[i * format->nBlockAlign + 2]);
}
}
else {
for (UINT32 i = 0; i < frames; ++i) {
copyFloatSample((float *)&buffer[i * format->nBlockAlign]);
copyFloatSample((float *)&buffer[i * format->nBlockAlign + 4]);
copyFloatSample((float *)&buffer[i * format->nBlockAlign], (float *)&buffer[i * format->nBlockAlign + 4]);
}
}
}
Expand Down Expand Up @@ -258,7 +276,9 @@ void kinc_a2_init() {
a2_buffer.read_location = 0;
a2_buffer.write_location = 0;
a2_buffer.data_size = 128 * 1024;
a2_buffer.data = (uint8_t *)malloc(a2_buffer.data_size);
a2_buffer.channel_count = 2;
a2_buffer.channels[0] = (float *)malloc(a2_buffer.data_size * sizeof(float));
a2_buffer.channels[1] = (float *)malloc(a2_buffer.data_size * sizeof(float));

audioProcessingDoneEvent = CreateEvent(0, FALSE, FALSE, 0);
kinc_affirm(audioProcessingDoneEvent != 0);
Expand All @@ -271,7 +291,7 @@ void kinc_a2_init() {
}
}

void kinc_a2_set_callback(void (*kinc_a2_audio_callback)(kinc_a2_buffer_t *buffer, int samples, void *userdata), void *userdata) {
void kinc_a2_set_callback(void (*kinc_a2_audio_callback)(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata), void *userdata) {
a2_callback = kinc_a2_audio_callback;
a2_userdata = userdata;
}
Expand Down
Loading

0 comments on commit 52e557a

Please sign in to comment.