Skip to content

Commit

Permalink
sound stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
ThePlank committed May 6, 2024
1 parent 00b5a93 commit 473b4e5
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 11 deletions.
13 changes: 4 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
cmake_minimum_required(VERSION 3.1.3 FATAL_ERROR)

project(lemons C)

Expand All @@ -7,13 +7,8 @@ if(MSVC)
endif()


if(CMAKE_VERSION VERSION_LESS "3.1")
set(CMAKE_C_FLAGS "-std=c11 ${CMAKE_C_FLAGS}")
else()
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
endif()

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

set(OUTPUT_DIR ${CMAKE_SOURCE_DIR}/out)
set(ARCHIVE_DIR ${CMAKE_SOURCE_DIR}/archive)
Expand All @@ -34,6 +29,7 @@ add_subdirectory(lib/)
message(STATUS "building lemons...")
set(LEMONS_SRC
src/image.c
src/sound.c
src/openal.c
src/global.h
)
Expand All @@ -52,7 +48,6 @@ target_include_directories(liblemons PUBLIC lib/include/)
target_link_libraries(liblemons OpenAL)


set_target_properties(liblemons PROPERTIES LINKER_LANGUAGE C)
set_target_properties(liblemons PROPERTIES LINKER_LANGUAGE C)
set_target_properties(liblemons PROPERTIES OUTPUT_NAME lemons PREFIX "" SUFFIX .hdll)

150 changes: 150 additions & 0 deletions src/sound.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#include "global.h"

#include <stb_vorbis.c>

#define DR_FLAC_IMPLEMENTATION
#include <dr_flac.h>

#define FUNC_NAME(n) HL_NAME(sound_##n)


typedef struct _LemonsSound LemonsSound;
struct _LemonsSound {
void (*finalize)(LemonsSound*);
void (*seek)(LemonsSound*, int);
varray* (*getComments)(LemonsSound*);
int (*read)(LemonsSound*, char*, int);
int sampleRate;
int channels;
void* handle;
};


//////////////////////////////////////////////////////////////////////////////////////////
// ogg specific functions

static varray* comments_ogg(LemonsSound* sound) {
stb_vorbis* vorbius = (stb_vorbis*)sound->handle;
stb_vorbis_comment commentStruct = stb_vorbis_get_comment(vorbius);

varray* array = hl_alloc_array(&hlt_bytes, commentStruct.comment_list_length);

for (int i = 0; i < commentStruct.comment_list_length; i++) {
int size = sizeof(char*) * (strlen(commentStruct.comment_list[i]) + 1);
hl_aptr(array, vbyte*)[i] = hl_copy_bytes((vbyte*)commentStruct.comment_list[i], size);
}

return array;
}

static void seek_ogg(LemonsSound* sound, int sample) {
stb_vorbis_seek((stb_vorbis*)sound->handle, sample);
}

// not sure if this function works, testing needed but i dont really have any way of doing that rn
static int read_ogg(LemonsSound* sound, char* out, int length) {
return stb_vorbis_get_samples_short_interleaved((stb_vorbis*)sound->handle, sound->channels, (short*)out, length * sound->channels);
}

static void finalize_ogg(LemonsSound* sound) {
stb_vorbis_close((stb_vorbis*)sound->handle);
sound->handle = NULL;
sound->channels = 0;
sound->sampleRate = 0;
}

HL_PRIM LemonsSound* FUNC_NAME(create_from_ogg)(vbyte* data, int length) {
LemonsSound* sound = (LemonsSound*)hl_gc_alloc_finalizer(sizeof(LemonsSound));
sound->finalize = finalize_ogg;

int error = 0;

stb_vorbis* soundThing = stb_vorbis_open_memory(data, length, &error, NULL);
sound->handle = (void*)&*soundThing; // this looks fucking stupid but it works

if (error > 0) {
hl_fatal1("vorbis open error!!!!! error code: %d", error);
return NULL;
}

stb_vorbis_info info = stb_vorbis_get_info(soundThing);
sound->sampleRate = (int)info.sample_rate;
sound->channels = info.channels;

stb_vorbis_seek_start(soundThing);

sound->seek = seek_ogg;
sound->read = read_ogg;
sound->getComments = comments_ogg;

return sound;
}

//////////////////////////////////////////////////////////////////////////////////////////
// flac specific functions

// todo: metadata stuff for getting comments

static void finalize_flac(LemonsSound* sound) {
drflac_close((drflac*)sound->handle);
sound->handle = NULL;
sound->channels = 0;
sound->sampleRate = 0;
}

static void seek_flac(LemonsSound* sound, int sample) {
drflac_seek_to_pcm_frame((drflac*)sound->handle, sample);
}

static int read_flac(LemonsSound* sound, char* out, int length) {
return drflac_read_pcm_frames_s16((drflac*)sound->handle, length * sound->channels, (short*)out);
}

