Cleanup
This commit is contained in:
@@ -7,7 +7,6 @@ let project = new Project(flags.name);
|
||||
let g5 = false;
|
||||
|
||||
project.add_cfiles("sources/kinc/*");
|
||||
project.add_cfiles("sources/kinc/threads/*");
|
||||
project.add_include_dir("sources");
|
||||
|
||||
function add_backend(name) {
|
||||
@@ -267,9 +266,6 @@ if (flags.with_audio) {
|
||||
project.add_define("KINC_A2");
|
||||
project.add_define("WITH_AUDIO");
|
||||
project.add_define("arm_audio");
|
||||
|
||||
project.add_cfiles("sources/kinc/audio1/*");
|
||||
project.add_cfiles("sources/kinc/audio2/*");
|
||||
project.add_cfiles("sources/libs/stb_vorbis.c");
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <kinc/surface.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/threads/mutex.h>
|
||||
#include <kinc/mutex.h>
|
||||
#include <kinc/video.h>
|
||||
#include <kinc/window.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <kinc/threads/mutex.h>
|
||||
#include <kinc/threads/thread.h>
|
||||
#include <kinc/mutex.h>
|
||||
#include <kinc/thread.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#include <kinc/threads/event.h>
|
||||
|
||||
void kinc_event_init(kinc_event_t *event, bool auto_clear) {
|
||||
event->impl.event = CreateEvent(0, auto_clear ? FALSE : TRUE, 0, 0);
|
||||
}
|
||||
|
||||
void kinc_event_destroy(kinc_event_t *event) {
|
||||
CloseHandle(event->impl.event);
|
||||
}
|
||||
|
||||
void kinc_event_signal(kinc_event_t *event) {
|
||||
SetEvent(event->impl.event);
|
||||
}
|
||||
|
||||
void kinc_event_wait(kinc_event_t *event) {
|
||||
WaitForSingleObject(event->impl.event, INFINITE);
|
||||
}
|
||||
|
||||
bool kinc_event_try_to_wait(kinc_event_t *event, double seconds) {
|
||||
return WaitForSingleObject(event->impl.event, (DWORD)(seconds * 1000.0)) != WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
void kinc_event_reset(kinc_event_t *event) {
|
||||
ResetEvent(event->impl.event);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
void *event;
|
||||
} kinc_event_impl_t;
|
||||
@@ -1,25 +0,0 @@
|
||||
#include <kinc/threads/fiber.h>
|
||||
|
||||
VOID WINAPI fiber_func(LPVOID param) {
|
||||
kinc_fiber_t *fiber = (kinc_fiber_t *)param;
|
||||
fiber->impl.func(fiber->impl.param);
|
||||
}
|
||||
|
||||
void kinc_fiber_init_current_thread(kinc_fiber_t *fiber) {
|
||||
fiber->impl.fiber = ConvertThreadToFiber(NULL);
|
||||
}
|
||||
|
||||
void kinc_fiber_init(kinc_fiber_t *fiber, void (*func)(void *param), void *param) {
|
||||
fiber->impl.func = func;
|
||||
fiber->impl.param = param;
|
||||
fiber->impl.fiber = CreateFiber(0, fiber_func, fiber);
|
||||
}
|
||||
|
||||
void kinc_fiber_destroy(kinc_fiber_t *fiber) {
|
||||
DeleteFiber(fiber->impl.fiber);
|
||||
fiber->impl.fiber = NULL;
|
||||
}
|
||||
|
||||
void kinc_fiber_switch(kinc_fiber_t *fiber) {
|
||||
SwitchToFiber(fiber->impl.fiber);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
void *fiber;
|
||||
void (*func)(void *param);
|
||||
void *param;
|
||||
} kinc_fiber_impl_t;
|
||||
@@ -48,9 +48,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "system_microsoft.c.h"
|
||||
#include "event.c.h"
|
||||
#include "fiber.c.h"
|
||||
#include "mutex.c.h"
|
||||
#include "semaphore.c.h"
|
||||
#include "thread.c.h"
|
||||
#include "threadlocal.c.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <kinc/threads/mutex.h>
|
||||
#include <kinc/mutex.h>
|
||||
|
||||
void kinc_mutex_init(kinc_mutex_t *mutex) {
|
||||
assert(sizeof(RTL_CRITICAL_SECTION) == sizeof(kinc_microsoft_critical_section_t));
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#include <kinc/threads/semaphore.h>
|
||||
|
||||
void kinc_semaphore_init(kinc_semaphore_t *semaphore, int current, int max) {
|
||||
semaphore->impl.handle = CreateSemaphoreA(NULL, current, max, NULL);
|
||||
}
|
||||
|
||||
void kinc_semaphore_destroy(kinc_semaphore_t *semaphore) {
|
||||
CloseHandle(semaphore->impl.handle);
|
||||
semaphore->impl.handle = NULL;
|
||||
}
|
||||
|
||||
void kinc_semaphore_release(kinc_semaphore_t *semaphore, int count) {
|
||||
ReleaseSemaphore(semaphore->impl.handle, count, NULL);
|
||||
}
|
||||
|
||||
void kinc_semaphore_acquire(kinc_semaphore_t *semaphore) {
|
||||
WaitForSingleObject(semaphore->impl.handle, INFINITE);
|
||||
}
|
||||
|
||||
bool kinc_semaphore_try_to_acquire(kinc_semaphore_t *semaphore, double seconds) {
|
||||
return WaitForSingleObject(semaphore->impl.handle, (DWORD)(seconds * 1000)) == WAIT_OBJECT_0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
void *handle;
|
||||
} kinc_semaphore_impl_t;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <kinc/threads/thread.h>
|
||||
#include <kinc/thread.h>
|
||||
|
||||
void kinc_threads_init() {}
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#include <kinc/threads/threadlocal.h>
|
||||
|
||||
void kinc_thread_local_init(kinc_thread_local_t *local) {
|
||||
local->impl.slot = TlsAlloc();
|
||||
TlsSetValue(local->impl.slot, 0);
|
||||
}
|
||||
|
||||
void kinc_thread_local_destroy(kinc_thread_local_t *local) {
|
||||
TlsFree(local->impl.slot);
|
||||
}
|
||||
|
||||
void *kinc_thread_local_get(kinc_thread_local_t *local) {
|
||||
return TlsGetValue(local->impl.slot);
|
||||
}
|
||||
|
||||
void kinc_thread_local_set(kinc_thread_local_t *local, void *data) {
|
||||
TlsSetValue(local->impl.slot, data);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
int slot;
|
||||
} kinc_thread_local_impl_t;
|
||||
@@ -1,77 +0,0 @@
|
||||
#include <kinc/threads/event.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
void kinc_event_init(kinc_event_t *event, bool auto_reset) {
|
||||
event->impl.auto_reset = auto_reset;
|
||||
event->impl.set = false;
|
||||
|
||||
pthread_cond_init(&event->impl.event, NULL);
|
||||
|
||||
// pthread_mutexattr_t attr;
|
||||
// pthread_mutexattr_init(&attr);
|
||||
// pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&event->impl.mutex, NULL); //&attr);
|
||||
}
|
||||
|
||||
void kinc_event_destroy(kinc_event_t *event) {
|
||||
pthread_cond_destroy(&event->impl.event);
|
||||
pthread_mutex_destroy(&event->impl.mutex);
|
||||
}
|
||||
|
||||
void kinc_event_signal(kinc_event_t *event) {
|
||||
pthread_mutex_lock(&event->impl.mutex);
|
||||
if (!event->impl.set) {
|
||||
event->impl.set = true;
|
||||
pthread_cond_signal(&event->impl.event);
|
||||
}
|
||||
pthread_mutex_unlock(&event->impl.mutex);
|
||||
}
|
||||
|
||||
void kinc_event_wait(kinc_event_t *event) {
|
||||
pthread_mutex_lock(&event->impl.mutex);
|
||||
while (!event->impl.set) {
|
||||
pthread_cond_wait(&event->impl.event, &event->impl.mutex);
|
||||
}
|
||||
if (event->impl.auto_reset) {
|
||||
event->impl.set = false;
|
||||
}
|
||||
pthread_mutex_unlock(&event->impl.mutex);
|
||||
}
|
||||
|
||||
bool kinc_event_try_to_wait(kinc_event_t *event, double seconds) {
|
||||
pthread_mutex_lock(&event->impl.mutex);
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
|
||||
int isec = (int)seconds;
|
||||
int usec = (int)((seconds - isec) * 1000000.0);
|
||||
struct timespec spec;
|
||||
spec.tv_nsec = (tv.tv_usec + usec) * 1000;
|
||||
if (spec.tv_nsec > 1000000000) {
|
||||
spec.tv_nsec -= 1000000000;
|
||||
isec += 1;
|
||||
}
|
||||
spec.tv_sec = tv.tv_sec + isec;
|
||||
|
||||
while (!event->impl.set) {
|
||||
int result = pthread_cond_timedwait(&event->impl.event, &event->impl.mutex, &spec);
|
||||
if (result == 0 || result == ETIMEDOUT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool result = event->impl.set;
|
||||
if (event->impl.auto_reset) {
|
||||
event->impl.set = false;
|
||||
}
|
||||
pthread_mutex_unlock(&event->impl.mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
void kinc_event_reset(kinc_event_t *event) {
|
||||
pthread_mutex_lock(&event->impl.mutex);
|
||||
event->impl.set = false;
|
||||
pthread_mutex_unlock(&event->impl.mutex);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
typedef struct {
|
||||
pthread_cond_t event;
|
||||
pthread_mutex_t mutex;
|
||||
volatile bool set;
|
||||
bool auto_reset;
|
||||
} kinc_event_impl_t;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <kinc/threads/mutex.h>
|
||||
#include <kinc/mutex.h>
|
||||
#include <assert.h>
|
||||
|
||||
void kinc_mutex_init(kinc_mutex_t *mutex) {
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
#include "event.c.h"
|
||||
#include "mutex.c.h"
|
||||
#include "semaphore.c.h"
|
||||
#include "thread.c.h"
|
||||
#include "threadlocal.c.h"
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/threads/semaphore.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
void kinc_semaphore_init(kinc_semaphore_t *semaphore, int current, int max) {
|
||||
semaphore->impl.semaphore = dispatch_semaphore_create(current);
|
||||
}
|
||||
|
||||
void kinc_semaphore_destroy(kinc_semaphore_t *semaphore) {}
|
||||
|
||||
void kinc_semaphore_release(kinc_semaphore_t *semaphore, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
dispatch_semaphore_signal(semaphore->impl.semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_semaphore_acquire(kinc_semaphore_t *semaphore) {
|
||||
dispatch_semaphore_wait(semaphore->impl.semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
bool kinc_semaphore_try_to_acquire(kinc_semaphore_t *semaphore, double seconds) {
|
||||
return dispatch_semaphore_wait(semaphore->impl.semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(seconds * 1000 * 1000 * 1000))) == 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void kinc_semaphore_init(kinc_semaphore_t *semaphore, int current, int max) {
|
||||
sem_init(&semaphore->impl.semaphore, 0, current);
|
||||
}
|
||||
|
||||
void kinc_semaphore_destroy(kinc_semaphore_t *semaphore) {
|
||||
sem_destroy(&semaphore->impl.semaphore);
|
||||
}
|
||||
|
||||
void kinc_semaphore_release(kinc_semaphore_t *semaphore, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
sem_post(&semaphore->impl.semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_semaphore_acquire(kinc_semaphore_t *semaphore) {
|
||||
sem_wait(&semaphore->impl.semaphore);
|
||||
}
|
||||
|
||||
bool kinc_semaphore_try_to_acquire(kinc_semaphore_t *semaphore, double seconds) {
|
||||
double now = kinc_time();
|
||||
do {
|
||||
if (sem_trywait(&semaphore->impl.semaphore) == 0) {
|
||||
return true;
|
||||
}
|
||||
} while (kinc_time() < now + seconds);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <dispatch/dispatch.h>
|
||||
#else
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
#ifdef __APPLE__
|
||||
dispatch_semaphore_t semaphore;
|
||||
#else
|
||||
sem_t semaphore;
|
||||
#endif
|
||||
} kinc_semaphore_impl_t;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <kinc/threads/thread.h>
|
||||
#include <kinc/thread.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#include <kinc/threads/threadlocal.h>
|
||||
|
||||
void kinc_thread_local_init(kinc_thread_local_t *local) {
|
||||
pthread_key_create(&local->impl.key, NULL);
|
||||
}
|
||||
|
||||
void kinc_thread_local_destroy(kinc_thread_local_t *local) {
|
||||
pthread_key_delete(local->impl.key);
|
||||
}
|
||||
|
||||
void *kinc_thread_local_get(kinc_thread_local_t *local) {
|
||||
return pthread_getspecific(local->impl.key);
|
||||
}
|
||||
|
||||
void kinc_thread_local_set(kinc_thread_local_t *local, void *data) {
|
||||
pthread_setspecific(local->impl.key, data);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
typedef struct {
|
||||
pthread_key_t key;
|
||||
} kinc_thread_local_impl_t;
|
||||
@@ -1,15 +0,0 @@
|
||||
#include <kinc/threads/event.h>
|
||||
|
||||
void kinc_event_init(kinc_event_t *event, bool auto_reset) {}
|
||||
|
||||
void kinc_event_destroy(kinc_event_t *event) {}
|
||||
|
||||
void kinc_event_signal(kinc_event_t *event) {}
|
||||
|
||||
void kinc_event_wait(kinc_event_t *event) {}
|
||||
|
||||
bool kinc_event_try_to_wait(kinc_event_t *event, double seconds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_event_reset(kinc_event_t *event) {}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
int nothing;
|
||||
} kinc_event_impl_t;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <kinc/threads/mutex.h>
|
||||
#include <kinc/mutex.h>
|
||||
|
||||
void kinc_mutex_init(kinc_mutex_t *mutex) {}
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include <kinc/threads/semaphore.h>
|
||||
|
||||
void kinc_semaphore_init(kinc_semaphore_t *semaphore, int current, int max) {}
|
||||
|
||||
void kinc_semaphore_destroy(kinc_semaphore_t *semaphore) {}
|
||||
|
||||
void kinc_semaphore_release(kinc_semaphore_t *semaphore, int count) {}
|
||||
|
||||
void kinc_semaphore_acquire(kinc_semaphore_t *semaphore) {}
|
||||
|
||||
bool kinc_semaphore_try_to_acquire(kinc_semaphore_t *semaphore, double seconds) {
|
||||
return false;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
int nothing;
|
||||
} kinc_semaphore_impl_t;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <kinc/threads/thread.h>
|
||||
#include <kinc/thread.h>
|
||||
|
||||
void kinc_thread_init(kinc_thread_t *t, void (*thread)(void *param), void *param) {}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#include <kinc/threads/threadlocal.h>
|
||||
#include <string.h>
|
||||
|
||||
void kinc_thread_local_init(kinc_thread_local_t *local) {}
|
||||
|
||||
void kinc_thread_local_destroy(kinc_thread_local_t *local) {}
|
||||
|
||||
void *kinc_thread_local_get(kinc_thread_local_t *local) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kinc_thread_local_set(kinc_thread_local_t *local, void *data) {}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
int nothing;
|
||||
} kinc_thread_local_impl_t;
|
||||
-3
@@ -1,11 +1,8 @@
|
||||
#include "audio.c.h"
|
||||
#include "display.c.h"
|
||||
#include "event.c.h"
|
||||
#include "mouse.c.h"
|
||||
#include "mutex.c.h"
|
||||
#include "semaphore.c.h"
|
||||
#include "system.c.h"
|
||||
#include "thread.c.h"
|
||||
#include "threadlocal.c.h"
|
||||
#include "video.c.h"
|
||||
#include "window.c.h"
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <kinc/surface.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/threads/thread.h>
|
||||
#include <kinc/thread.h>
|
||||
#include <kinc/video.h>
|
||||
#include <kinc/window.h>
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <kinc/window.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/threads/thread.h>
|
||||
#include <kinc/thread.h>
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/filereader.h>
|
||||
#include "iron_string.h"
|
||||
@@ -342,7 +342,7 @@ string_t *iron_get_arg(i32 index) {
|
||||
#include <kinc/gamepad.h>
|
||||
#include <kinc/random.h>
|
||||
#include <kinc/core.h>
|
||||
#include <kinc/threads/mutex.h>
|
||||
#include <kinc/mutex.h>
|
||||
#include <kinc/http.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
|
||||
@@ -0,0 +1,577 @@
|
||||
#include "a1.h"
|
||||
|
||||
#ifdef KINC_A1
|
||||
|
||||
#include <kinc/a2.h>
|
||||
#include <kinc/core.h>
|
||||
#include <kinc/atomic.h>
|
||||
#include <kinc/mutex.h>
|
||||
#include <kinc/video.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct kinc_a1_channel {
|
||||
kinc_a1_sound_t *sound;
|
||||
float position;
|
||||
bool loop;
|
||||
volatile float volume;
|
||||
volatile float pitch;
|
||||
};
|
||||
|
||||
struct kinc_a1_stream_channel {
|
||||
kinc_a1_sound_stream_t *stream;
|
||||
int position;
|
||||
};
|
||||
|
||||
struct kinc_internal_video_channel {
|
||||
struct kinc_internal_video_sound_stream *stream;
|
||||
int position;
|
||||
};
|
||||
|
||||
static kinc_mutex_t mutex;
|
||||
|
||||
#define CHANNEL_COUNT 16
|
||||
static kinc_a1_channel_t channels[CHANNEL_COUNT];
|
||||
static kinc_a1_stream_channel_t streamchannels[CHANNEL_COUNT];
|
||||
static kinc_internal_video_channel_t videos[CHANNEL_COUNT];
|
||||
|
||||
static float sampleLinear(int16_t *data, float position) {
|
||||
int pos1 = (int)position;
|
||||
int pos2 = (int)(position + 1);
|
||||
float sample1 = data[pos1] / 32767.0f;
|
||||
float sample2 = data[pos2] / 32767.0f;
|
||||
float a = position - pos1;
|
||||
return sample1 * (1 - a) + sample2 * a;
|
||||
}
|
||||
|
||||
static void kinc_a2_on_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata) {
|
||||
kinc_a1_mix(buffer, samples);
|
||||
}
|
||||
|
||||
void kinc_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples) {
|
||||
for (uint32_t i = 0; i < samples; ++i) {
|
||||
float left_value = 0.0f;
|
||||
float right_value = 0.0f;
|
||||
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (channels[i].sound != NULL) {
|
||||
left_value += sampleLinear(channels[i].sound->left, channels[i].position) * channels[i].volume * channels[i].sound->volume;
|
||||
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
|
||||
right_value += sampleLinear(channels[i].sound->right, channels[i].position) * channels[i].volume * channels[i].sound->volume;
|
||||
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
|
||||
|
||||
channels[i].position += channels[i].pitch / channels[i].sound->sample_rate_pos;
|
||||
// channels[i].position += 2;
|
||||
if (channels[i].position + 1 >= channels[i].sound->size) {
|
||||
if (channels[i].loop) {
|
||||
channels[i].position = 0;
|
||||
}
|
||||
else {
|
||||
channels[i].sound = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (streamchannels[i].stream != NULL) {
|
||||
float *samples = kinc_a1_sound_stream_next_frame(streamchannels[i].stream);
|
||||
left_value += samples[0] * kinc_a1_sound_stream_volume(streamchannels[i].stream);
|
||||
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
|
||||
right_value += samples[1] * kinc_a1_sound_stream_volume(streamchannels[i].stream);
|
||||
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
|
||||
if (kinc_a1_sound_stream_ended(streamchannels[i].stream)) {
|
||||
streamchannels[i].stream = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (videos[i].stream != NULL) {
|
||||
float *samples = kinc_internal_video_sound_stream_next_frame(videos[i].stream);
|
||||
left_value += samples[0];
|
||||
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
|
||||
right_value += samples[1];
|
||||
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
|
||||
if (kinc_internal_video_sound_stream_ended(videos[i].stream)) {
|
||||
videos[i].stream = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kinc_mutex_unlock(&mutex);
|
||||
|
||||
assert(buffer->channel_count >= 2);
|
||||
buffer->channels[0][buffer->write_location] = left_value;
|
||||
buffer->channels[1][buffer->write_location] = right_value;
|
||||
|
||||
buffer->write_location += 1;
|
||||
if (buffer->write_location >= buffer->data_size) {
|
||||
buffer->write_location = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_a1_init(void) {
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
channels[i].sound = NULL;
|
||||
channels[i].position = 0;
|
||||
}
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
streamchannels[i].stream = NULL;
|
||||
streamchannels[i].position = 0;
|
||||
}
|
||||
kinc_mutex_init(&mutex);
|
||||
|
||||
kinc_a2_init();
|
||||
kinc_a2_set_callback(kinc_a2_on_a1_mix, NULL);
|
||||
}
|
||||
|
||||
kinc_a1_channel_t *kinc_a1_play_sound(kinc_a1_sound_t *sound, bool loop, float pitch, bool unique) {
|
||||
kinc_a1_channel_t *channel = NULL;
|
||||
kinc_mutex_lock(&mutex);
|
||||
bool found = false;
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (channels[i].sound == sound) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found || !unique) {
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (channels[i].sound == NULL) {
|
||||
channels[i].sound = sound;
|
||||
channels[i].position = 0;
|
||||
channels[i].loop = loop;
|
||||
channels[i].pitch = pitch;
|
||||
channels[i].volume = sound->volume;
|
||||
channel = &channels[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
return channel;
|
||||
}
|
||||
|
||||
void kinc_a1_stop_sound(kinc_a1_sound_t *sound) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (channels[i].sound == sound) {
|
||||
channels[i].sound = NULL;
|
||||
channels[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void kinc_a1_play_sound_stream(kinc_a1_sound_stream_t *stream) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (streamchannels[i].stream == stream) {
|
||||
streamchannels[i].stream = NULL;
|
||||
streamchannels[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (streamchannels[i].stream == NULL) {
|
||||
streamchannels[i].stream = stream;
|
||||
streamchannels[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void kinc_a1_stop_sound_stream(kinc_a1_sound_stream_t *stream) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (streamchannels[i].stream == stream) {
|
||||
streamchannels[i].stream = NULL;
|
||||
streamchannels[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void kinc_internal_play_video_sound_stream(struct kinc_internal_video_sound_stream *stream) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (videos[i].stream == NULL) {
|
||||
videos[i].stream = stream;
|
||||
videos[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void kinc_internal_stop_video_sound_stream(struct kinc_internal_video_sound_stream *stream) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (videos[i].stream == stream) {
|
||||
videos[i].stream = NULL;
|
||||
videos[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
float kinc_a1_channel_get_volume(kinc_a1_channel_t *channel) {
|
||||
return channel->volume;
|
||||
}
|
||||
|
||||
void kinc_a1_channel_set_volume(kinc_a1_channel_t *channel, float volume) {
|
||||
KINC_ATOMIC_EXCHANGE_FLOAT(&channel->volume, volume);
|
||||
}
|
||||
|
||||
void kinc_a1_channel_set_pitch(kinc_a1_channel_t *channel, float pitch) {
|
||||
KINC_ATOMIC_EXCHANGE_FLOAT(&channel->pitch, pitch);
|
||||
}
|
||||
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include <stb_vorbis.c>
|
||||
|
||||
struct WaveData {
|
||||
uint16_t audioFormat;
|
||||
uint16_t numChannels;
|
||||
uint32_t sampleRate;
|
||||
uint32_t bytesPerSecond;
|
||||
uint16_t bitsPerSample;
|
||||
uint32_t dataSize;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
static void checkFOURCC(uint8_t **data, const char *fourcc) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
kinc_affirm(**data == fourcc[i]);
|
||||
++*data;
|
||||
}
|
||||
}
|
||||
|
||||
static void readFOURCC(uint8_t **data, char *fourcc) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
fourcc[i] = **data;
|
||||
++*data;
|
||||
}
|
||||
fourcc[4] = 0;
|
||||
}
|
||||
|
||||
static void readChunk(uint8_t **data, struct WaveData *wave) {
|
||||
char fourcc[5];
|
||||
readFOURCC(data, fourcc);
|
||||
uint32_t chunksize = kinc_read_u32le(*data);
|
||||
*data += 4;
|
||||
if (strcmp(fourcc, "fmt ") == 0) {
|
||||
wave->audioFormat = kinc_read_u16le(*data + 0);
|
||||
wave->numChannels = kinc_read_u16le(*data + 2);
|
||||
wave->sampleRate = kinc_read_u32le(*data + 4);
|
||||
wave->bytesPerSecond = kinc_read_u32le(*data + 8);
|
||||
wave->bitsPerSample = kinc_read_u16le(*data + 14);
|
||||
*data += chunksize;
|
||||
}
|
||||
else if (strcmp(fourcc, "data") == 0) {
|
||||
wave->dataSize = chunksize;
|
||||
wave->data = (uint8_t *)malloc(chunksize * sizeof(uint8_t));
|
||||
kinc_affirm(wave->data != NULL);
|
||||
memcpy(wave->data, *data, chunksize);
|
||||
*data += chunksize;
|
||||
}
|
||||
else {
|
||||
*data += chunksize;
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t convert8to16(uint8_t sample) {
|
||||
return (sample - 127) << 8;
|
||||
}
|
||||
|
||||
static void splitStereo8(uint8_t *data, int size, int16_t *left, int16_t *right) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
left[i] = convert8to16(data[i * 2 + 0]);
|
||||
right[i] = convert8to16(data[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void splitStereo16(int16_t *data, int size, int16_t *left, int16_t *right) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
left[i] = data[i * 2 + 0];
|
||||
right[i] = data[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
static void splitMono8(uint8_t *data, int size, int16_t *left, int16_t *right) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
left[i] = convert8to16(data[i]);
|
||||
right[i] = convert8to16(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void splitMono16(int16_t *data, int size, int16_t *left, int16_t *right) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
left[i] = data[i];
|
||||
right[i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
#define MAXIMUM_SOUNDS 1024
|
||||
static kinc_a1_sound_t sounds[MAXIMUM_SOUNDS] = {0};
|
||||
|
||||
static kinc_a1_sound_t *find_sound(void) {
|
||||
for (int i = 0; i < MAXIMUM_SOUNDS; ++i) {
|
||||
if (!sounds[i].in_use) {
|
||||
return &sounds[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kinc_a1_sound_t *kinc_a1_sound_create(const char *filename) {
|
||||
kinc_a1_sound_t *sound = find_sound();
|
||||
assert(sound != NULL);
|
||||
sound->in_use = true;
|
||||
sound->volume = 1.0f;
|
||||
sound->size = 0;
|
||||
sound->left = NULL;
|
||||
sound->right = NULL;
|
||||
size_t filenameLength = strlen(filename);
|
||||
uint8_t *data = NULL;
|
||||
|
||||
if (strncmp(&filename[filenameLength - 4], ".ogg", 4) == 0) {
|
||||
kinc_file_reader_t file;
|
||||
if (!kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET)) {
|
||||
sound->in_use = false;
|
||||
return NULL;
|
||||
}
|
||||
uint8_t *filedata = (uint8_t *)malloc(kinc_file_reader_size(&file));
|
||||
kinc_file_reader_read(&file, filedata, kinc_file_reader_size(&file));
|
||||
kinc_file_reader_close(&file);
|
||||
|
||||
int channels, sample_rate;
|
||||
int samples = stb_vorbis_decode_memory(filedata, (int)kinc_file_reader_size(&file), &channels, &sample_rate, (short **)&data);
|
||||
sound->channel_count = (uint8_t)channels;
|
||||
sound->samples_per_second = (uint32_t)sample_rate;
|
||||
sound->size = samples * 2 * sound->channel_count;
|
||||
sound->bits_per_sample = 16;
|
||||
free(filedata);
|
||||
}
|
||||
else if (strncmp(&filename[filenameLength - 4], ".wav", 4) == 0) {
|
||||
struct WaveData wave = {0};
|
||||
{
|
||||
kinc_file_reader_t file;
|
||||
if (!kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET)) {
|
||||
sound->in_use = false;
|
||||
return NULL;
|
||||
}
|
||||
uint8_t *filedata = (uint8_t *)malloc(kinc_file_reader_size(&file));
|
||||
kinc_file_reader_read(&file, filedata, kinc_file_reader_size(&file));
|
||||
kinc_file_reader_close(&file);
|
||||
uint8_t *data = filedata;
|
||||
|
||||
checkFOURCC(&data, "RIFF");
|
||||
uint32_t filesize = kinc_read_u32le(data);
|
||||
data += 4;
|
||||
checkFOURCC(&data, "WAVE");
|
||||
while (data + 8 - filedata < (intptr_t)filesize) {
|
||||
readChunk(&data, &wave);
|
||||
}
|
||||
|
||||
free(filedata);
|
||||
}
|
||||
|
||||
sound->bits_per_sample = (uint8_t)wave.bitsPerSample;
|
||||
sound->channel_count = (uint8_t)wave.numChannels;
|
||||
sound->samples_per_second = wave.sampleRate;
|
||||
data = wave.data;
|
||||
sound->size = wave.dataSize;
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (sound->channel_count == 1) {
|
||||
if (sound->bits_per_sample == 8) {
|
||||
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
splitMono8(data, sound->size, sound->left, sound->right);
|
||||
}
|
||||
else if (sound->bits_per_sample == 16) {
|
||||
sound->size /= 2;
|
||||
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
splitMono16((int16_t *)data, sound->size, sound->left, sound->right);
|
||||
}
|
||||
else {
|
||||
kinc_affirm(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Left and right channel are in s16 audio stream, alternating.
|
||||
if (sound->bits_per_sample == 8) {
|
||||
sound->size /= 2;
|
||||
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
splitStereo8(data, sound->size, sound->left, sound->right);
|
||||
}
|
||||
else if (sound->bits_per_sample == 16) {
|
||||
sound->size /= 4;
|
||||
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
splitStereo16((int16_t *)data, sound->size, sound->left, sound->right);
|
||||
}
|
||||
else {
|
||||
kinc_affirm(false);
|
||||
}
|
||||
}
|
||||
sound->sample_rate_pos = 44100 / (float)sound->samples_per_second;
|
||||
free(data);
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
void kinc_a1_sound_destroy(kinc_a1_sound_t *sound) {
|
||||
free(sound->left);
|
||||
free(sound->right);
|
||||
sound->left = NULL;
|
||||
sound->right = NULL;
|
||||
sound->in_use = false;
|
||||
}
|
||||
|
||||
float kinc_a1_sound_volume(kinc_a1_sound_t *sound) {
|
||||
return sound->volume;
|
||||
}
|
||||
|
||||
void kinc_a1_sound_set_volume(kinc_a1_sound_t *sound, float value) {
|
||||
sound->volume = value;
|
||||
}
|
||||
|
||||
static kinc_a1_sound_stream_t streams[256];
|
||||
static int nextStream = 0;
|
||||
static uint8_t buffer[1024 * 10];
|
||||
static int bufferIndex;
|
||||
|
||||
kinc_a1_sound_stream_t *kinc_a1_sound_stream_create(const char *filename, bool looping) {
|
||||
kinc_a1_sound_stream_t *stream = &streams[nextStream];
|
||||
stream->myLooping = looping;
|
||||
stream->myVolume = 1;
|
||||
stream->rateDecodedHack = false;
|
||||
stream->end = false;
|
||||
kinc_file_reader_t file;
|
||||
kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET);
|
||||
stream->buffer = &buffer[bufferIndex];
|
||||
bufferIndex += (int)kinc_file_reader_size(&file);
|
||||
uint8_t *filecontent = (uint8_t *)malloc(kinc_file_reader_size(&file));
|
||||
kinc_file_reader_read(&file, filecontent, kinc_file_reader_size(&file));
|
||||
kinc_file_reader_close(&file);
|
||||
memcpy(stream->buffer, filecontent, kinc_file_reader_size(&file));
|
||||
free(filecontent);
|
||||
stream->vorbis = stb_vorbis_open_memory(buffer, (int)kinc_file_reader_size(&file), NULL, NULL);
|
||||
if (stream->vorbis != NULL) {
|
||||
stb_vorbis_info info = stb_vorbis_get_info(stream->vorbis);
|
||||
stream->chans = info.channels;
|
||||
stream->rate = info.sample_rate;
|
||||
}
|
||||
else {
|
||||
stream->chans = 2;
|
||||
stream->rate = 22050;
|
||||
}
|
||||
++nextStream;
|
||||
return stream;
|
||||
}
|
||||
|
||||
int kinc_a1_sound_stream_channels(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->chans;
|
||||
}
|
||||
|
||||
int kinc_a1_sound_stream_sample_rate(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->rate;
|
||||
}
|
||||
|
||||
bool kinc_a1_sound_stream_looping(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->myLooping;
|
||||
}
|
||||
|
||||
void kinc_a1_sound_stream_set_looping(kinc_a1_sound_stream_t *stream, bool loop) {
|
||||
stream->myLooping = loop;
|
||||
}
|
||||
|
||||
float kinc_a1_sound_stream_volume(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->myVolume;
|
||||
}
|
||||
|
||||
void kinc_a1_sound_stream_set_volume(kinc_a1_sound_stream_t *stream, float value) {
|
||||
stream->myVolume = value;
|
||||
}
|
||||
|
||||
bool kinc_a1_sound_stream_ended(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->end;
|
||||
}
|
||||
|
||||
float kinc_a1_sound_stream_length(kinc_a1_sound_stream_t *stream) {
|
||||
if (stream->vorbis == NULL)
|
||||
return 0;
|
||||
return stb_vorbis_stream_length_in_seconds(stream->vorbis);
|
||||
}
|
||||
|
||||
float kinc_a1_sound_stream_position(kinc_a1_sound_stream_t *stream) {
|
||||
if (stream->vorbis == NULL)
|
||||
return 0;
|
||||
return stb_vorbis_get_sample_offset(stream->vorbis) / stb_vorbis_stream_length_in_samples(stream->vorbis) * kinc_a1_sound_stream_length(stream);
|
||||
}
|
||||
|
||||
void kinc_a1_sound_stream_reset(kinc_a1_sound_stream_t *stream) {
|
||||
if (stream->vorbis != NULL)
|
||||
stb_vorbis_seek_start(stream->vorbis);
|
||||
stream->end = false;
|
||||
stream->rateDecodedHack = false;
|
||||
}
|
||||
|
||||
float *kinc_a1_sound_stream_next_frame(kinc_a1_sound_stream_t *stream) {
|
||||
if (stream->vorbis == NULL) {
|
||||
for (int i = 0; i < stream->chans; ++i) {
|
||||
stream->samples[i] = 0;
|
||||
}
|
||||
return stream->samples;
|
||||
}
|
||||
if (stream->rate == 22050) {
|
||||
if (stream->rateDecodedHack) {
|
||||
stream->rateDecodedHack = false;
|
||||
return stream->samples;
|
||||
}
|
||||
}
|
||||
|
||||
float left, right;
|
||||
float *samples_array[2] = {&left, &right};
|
||||
int read = stb_vorbis_get_samples_float(stream->vorbis, stream->chans, samples_array, 1);
|
||||
if (read == 0) {
|
||||
if (kinc_a1_sound_stream_looping(stream)) {
|
||||
stb_vorbis_seek_start(stream->vorbis);
|
||||
stb_vorbis_get_samples_float(stream->vorbis, stream->chans, samples_array, 1);
|
||||
}
|
||||
else {
|
||||
stream->end = true;
|
||||
for (int i = 0; i < stream->chans; ++i) {
|
||||
stream->samples[i] = 0;
|
||||
}
|
||||
return stream->samples;
|
||||
}
|
||||
}
|
||||
|
||||
stream->samples[0] = samples_array[0][0];
|
||||
stream->samples[1] = samples_array[1][0];
|
||||
|
||||
stream->rateDecodedHack = true;
|
||||
return stream->samples;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef KINC_A1
|
||||
|
||||
#include <kinc/global.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*! \file audio.h
|
||||
\brief Audio1 is a high-level audio-API that lets you directly play audio-files. Depending on the target-system it either sits directly on a high-level
|
||||
system audio-API or is implemented based on Audio2.
|
||||
*/
|
||||
|
||||
struct kinc_internal_video_sound_stream;
|
||||
|
||||
struct kinc_a1_channel;
|
||||
typedef struct kinc_a1_channel kinc_a1_channel_t;
|
||||
|
||||
struct kinc_a1_stream_channel;
|
||||
typedef struct kinc_a1_stream_channel kinc_a1_stream_channel_t;
|
||||
|
||||
struct kinc_internal_video_channel;
|
||||
typedef struct kinc_internal_video_channel kinc_internal_video_channel_t;
|
||||
|
||||
void kinc_a1_init(void);
|
||||
kinc_a1_channel_t *kinc_a1_play_sound(kinc_a1_sound_t *sound, bool loop, float pitch, bool unique);
|
||||
void kinc_a1_stop_sound(kinc_a1_sound_t *sound);
|
||||
void kinc_a1_play_sound_stream(kinc_a1_sound_stream_t *stream);
|
||||
void kinc_a1_stop_sound_stream(kinc_a1_sound_stream_t *stream);
|
||||
float kinc_a1_channel_get_volume(kinc_a1_channel_t *channel);
|
||||
void kinc_a1_channel_set_volume(kinc_a1_channel_t *channel, float volume);
|
||||
void kinc_a1_channel_set_pitch(kinc_a1_channel_t *channel, float pitch);
|
||||
void kinc_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples);
|
||||
|
||||
void kinc_internal_play_video_sound_stream(struct kinc_internal_video_sound_stream *stream);
|
||||
void kinc_internal_stop_video_sound_stream(struct kinc_internal_video_sound_stream *stream);
|
||||
|
||||
typedef struct kinc_a1_sound {
|
||||
uint8_t channel_count;
|
||||
uint8_t bits_per_sample;
|
||||
uint32_t samples_per_second;
|
||||
int16_t *left;
|
||||
int16_t *right;
|
||||
int size;
|
||||
float sample_rate_pos;
|
||||
float volume;
|
||||
bool in_use;
|
||||
} kinc_a1_sound_t;
|
||||
|
||||
kinc_a1_sound_t *kinc_a1_sound_create(const char *filename);
|
||||
void kinc_a1_sound_destroy(kinc_a1_sound_t *sound);
|
||||
float kinc_a1_sound_volume(kinc_a1_sound_t *sound);
|
||||
void kinc_a1_sound_set_volume(kinc_a1_sound_t *sound, float value);
|
||||
|
||||
struct stb_vorbis;
|
||||
|
||||
typedef struct kinc_a1_sound_stream {
|
||||
struct stb_vorbis *vorbis;
|
||||
int chans;
|
||||
int rate;
|
||||
bool myLooping;
|
||||
float myVolume;
|
||||
bool rateDecodedHack;
|
||||
bool end;
|
||||
float samples[2];
|
||||
uint8_t *buffer;
|
||||
} kinc_a1_sound_stream_t;
|
||||
|
||||
kinc_a1_sound_stream_t *kinc_a1_sound_stream_create(const char *filename, bool looping);
|
||||
float *kinc_a1_sound_stream_next_frame(kinc_a1_sound_stream_t *stream);
|
||||
int kinc_a1_sound_stream_channels(kinc_a1_sound_stream_t *stream);
|
||||
int kinc_a1_sound_stream_sample_rate(kinc_a1_sound_stream_t *stream);
|
||||
bool kinc_a1_sound_stream_looping(kinc_a1_sound_stream_t *stream);
|
||||
void kinc_a1_sound_stream_set_looping(kinc_a1_sound_stream_t *stream, bool loop);
|
||||
bool kinc_a1_sound_stream_ended(kinc_a1_sound_stream_t *stream);
|
||||
float kinc_a1_sound_stream_length(kinc_a1_sound_stream_t *stream);
|
||||
float kinc_a1_sound_stream_position(kinc_a1_sound_stream_t *stream);
|
||||
void kinc_a1_sound_stream_reset(kinc_a1_sound_stream_t *stream);
|
||||
float kinc_a1_sound_stream_volume(kinc_a1_sound_stream_t *stream);
|
||||
void kinc_a1_sound_stream_set_volume(kinc_a1_sound_stream_t *stream, float value);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,3 @@
|
||||
#define KINC_IMPLEMENTATION_AUDIO2
|
||||
|
||||
#include "audio.h"
|
||||
#include "a2.h"
|
||||
@@ -37,7 +37,7 @@ void kinc_a2_internal_sample_rate_callback(void);
|
||||
|
||||
#ifdef KINC_IMPLEMENTATION
|
||||
|
||||
#include <kinc/threads/mutex.h>
|
||||
#include <kinc/mutex.h>
|
||||
#include <memory.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#include "audio.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct kinc_a1_channel {
|
||||
kinc_a1_sound_t *sound;
|
||||
float position;
|
||||
bool loop;
|
||||
volatile float volume;
|
||||
volatile float pitch;
|
||||
};
|
||||
|
||||
struct kinc_a1_stream_channel {
|
||||
kinc_a1_sound_stream_t *stream;
|
||||
int position;
|
||||
};
|
||||
|
||||
struct kinc_internal_video_channel {
|
||||
struct kinc_internal_video_sound_stream *stream;
|
||||
int position;
|
||||
};
|
||||
|
||||
#include "audio.c.h"
|
||||
#include "sound.c.h"
|
||||
#include "soundstream.c.h"
|
||||
@@ -1,220 +0,0 @@
|
||||
#include "audio.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <kinc/audio2/audio.h>
|
||||
#include <kinc/core.h>
|
||||
#include <kinc/threads/atomic.h>
|
||||
#include <kinc/threads/mutex.h>
|
||||
#include <kinc/video.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static kinc_mutex_t mutex;
|
||||
|
||||
#define CHANNEL_COUNT 16
|
||||
static kinc_a1_channel_t channels[CHANNEL_COUNT];
|
||||
static kinc_a1_stream_channel_t streamchannels[CHANNEL_COUNT];
|
||||
static kinc_internal_video_channel_t videos[CHANNEL_COUNT];
|
||||
|
||||
static float sampleLinear(int16_t *data, float position) {
|
||||
int pos1 = (int)position;
|
||||
int pos2 = (int)(position + 1);
|
||||
float sample1 = data[pos1] / 32767.0f;
|
||||
float sample2 = data[pos2] / 32767.0f;
|
||||
float a = position - pos1;
|
||||
return sample1 * (1 - a) + sample2 * a;
|
||||
}
|
||||
|
||||
static void kinc_a2_on_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata) {
|
||||
kinc_a1_mix(buffer, samples);
|
||||
}
|
||||
|
||||
void kinc_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples) {
|
||||
for (uint32_t i = 0; i < samples; ++i) {
|
||||
float left_value = 0.0f;
|
||||
float right_value = 0.0f;
|
||||
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (channels[i].sound != NULL) {
|
||||
left_value += sampleLinear(channels[i].sound->left, channels[i].position) * channels[i].volume * channels[i].sound->volume;
|
||||
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
|
||||
right_value += sampleLinear(channels[i].sound->right, channels[i].position) * channels[i].volume * channels[i].sound->volume;
|
||||
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
|
||||
|
||||
channels[i].position += channels[i].pitch / channels[i].sound->sample_rate_pos;
|
||||
// channels[i].position += 2;
|
||||
if (channels[i].position + 1 >= channels[i].sound->size) {
|
||||
if (channels[i].loop) {
|
||||
channels[i].position = 0;
|
||||
}
|
||||
else {
|
||||
channels[i].sound = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (streamchannels[i].stream != NULL) {
|
||||
float *samples = kinc_a1_sound_stream_next_frame(streamchannels[i].stream);
|
||||
left_value += samples[0] * kinc_a1_sound_stream_volume(streamchannels[i].stream);
|
||||
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
|
||||
right_value += samples[1] * kinc_a1_sound_stream_volume(streamchannels[i].stream);
|
||||
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
|
||||
if (kinc_a1_sound_stream_ended(streamchannels[i].stream)) {
|
||||
streamchannels[i].stream = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (videos[i].stream != NULL) {
|
||||
float *samples = kinc_internal_video_sound_stream_next_frame(videos[i].stream);
|
||||
left_value += samples[0];
|
||||
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
|
||||
right_value += samples[1];
|
||||
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
|
||||
if (kinc_internal_video_sound_stream_ended(videos[i].stream)) {
|
||||
videos[i].stream = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kinc_mutex_unlock(&mutex);
|
||||
|
||||
assert(buffer->channel_count >= 2);
|
||||
buffer->channels[0][buffer->write_location] = left_value;
|
||||
buffer->channels[1][buffer->write_location] = right_value;
|
||||
|
||||
buffer->write_location += 1;
|
||||
if (buffer->write_location >= buffer->data_size) {
|
||||
buffer->write_location = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_a1_init(void) {
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
channels[i].sound = NULL;
|
||||
channels[i].position = 0;
|
||||
}
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
streamchannels[i].stream = NULL;
|
||||
streamchannels[i].position = 0;
|
||||
}
|
||||
kinc_mutex_init(&mutex);
|
||||
|
||||
kinc_a2_init();
|
||||
kinc_a2_set_callback(kinc_a2_on_a1_mix, NULL);
|
||||
}
|
||||
|
||||
kinc_a1_channel_t *kinc_a1_play_sound(kinc_a1_sound_t *sound, bool loop, float pitch, bool unique) {
|
||||
kinc_a1_channel_t *channel = NULL;
|
||||
kinc_mutex_lock(&mutex);
|
||||
bool found = false;
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (channels[i].sound == sound) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found || !unique) {
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (channels[i].sound == NULL) {
|
||||
channels[i].sound = sound;
|
||||
channels[i].position = 0;
|
||||
channels[i].loop = loop;
|
||||
channels[i].pitch = pitch;
|
||||
channels[i].volume = sound->volume;
|
||||
channel = &channels[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
return channel;
|
||||
}
|
||||
|
||||
void kinc_a1_stop_sound(kinc_a1_sound_t *sound) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (channels[i].sound == sound) {
|
||||
channels[i].sound = NULL;
|
||||
channels[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void kinc_a1_play_sound_stream(kinc_a1_sound_stream_t *stream) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (streamchannels[i].stream == stream) {
|
||||
streamchannels[i].stream = NULL;
|
||||
streamchannels[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (streamchannels[i].stream == NULL) {
|
||||
streamchannels[i].stream = stream;
|
||||
streamchannels[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void kinc_a1_stop_sound_stream(kinc_a1_sound_stream_t *stream) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (streamchannels[i].stream == stream) {
|
||||
streamchannels[i].stream = NULL;
|
||||
streamchannels[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void kinc_internal_play_video_sound_stream(struct kinc_internal_video_sound_stream *stream) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (videos[i].stream == NULL) {
|
||||
videos[i].stream = stream;
|
||||
videos[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void kinc_internal_stop_video_sound_stream(struct kinc_internal_video_sound_stream *stream) {
|
||||
kinc_mutex_lock(&mutex);
|
||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
||||
if (videos[i].stream == stream) {
|
||||
videos[i].stream = NULL;
|
||||
videos[i].position = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
float kinc_a1_channel_get_volume(kinc_a1_channel_t *channel) {
|
||||
return channel->volume;
|
||||
}
|
||||
|
||||
void kinc_a1_channel_set_volume(kinc_a1_channel_t *channel, float volume) {
|
||||
KINC_ATOMIC_EXCHANGE_FLOAT(&channel->volume, volume);
|
||||
}
|
||||
|
||||
void kinc_a1_channel_set_pitch(kinc_a1_channel_t *channel, float pitch) {
|
||||
KINC_ATOMIC_EXCHANGE_FLOAT(&channel->pitch, pitch);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/global.h>
|
||||
|
||||
#include "sound.h"
|
||||
#include "soundstream.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/*! \file audio.h
|
||||
\brief Audio1 is a high-level audio-API that lets you directly play audio-files. Depending on the target-system it either sits directly on a high-level
|
||||
system audio-API or is implemented based on Audio2.
|
||||
*/
|
||||
|
||||
struct kinc_internal_video_sound_stream;
|
||||
|
||||
struct kinc_a1_channel;
|
||||
typedef struct kinc_a1_channel kinc_a1_channel_t;
|
||||
|
||||
struct kinc_a1_stream_channel;
|
||||
typedef struct kinc_a1_stream_channel kinc_a1_stream_channel_t;
|
||||
|
||||
struct kinc_internal_video_channel;
|
||||
typedef struct kinc_internal_video_channel kinc_internal_video_channel_t;
|
||||
|
||||
void kinc_a1_init(void);
|
||||
kinc_a1_channel_t *kinc_a1_play_sound(kinc_a1_sound_t *sound, bool loop, float pitch, bool unique);
|
||||
void kinc_a1_stop_sound(kinc_a1_sound_t *sound);
|
||||
void kinc_a1_play_sound_stream(kinc_a1_sound_stream_t *stream);
|
||||
void kinc_a1_stop_sound_stream(kinc_a1_sound_stream_t *stream);
|
||||
float kinc_a1_channel_get_volume(kinc_a1_channel_t *channel);
|
||||
void kinc_a1_channel_set_volume(kinc_a1_channel_t *channel, float volume);
|
||||
void kinc_a1_channel_set_pitch(kinc_a1_channel_t *channel, float pitch);
|
||||
void kinc_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples);
|
||||
|
||||
void kinc_internal_play_video_sound_stream(struct kinc_internal_video_sound_stream *stream);
|
||||
void kinc_internal_stop_video_sound_stream(struct kinc_internal_video_sound_stream *stream);
|
||||
@@ -1,224 +0,0 @@
|
||||
#include "sound.h"
|
||||
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include <stb_vorbis.c>
|
||||
|
||||
#include <kinc/audio2/audio.h>
|
||||
#include <kinc/error.h>
|
||||
#include <kinc/filereader.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
struct WaveData {
|
||||
uint16_t audioFormat;
|
||||
uint16_t numChannels;
|
||||
uint32_t sampleRate;
|
||||
uint32_t bytesPerSecond;
|
||||
uint16_t bitsPerSample;
|
||||
uint32_t dataSize;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
static void checkFOURCC(uint8_t **data, const char *fourcc) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
kinc_affirm(**data == fourcc[i]);
|
||||
++*data;
|
||||
}
|
||||
}
|
||||
|
||||
static void readFOURCC(uint8_t **data, char *fourcc) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
fourcc[i] = **data;
|
||||
++*data;
|
||||
}
|
||||
fourcc[4] = 0;
|
||||
}
|
||||
|
||||
static void readChunk(uint8_t **data, struct WaveData *wave) {
|
||||
char fourcc[5];
|
||||
readFOURCC(data, fourcc);
|
||||
uint32_t chunksize = kinc_read_u32le(*data);
|
||||
*data += 4;
|
||||
if (strcmp(fourcc, "fmt ") == 0) {
|
||||
wave->audioFormat = kinc_read_u16le(*data + 0);
|
||||
wave->numChannels = kinc_read_u16le(*data + 2);
|
||||
wave->sampleRate = kinc_read_u32le(*data + 4);
|
||||
wave->bytesPerSecond = kinc_read_u32le(*data + 8);
|
||||
wave->bitsPerSample = kinc_read_u16le(*data + 14);
|
||||
*data += chunksize;
|
||||
}
|
||||
else if (strcmp(fourcc, "data") == 0) {
|
||||
wave->dataSize = chunksize;
|
||||
wave->data = (uint8_t *)malloc(chunksize * sizeof(uint8_t));
|
||||
kinc_affirm(wave->data != NULL);
|
||||
memcpy(wave->data, *data, chunksize);
|
||||
*data += chunksize;
|
||||
}
|
||||
else {
|
||||
*data += chunksize;
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t convert8to16(uint8_t sample) {
|
||||
return (sample - 127) << 8;
|
||||
}
|
||||
|
||||
static void splitStereo8(uint8_t *data, int size, int16_t *left, int16_t *right) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
left[i] = convert8to16(data[i * 2 + 0]);
|
||||
right[i] = convert8to16(data[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void splitStereo16(int16_t *data, int size, int16_t *left, int16_t *right) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
left[i] = data[i * 2 + 0];
|
||||
right[i] = data[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
static void splitMono8(uint8_t *data, int size, int16_t *left, int16_t *right) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
left[i] = convert8to16(data[i]);
|
||||
right[i] = convert8to16(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void splitMono16(int16_t *data, int size, int16_t *left, int16_t *right) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
left[i] = data[i];
|
||||
right[i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
#define MAXIMUM_SOUNDS 1024
|
||||
static kinc_a1_sound_t sounds[MAXIMUM_SOUNDS] = {0};
|
||||
|
||||
static kinc_a1_sound_t *find_sound(void) {
|
||||
for (int i = 0; i < MAXIMUM_SOUNDS; ++i) {
|
||||
if (!sounds[i].in_use) {
|
||||
return &sounds[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kinc_a1_sound_t *kinc_a1_sound_create(const char *filename) {
|
||||
kinc_a1_sound_t *sound = find_sound();
|
||||
assert(sound != NULL);
|
||||
sound->in_use = true;
|
||||
sound->volume = 1.0f;
|
||||
sound->size = 0;
|
||||
sound->left = NULL;
|
||||
sound->right = NULL;
|
||||
size_t filenameLength = strlen(filename);
|
||||
uint8_t *data = NULL;
|
||||
|
||||
if (strncmp(&filename[filenameLength - 4], ".ogg", 4) == 0) {
|
||||
kinc_file_reader_t file;
|
||||
if (!kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET)) {
|
||||
sound->in_use = false;
|
||||
return NULL;
|
||||
}
|
||||
uint8_t *filedata = (uint8_t *)malloc(kinc_file_reader_size(&file));
|
||||
kinc_file_reader_read(&file, filedata, kinc_file_reader_size(&file));
|
||||
kinc_file_reader_close(&file);
|
||||
|
||||
int channels, sample_rate;
|
||||
int samples = stb_vorbis_decode_memory(filedata, (int)kinc_file_reader_size(&file), &channels, &sample_rate, (short **)&data);
|
||||
sound->channel_count = (uint8_t)channels;
|
||||
sound->samples_per_second = (uint32_t)sample_rate;
|
||||
sound->size = samples * 2 * sound->channel_count;
|
||||
sound->bits_per_sample = 16;
|
||||
free(filedata);
|
||||
}
|
||||
else if (strncmp(&filename[filenameLength - 4], ".wav", 4) == 0) {
|
||||
struct WaveData wave = {0};
|
||||
{
|
||||
kinc_file_reader_t file;
|
||||
if (!kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET)) {
|
||||
sound->in_use = false;
|
||||
return NULL;
|
||||
}
|
||||
uint8_t *filedata = (uint8_t *)malloc(kinc_file_reader_size(&file));
|
||||
kinc_file_reader_read(&file, filedata, kinc_file_reader_size(&file));
|
||||
kinc_file_reader_close(&file);
|
||||
uint8_t *data = filedata;
|
||||
|
||||
checkFOURCC(&data, "RIFF");
|
||||
uint32_t filesize = kinc_read_u32le(data);
|
||||
data += 4;
|
||||
checkFOURCC(&data, "WAVE");
|
||||
while (data + 8 - filedata < (intptr_t)filesize) {
|
||||
readChunk(&data, &wave);
|
||||
}
|
||||
|
||||
free(filedata);
|
||||
}
|
||||
|
||||
sound->bits_per_sample = (uint8_t)wave.bitsPerSample;
|
||||
sound->channel_count = (uint8_t)wave.numChannels;
|
||||
sound->samples_per_second = wave.sampleRate;
|
||||
data = wave.data;
|
||||
sound->size = wave.dataSize;
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (sound->channel_count == 1) {
|
||||
if (sound->bits_per_sample == 8) {
|
||||
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
splitMono8(data, sound->size, sound->left, sound->right);
|
||||
}
|
||||
else if (sound->bits_per_sample == 16) {
|
||||
sound->size /= 2;
|
||||
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
splitMono16((int16_t *)data, sound->size, sound->left, sound->right);
|
||||
}
|
||||
else {
|
||||
kinc_affirm(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Left and right channel are in s16 audio stream, alternating.
|
||||
if (sound->bits_per_sample == 8) {
|
||||
sound->size /= 2;
|
||||
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
splitStereo8(data, sound->size, sound->left, sound->right);
|
||||
}
|
||||
else if (sound->bits_per_sample == 16) {
|
||||
sound->size /= 4;
|
||||
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
|
||||
splitStereo16((int16_t *)data, sound->size, sound->left, sound->right);
|
||||
}
|
||||
else {
|
||||
kinc_affirm(false);
|
||||
}
|
||||
}
|
||||
sound->sample_rate_pos = 44100 / (float)sound->samples_per_second;
|
||||
free(data);
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
void kinc_a1_sound_destroy(kinc_a1_sound_t *sound) {
|
||||
free(sound->left);
|
||||
free(sound->right);
|
||||
sound->left = NULL;
|
||||
sound->right = NULL;
|
||||
sound->in_use = false;
|
||||
}
|
||||
|
||||
float kinc_a1_sound_volume(kinc_a1_sound_t *sound) {
|
||||
return sound->volume;
|
||||
}
|
||||
|
||||
void kinc_a1_sound_set_volume(kinc_a1_sound_t *sound, float value) {
|
||||
sound->volume = value;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/global.h>
|
||||
#include <kinc/audio2/audio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*! \file sound.h
|
||||
\brief Sounds are pre-decoded on load and therefore primarily useful for playing sound-effects.
|
||||
*/
|
||||
|
||||
typedef struct kinc_a1_sound {
|
||||
uint8_t channel_count;
|
||||
uint8_t bits_per_sample;
|
||||
uint32_t samples_per_second;
|
||||
int16_t *left;
|
||||
int16_t *right;
|
||||
int size;
|
||||
float sample_rate_pos;
|
||||
float volume;
|
||||
bool in_use;
|
||||
} kinc_a1_sound_t;
|
||||
|
||||
kinc_a1_sound_t *kinc_a1_sound_create(const char *filename);
|
||||
void kinc_a1_sound_destroy(kinc_a1_sound_t *sound);
|
||||
float kinc_a1_sound_volume(kinc_a1_sound_t *sound);
|
||||
void kinc_a1_sound_set_volume(kinc_a1_sound_t *sound, float value);
|
||||
@@ -1,128 +0,0 @@
|
||||
#include "soundstream.h"
|
||||
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include <stb_vorbis.c>
|
||||
|
||||
#include <kinc/filereader.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static kinc_a1_sound_stream_t streams[256];
|
||||
static int nextStream = 0;
|
||||
static uint8_t buffer[1024 * 10];
|
||||
static int bufferIndex;
|
||||
|
||||
kinc_a1_sound_stream_t *kinc_a1_sound_stream_create(const char *filename, bool looping) {
|
||||
kinc_a1_sound_stream_t *stream = &streams[nextStream];
|
||||
stream->myLooping = looping;
|
||||
stream->myVolume = 1;
|
||||
stream->rateDecodedHack = false;
|
||||
stream->end = false;
|
||||
kinc_file_reader_t file;
|
||||
kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET);
|
||||
stream->buffer = &buffer[bufferIndex];
|
||||
bufferIndex += (int)kinc_file_reader_size(&file);
|
||||
uint8_t *filecontent = (uint8_t *)malloc(kinc_file_reader_size(&file));
|
||||
kinc_file_reader_read(&file, filecontent, kinc_file_reader_size(&file));
|
||||
kinc_file_reader_close(&file);
|
||||
memcpy(stream->buffer, filecontent, kinc_file_reader_size(&file));
|
||||
free(filecontent);
|
||||
stream->vorbis = stb_vorbis_open_memory(buffer, (int)kinc_file_reader_size(&file), NULL, NULL);
|
||||
if (stream->vorbis != NULL) {
|
||||
stb_vorbis_info info = stb_vorbis_get_info(stream->vorbis);
|
||||
stream->chans = info.channels;
|
||||
stream->rate = info.sample_rate;
|
||||
}
|
||||
else {
|
||||
stream->chans = 2;
|
||||
stream->rate = 22050;
|
||||
}
|
||||
++nextStream;
|
||||
return stream;
|
||||
}
|
||||
|
||||
int kinc_a1_sound_stream_channels(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->chans;
|
||||
}
|
||||
|
||||
int kinc_a1_sound_stream_sample_rate(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->rate;
|
||||
}
|
||||
|
||||
bool kinc_a1_sound_stream_looping(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->myLooping;
|
||||
}
|
||||
|
||||
void kinc_a1_sound_stream_set_looping(kinc_a1_sound_stream_t *stream, bool loop) {
|
||||
stream->myLooping = loop;
|
||||
}
|
||||
|
||||
float kinc_a1_sound_stream_volume(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->myVolume;
|
||||
}
|
||||
|
||||
void kinc_a1_sound_stream_set_volume(kinc_a1_sound_stream_t *stream, float value) {
|
||||
stream->myVolume = value;
|
||||
}
|
||||
|
||||
bool kinc_a1_sound_stream_ended(kinc_a1_sound_stream_t *stream) {
|
||||
return stream->end;
|
||||
}
|
||||
|
||||
float kinc_a1_sound_stream_length(kinc_a1_sound_stream_t *stream) {
|
||||
if (stream->vorbis == NULL)
|
||||
return 0;
|
||||
return stb_vorbis_stream_length_in_seconds(stream->vorbis);
|
||||
}
|
||||
|
||||
float kinc_a1_sound_stream_position(kinc_a1_sound_stream_t *stream) {
|
||||
if (stream->vorbis == NULL)
|
||||
return 0;
|
||||
return stb_vorbis_get_sample_offset(stream->vorbis) / stb_vorbis_stream_length_in_samples(stream->vorbis) * kinc_a1_sound_stream_length(stream);
|
||||
}
|
||||
|
||||
void kinc_a1_sound_stream_reset(kinc_a1_sound_stream_t *stream) {
|
||||
if (stream->vorbis != NULL)
|
||||
stb_vorbis_seek_start(stream->vorbis);
|
||||
stream->end = false;
|
||||
stream->rateDecodedHack = false;
|
||||
}
|
||||
|
||||
float *kinc_a1_sound_stream_next_frame(kinc_a1_sound_stream_t *stream) {
|
||||
if (stream->vorbis == NULL) {
|
||||
for (int i = 0; i < stream->chans; ++i) {
|
||||
stream->samples[i] = 0;
|
||||
}
|
||||
return stream->samples;
|
||||
}
|
||||
if (stream->rate == 22050) {
|
||||
if (stream->rateDecodedHack) {
|
||||
stream->rateDecodedHack = false;
|
||||
return stream->samples;
|
||||
}
|
||||
}
|
||||
|
||||
float left, right;
|
||||
float *samples_array[2] = {&left, &right};
|
||||
int read = stb_vorbis_get_samples_float(stream->vorbis, stream->chans, samples_array, 1);
|
||||
if (read == 0) {
|
||||
if (kinc_a1_sound_stream_looping(stream)) {
|
||||
stb_vorbis_seek_start(stream->vorbis);
|
||||
stb_vorbis_get_samples_float(stream->vorbis, stream->chans, samples_array, 1);
|
||||
}
|
||||
else {
|
||||
stream->end = true;
|
||||
for (int i = 0; i < stream->chans; ++i) {
|
||||
stream->samples[i] = 0;
|
||||
}
|
||||
return stream->samples;
|
||||
}
|
||||
}
|
||||
|
||||
stream->samples[0] = samples_array[0][0];
|
||||
stream->samples[1] = samples_array[1][0];
|
||||
|
||||
stream->rateDecodedHack = true;
|
||||
return stream->samples;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/global.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*! \file soundstream.h
|
||||
\brief Sound-Streams are decoded while playing and as such are useful for large audio-files like music or speech.
|
||||
*/
|
||||
|
||||
struct stb_vorbis;
|
||||
|
||||
typedef struct kinc_a1_sound_stream {
|
||||
struct stb_vorbis *vorbis;
|
||||
int chans;
|
||||
int rate;
|
||||
bool myLooping;
|
||||
float myVolume;
|
||||
bool rateDecodedHack;
|
||||
bool end;
|
||||
float samples[2];
|
||||
uint8_t *buffer;
|
||||
} kinc_a1_sound_stream_t;
|
||||
|
||||
kinc_a1_sound_stream_t *kinc_a1_sound_stream_create(const char *filename, bool looping);
|
||||
float *kinc_a1_sound_stream_next_frame(kinc_a1_sound_stream_t *stream);
|
||||
int kinc_a1_sound_stream_channels(kinc_a1_sound_stream_t *stream);
|
||||
int kinc_a1_sound_stream_sample_rate(kinc_a1_sound_stream_t *stream);
|
||||
bool kinc_a1_sound_stream_looping(kinc_a1_sound_stream_t *stream);
|
||||
void kinc_a1_sound_stream_set_looping(kinc_a1_sound_stream_t *stream, bool loop);
|
||||
bool kinc_a1_sound_stream_ended(kinc_a1_sound_stream_t *stream);
|
||||
float kinc_a1_sound_stream_length(kinc_a1_sound_stream_t *stream);
|
||||
float kinc_a1_sound_stream_position(kinc_a1_sound_stream_t *stream);
|
||||
void kinc_a1_sound_stream_reset(kinc_a1_sound_stream_t *stream);
|
||||
float kinc_a1_sound_stream_volume(kinc_a1_sound_stream_t *stream);
|
||||
void kinc_a1_sound_stream_set_volume(kinc_a1_sound_stream_t *stream, float value);
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/global.h>
|
||||
#include <kinc/backend/event.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*! \file event.h
|
||||
\brief An event is a simple threading-object that allows a thread to wait for something to happen on another thread.
|
||||
*/
|
||||
|
||||
typedef struct kinc_event {
|
||||
kinc_event_impl_t impl;
|
||||
} kinc_event_t;
|
||||
|
||||
void kinc_event_init(kinc_event_t *event, bool auto_clear);
|
||||
void kinc_event_destroy(kinc_event_t *event);
|
||||
void kinc_event_signal(kinc_event_t *event);
|
||||
void kinc_event_wait(kinc_event_t *event);
|
||||
bool kinc_event_try_to_wait(kinc_event_t *event, double timeout);
|
||||
void kinc_event_reset(kinc_event_t *event);
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/global.h>
|
||||
#include <kinc/backend/fiber.h>
|
||||
|
||||
/*! \file fiber.h
|
||||
\brief The fiber-API is experimental and only supported on a few system.
|
||||
*/
|
||||
|
||||
typedef struct kinc_fiber {
|
||||
kinc_fiber_impl_t impl;
|
||||
} kinc_fiber_t;
|
||||
|
||||
void kinc_fiber_init_current_thread(kinc_fiber_t *fiber);
|
||||
void kinc_fiber_init(kinc_fiber_t *fiber, void (*func)(void *param), void *param);
|
||||
void kinc_fiber_destroy(kinc_fiber_t *fiber);
|
||||
void kinc_fiber_switch(kinc_fiber_t *fiber);
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/global.h>
|
||||
#include <kinc/backend/semaphore.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*! \file semaphore.h
|
||||
\brief A semaphore is a fancier version of an event that includes a counter to control how many threads are allowed to work on a task.
|
||||
*/
|
||||
|
||||
typedef struct kinc_semaphore {
|
||||
kinc_semaphore_impl_t impl;
|
||||
} kinc_semaphore_t;
|
||||
|
||||
void kinc_semaphore_init(kinc_semaphore_t *semaphore, int current, int max);
|
||||
void kinc_semaphore_destroy(kinc_semaphore_t *semaphore);
|
||||
void kinc_semaphore_release(kinc_semaphore_t *semaphore, int count);
|
||||
void kinc_semaphore_acquire(kinc_semaphore_t *semaphore);
|
||||
bool kinc_semaphore_try_to_acquire(kinc_semaphore_t *semaphore, double timeout);
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/global.h>
|
||||
#include <kinc/backend/threadlocal.h>
|
||||
|
||||
/*! \file threadlocal.h
|
||||
\brief Provides storage-slots for thread-specific data.
|
||||
*/
|
||||
|
||||
typedef struct kinc_thread_local {
|
||||
kinc_thread_local_impl_t impl;
|
||||
} kinc_thread_local_t;
|
||||
|
||||
void kinc_thread_local_init(kinc_thread_local_t *local);
|
||||
void kinc_thread_local_destroy(kinc_thread_local_t *local);
|
||||
void *kinc_thread_local_get(kinc_thread_local_t *local);
|
||||
void kinc_thread_local_set(kinc_thread_local_t *local, void *data);
|
||||
Reference in New Issue
Block a user