add vorbis

This commit is contained in:
Nishi 2026-01-27 16:08:41 +09:00
commit feb686e155
Signed by: nishi
GPG key ID: 27EF69B208EB9343
14 changed files with 5882 additions and 26 deletions

View file

@ -78,7 +78,7 @@ int main(int argc, char** argv){
GSClientToggleSkybox(GSEngineGetClient(engine), GSTrue);
if((sound = GSSoundOpen(GSClientGetSoundEngine(GSEngineGetClient(engine)), "game:/shanghai.mp3")) != NULL){
if((sound = GSSoundOpen(GSClientGetSoundEngine(GSEngineGetClient(engine)), "game:/shanghai.ogg")) != NULL){
GSSoundToggleLoop(sound, 1);
GSSoundStart(sound);
}

5584
engine/external/stb/stb_vorbis.c generated vendored Normal file

File diff suppressed because it is too large Load diff

4
engine/external/stb/stb_vorbis.h generated vendored Normal file
View file

@ -0,0 +1,4 @@
#ifndef STB_VORBIS_IMPLEMENTATION
#define STB_VORBIS_HEADER_ONLY
#endif
#include "stb_vorbis.c"

View file

@ -8,7 +8,7 @@
extern "C" {
#endif
/* sound.c */
/* src/sound/sound.c */
GSDECL GSSound GSSoundNew(GSSoundEngine sengine);
GSDECL GSSound GSSoundOpen(GSSoundEngine sengine, const char* path);
GSDECL void GSSoundClose(GSSound sound);
@ -19,11 +19,13 @@ GSDECL void GSSoundPause(GSSound audio);
GSDECL void GSSoundLock(GSSound sound);
GSDECL void GSSoundUnlock(GSSound sound);
/* snd_xm.c */
/* you can guess where they are */
GSDECL GSSound GSSoundOpenXM(GSSoundEngine sengine, GSFile file);
/* snd_mod.c */
GSDECL GSSound GSSoundOpenMOD(GSSoundEngine sengine, GSFile file);
GSDECL GSSound GSSoundOpenMP3(GSSoundEngine sengine, GSFile file);
GSDECL GSSound GSSoundOpenFLAC(GSSoundEngine sengine, GSFile file);
GSDECL GSSound GSSoundOpenVorbis(GSSoundEngine sengine, GSFile file);
GSDECL GSSound GSSoundOpenWAV(GSSoundEngine sengine, GSFile file);
#ifdef __cplusplus
}

View file

@ -179,8 +179,11 @@ struct _GSSound {
GSFile file;
void* opaque1;
void* opaque2;
void* opaque1;
void* opaque2;
int from_samplerate;
ma_resampler_config resampler_config;
ma_resampler resampler;
GSSoundResetCallback reset;
GSSoundReadCallback read;

2
engine/src/external/stb_vorbis.c vendored Normal file
View file

@ -0,0 +1,2 @@
#define STB_VORBIS_IMPLEMENTATION
#include <stb_vorbis.h>

View file

@ -0,0 +1,50 @@
#include <GearSrc/Sound.h>
#include <GearSrc/SoundDriver.h>
#include <GearSrc/File.h>
#include <dr_flac.h>
static void snd_reset(GSSound sound) {
drflac_seek_to_pcm_frame(sound->opaque1, 0);
}
static int snd_read(GSSound sound, GSI16* out, int frame) {
return drflac_read_pcm_frames_s16(sound->opaque1, frame, out);
}
static void snd_close(GSSound sound) {
if(sound->opaque1 != NULL) {
drflac_free(sound->opaque1, NULL);
}
free(sound->opaque2);
}
GSSound GSSoundOpenFLAC(GSSoundEngine sengine, GSFile file) {
GSSound sound = GSSoundNew(sengine);
int size;
size = GSFileSize(file);
sound->opaque2 = malloc(size);
GSFileRead(file, sound->opaque2, size);
sound->reset = snd_reset;
sound->read = snd_read;
sound->close = snd_close;
if(size < 4 || memcmp(sound->opaque2, "fLaC", 4) != 0) {
GSSoundClose(sound);
return NULL;
}
if((sound->opaque1 = drflac_open_memory(sound->opaque2, size, NULL)) == NULL) {
GSSoundClose(sound);
return NULL;
}
sound->from_samplerate = ((drflac*)sound->opaque1)->sampleRate;
return sound;
}

View file

@ -42,8 +42,6 @@ GSSound GSSoundOpenMOD(GSSoundEngine sengine, GSFile file) {
GSSound sound = GSSoundNew(sengine);
int size;
GSFileSeek(file, 0);
size = GSFileSize(file);
sound->opaque2 = malloc(size);
GSFileRead(file, sound->opaque2, size);

View file

@ -0,0 +1,59 @@
#include <GearSrc/Sound.h>
#include <GearSrc/SoundDriver.h>
#include <GearSrc/File.h>
#include <dr_mp3.h>
static void snd_reset(GSSound sound) {
drmp3_seek_to_pcm_frame(sound->opaque1, 0);
}
static int snd_read(GSSound sound, GSI16* out, int frame) {
return drmp3_read_pcm_frames_s16(sound->opaque1, frame, out);
}
static void snd_close(GSSound sound) {
if(sound->opaque1 != NULL) {
drmp3_uninit(sound->opaque1);
free(sound->opaque1);
}
free(sound->opaque2);
}
GSSound GSSoundOpenMP3(GSSoundEngine sengine, GSFile file) {
GSSound sound = GSSoundNew(sengine);
int size;
unsigned char* buf;
size = GSFileSize(file);
sound->opaque2 = malloc(size);
GSFileRead(file, sound->opaque2, size);
sound->reset = snd_reset;
sound->read = snd_read;
sound->close = snd_close;
buf = sound->opaque2;
if(size > 2 && buf[0] == 0xff && (buf[1] == 0xfb || buf[1] == 0xf3 || buf[2] == 0xf2)) {
} else if(size > 3 && memcmp(buf, "ID3", 3) == 0) {
} else {
GSSoundClose(sound);
return NULL;
}
sound->opaque1 = malloc(sizeof(drmp3));
if(!drmp3_init_memory(sound->opaque1, sound->opaque2, size, NULL)) {
free(sound->opaque1);
sound->opaque1 = NULL;
GSSoundClose(sound);
return NULL;
}
sound->from_samplerate = ((drmp3*)sound->opaque1)->sampleRate;
return sound;
}

View file

@ -0,0 +1,48 @@
#include <GearSrc/Sound.h>
#include <GearSrc/SoundDriver.h>
#include <GearSrc/File.h>
#include <stb_vorbis.h>
static void snd_reset(GSSound sound) {
stb_vorbis_seek_frame(sound->opaque1, 0);
}
static int snd_read(GSSound sound, GSI16* out, int frame) {
return stb_vorbis_get_samples_short_interleaved(sound->opaque1, 2, out, frame * 2);
}
static void snd_close(GSSound sound) {
if(sound->opaque1 != NULL) {
stb_vorbis_close(sound->opaque1);
}
free(sound->opaque2);
}
GSSound GSSoundOpenVorbis(GSSoundEngine sengine, GSFile file) {
GSSound sound = GSSoundNew(sengine);
int size;
stb_vorbis_info info;
int err;
size = GSFileSize(file);
sound->opaque2 = malloc(size);
GSFileRead(file, sound->opaque2, size);
sound->reset = snd_reset;
sound->read = snd_read;
sound->close = snd_close;
if((sound->opaque1 = stb_vorbis_open_memory(sound->opaque2, size, &err, NULL)) == NULL) {
GSSoundClose(sound);
return NULL;
}
info = stb_vorbis_get_info(sound->opaque1);
sound->from_samplerate = info.sample_rate;
return sound;
}

View file

@ -0,0 +1,55 @@
#include <GearSrc/Sound.h>
#include <GearSrc/SoundDriver.h>
#include <GearSrc/File.h>
#include <dr_wav.h>
static void snd_reset(GSSound sound) {
drwav_seek_to_pcm_frame(sound->opaque1, 0);
}
static int snd_read(GSSound sound, GSI16* out, int frame) {
return drwav_read_pcm_frames_s16(sound->opaque1, frame, out);
}
static void snd_close(GSSound sound) {
if(sound->opaque1 != NULL) {
drwav_uninit(sound->opaque1);
free(sound->opaque1);
}
free(sound->opaque2);
}
GSSound GSSoundOpenWAV(GSSoundEngine sengine, GSFile file) {
GSSound sound = GSSoundNew(sengine);
int size;
size = GSFileSize(file);
sound->opaque2 = malloc(size);
GSFileRead(file, sound->opaque2, size);
sound->reset = snd_reset;
sound->read = snd_read;
sound->close = snd_close;
if(size < 4 || memcmp(sound->opaque2, "RIFF", 4) != 0) {
GSSoundClose(sound);
return NULL;
}
sound->opaque1 = malloc(sizeof(drwav));
if(!drwav_init_memory(sound->opaque1, sound->opaque2, size, NULL)) {
free(sound->opaque1);
sound->opaque1 = NULL;
GSSoundClose(sound);
return NULL;
}
sound->from_samplerate = ((drwav*)sound->opaque1)->sampleRate;
return sound;
}

View file

@ -28,8 +28,6 @@ GSSound GSSoundOpenXM(GSSoundEngine sengine, GSFile file) {
GSSound sound = GSSoundNew(sengine);
int size;
GSFileSeek(file, 0);
size = GSFileSize(file);
sound->opaque2 = malloc(size);
GSFileRead(file, sound->opaque2, size);

View file

@ -1,6 +1,7 @@
#include <GearSrc/Sound.h>
#include <GearSrc/File.h>
#include <GearSrc/SoundDriver.h>
#include <GearSrc/SoundEngine.h>
#include <GearSrc/Sound.h>
#include <GearSrc/Log.h>
@ -18,6 +19,8 @@ GSSound GSSoundNew(GSSoundEngine sengine) {
sound->paused = 1;
sound->loop = 0;
sound->from_samplerate = 0;
ma_mutex_init(&sound->mutex);
GSSoundEngineLock(sengine);
@ -27,21 +30,44 @@ GSSound GSSoundNew(GSSoundEngine sengine) {
return sound;
}
static void after(GSSound s) {
GSSoundLock(s);
if(s->from_samplerate > 0) {
s->resampler_config = ma_resampler_config_init(ma_format_s16, 2, s->from_samplerate, GSSoundDriverRate, ma_resample_algorithm_linear);
ma_resampler_init(&s->resampler_config, NULL, &s->resampler);
}
GSSoundUnlock(s);
}
typedef struct pair {
const char* name;
GSSound (*callback)(GSSoundEngine sengine, GSFile file);
} pair_t;
GSSound GSSoundOpen(GSSoundEngine sengine, const char* path) {
GSSound s;
GSFile f;
int i;
pair_t formats[] = {
{"XM", GSSoundOpenXM}, /**/
{"MOD", GSSoundOpenMOD}, /**/
{"MP3", GSSoundOpenMP3}, /**/
{"FLAC", GSSoundOpenFLAC}, /**/
{"Vorbis", GSSoundOpenVorbis}, /**/
{"WAV", GSSoundOpenWAV} /**/
};
if((f = GSFileOpen(sengine->engine, path)) == NULL) return NULL;
if((s = GSSoundOpenXM(sengine, f)) != NULL) {
s->file = f;
GSLog(sengine->engine, GSLogInfo, "%s: Opened as XM", path);
return s;
}
if((s = GSSoundOpenMOD(sengine, f)) != NULL) {
s->file = f;
GSLog(sengine->engine, GSLogInfo, "%s: Opened as MOD", path);
return s;
for(i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
GSFileSeek(f, 0);
if((s = formats[i].callback(sengine, f)) != NULL) {
s->file = f;
GSLog(sengine->engine, GSLogInfo, "%s: Opened as %s", path, formats[i].name);
after(s);
return s;
}
}
GSLog(sengine->engine, GSLogError, "%s: Unrecognized format", path);
@ -70,6 +96,8 @@ void GSSoundClose(GSSound sound) {
if(sound->file != NULL) GSFileClose(sound->file);
if(sound->from_samplerate > 0) ma_resampler_uninit(&sound->resampler, NULL);
free(sound);
}

View file

@ -11,13 +11,14 @@ static void read_callback(void* opaque, GSI16* out, int frame) {
GSSoundEngine sengine = opaque;
int i;
GSNumber* buffer = malloc(sizeof(*buffer) * frame * 2);
GSI16* result = malloc(sizeof(*result) * frame * 2);
for(i = 0; i < frame * 2; i++) buffer[i] = 0;
GSSoundEngineLock(sengine);
for(i = 0; i < arrlen(sengine->sound); i++) {
int s;
int s, f;
GSI16* result;
GSI16* result2;
GSSoundLock(sengine->sound[i]);
if(sengine->sound[i]->paused || sengine->sound[i]->read == NULL) {
@ -25,23 +26,47 @@ static void read_callback(void* opaque, GSI16* out, int frame) {
continue;
}
memset(result, 0, sizeof(*result) * frame * 2);
s = sengine->sound[i]->read(sengine->sound[i], result, frame);
if(sengine->sound[i]->from_samplerate > 0) {
f = frame * sengine->sound[i]->from_samplerate / GSSoundDriverRate;
} else {
f = frame;
}
result = malloc(sizeof(*result) * f * 2);
memset(result, 0, sizeof(*result) * f * 2);
s = sengine->sound[i]->read(sengine->sound[i], result, f);
if(s > 0) {
int j;
for(j = 0; j < s * 2; j++) buffer[j] += (GSNumber)result[j] / 32767;
if(sengine->sound[i]->from_samplerate > 0) {
ma_uint64 fin = f;
ma_uint64 fout = frame;
result2 = malloc(sizeof(*result2) * frame * 2);
memset(result2, 0, sizeof(*result2) * frame * 2);
ma_resampler_process_pcm_frames(&sengine->sound[i]->resampler, result, &fin, result2, &fout);
s = s * GSSoundDriverRate / sengine->sound[i]->from_samplerate;
} else {
result2 = result;
}
for(j = 0; j < s * 2; j++) buffer[j] += (GSNumber)result2[j] / 32767;
if(result2 != result) free(result2);
} else if(sengine->sound[i]->loop && sengine->sound[i]->reset != NULL) {
sengine->sound[i]->reset(sengine->sound[i]);
} else {
sengine->sound[i]->paused = GSTrue;
}
free(result);
GSSoundUnlock(sengine->sound[i]);
}
GSSoundEngineUnlock(sengine);
for(i = 0; i < frame * 2; i++) out[i] = buffer[i] * 32767;
free(result);
free(buffer);
}