static int flac_metadata(void* pUserData, drflac_metadata* pMetadata) {
}

HL_PRIM LemonsSound* FUNC_NAME(create_from_flac)(vbyte* data, int length) {
LemonsSound* sound = (LemonsSound*)hl_gc_alloc_finalizer(sizeof(LemonsSound));
sound->finalize = finalize_flac;

drflac* soundThing = drflac_open_memory_with_metadata(data, length, flac_metadata, NULL, NULL);
sound->handle = (void*)&*soundThing;

sound->sampleRate = soundThing->sampleRate;
sound->channels = soundThing->channels;

sound->seek = seek_flac;
sound->read = read_flac;

return sound;
}

//////////////////////////////////////////////////////////////////////////////////////////
// getter stuff


HL_PRIM void FUNC_NAME(seek)(LemonsSound* sound, int sample) {
sound->seek(sound, sample);
}

HL_PRIM int FUNC_NAME(read)(LemonsSound* sound, vbyte* out, int length) {
return sound->read(sound, out, length);
}

HL_PRIM void FUNC_NAME(get_data)(LemonsSound* sound, int* sampleRate, int* channels) {
*sampleRate = sound->sampleRate;
*channels = sound->channels;
}

HL_PRIM varray* FUNC_NAME(get_comments)(LemonsSound* sound) {
return sound->getComments(sound);
}

#define _SOUND _ABSTRACT(LemonsSound*)

DEFINE_PRIM(_SOUND, sound_create_from_ogg, _BYTES _I32);
DEFINE_PRIM(_SOUND, sound_create_from_flac, _BYTES _I32);
DEFINE_PRIM(_VOID, sound_seek, _SOUND _I32);
DEFINE_PRIM(_I32, sound_read, _SOUND _BYTES _I32);
DEFINE_PRIM(_VOID, sound_get_data, _SOUND _REF(_I32) _REF(_I32));
DEFINE_PRIM(_ARR, sound_get_comments, _SOUND);
3 changes: 2 additions & 1 deletion tests/RunAll.hx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ class RunAll {
trace('hai');
var runner = new Runner();
runner.addCase(new tests.TestImage());
// runner.addCase(new TestCase2());
runner.addCase(new tests.TestSound());
Report.create(runner);

runner.run();
}
}
Binary file added tests/res/flacTest.flac
Binary file not shown.
Binary file added tests/res/vorbisTest.ogg
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/tests/TestImage.hx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class TestImage extends utest.Test {
var channels = 0;
getImageInfo(image, width, height, channels);

Assert.isFalse(width == 128, 'failed to get image width');
Assert.isFalse(width == 128, 'failed to get image width'); // for some reason these return false, maybe hl.Ref doesent like getting compared?
Assert.isFalse(height == 128, 'failed to get image height');
Assert.isFalse(channels == 4, 'failed to get channel count');
}
Expand Down
43 changes: 43 additions & 0 deletions tests/tests/TestSound.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package tests;

import utest.Assert;
import utest.Async;

typedef SoundThing = hl.Abstract<"LemonsSound*">;

class TestSound extends utest.Test {
var sound:SoundThing;

public function setup() {
var soundData = sys.io.File.getBytes('../res/vorbisTest.ogg');
sound = createFromOgg(soundData, soundData.length);
}

public function testOggRead() {
var sampleRate = 0;
var channels = 0;
soundGetData(sound, sampleRate, channels);

Assert.equals(44100, sampleRate, 'failed to get sample rate');
Assert.equals(2, channels, 'failed to get channel count');

var expectedOutput:Array<String> = ['ARTIST=plankdev', 'ENCODER=FL Studio', 'TITLE=PASSPO~4.MID [Passport Please S-YXG2006LE Rearrange]'];
var output:Array<String> = [];

var arr:hl.NativeArray<hl.Bytes> = soundGetComments(sound);
for (val in arr) output.push(@:privateAccess String.fromUTF8(val));

Assert.same(expectedOutput, output, false, 'failed to get ogg comments');
}

public function teardown() {
sound = null;
}

@:hlNative("lemons", "sound_create_from_ogg") static function createFromOgg(bytes:hl.Bytes, length:Int):SoundThing {return null;}
@:hlNative("lemons", "sound_seek") static function soundSeek(snd:SoundThing, pos:Int):Void {}
@:hlNative("lemons", "sound_read") static function soundRead(snd:SoundThing, out:hl.Bytes, length:Int):Int { return 0; }
@:hlNative("lemons", "sound_get_data") static function soundGetData(snd:SoundThing, sampleRate:hl.Ref<Int>, channels:hl.Ref<Int>):Void {}
@:hlNative("lemons", "sound_get_comments") static function soundGetComments(snd:SoundThing):hl.NativeArray<hl.Bytes> { return null; }
}

0 comments on commit 473b4e5

Please sign in to comment.