sfizz/external/st_audiofile/src/st_audiofile.c

350 lines
9 KiB
C
Raw Normal View History

2020-10-07 16:41:31 +02:00
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "st_audiofile.h"
#if !defined(ST_AUDIO_FILE_USE_SNDFILE)
#include "st_audiofile_libs.h"
#include <stdlib.h>
struct st_audio_file {
int type;
union {
drwav *wav;
drflac *flac;
2020-10-31 11:59:45 +01:00
AIFF_Ref aiff;
2020-10-09 15:41:08 +02:00
drmp3 *mp3;
2020-10-09 17:29:53 +02:00
stb_vorbis* ogg;
2020-10-07 16:41:31 +02:00
};
2020-10-09 15:41:08 +02:00
union {
2020-10-31 11:59:45 +01:00
struct { uint32_t channels; float sample_rate; uint64_t frames; } aiff;
2020-10-09 15:41:08 +02:00
struct { uint64_t frames; } mp3;
2020-10-09 17:29:53 +02:00
struct { uint32_t channels; float sample_rate; uint64_t frames; } ogg;
2020-10-09 15:41:08 +02:00
} cache;
2020-10-07 16:41:31 +02:00
};
2020-10-09 18:30:26 +02:00
static st_audio_file* st_generic_open_file(const void* filename, int widepath)
2020-10-07 16:41:31 +02:00
{
2020-10-09 18:30:26 +02:00
#if !defined(_WIN32)
if (widepath)
return NULL;
#endif
2020-10-07 16:41:31 +02:00
st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file));
if (!af)
return NULL;
2020-10-09 18:30:26 +02:00
// Try WAV
{
2020-10-07 16:41:31 +02:00
af->wav = (drwav*)malloc(sizeof(drwav));
if (!af->wav) {
free(af);
return NULL;
}
2020-10-09 18:30:26 +02:00
drwav_bool32 ok =
#if defined(_WIN32)
widepath ? drwav_init_file_w(af->wav, (const wchar_t*)filename, NULL) :
#endif
drwav_init_file(af->wav, (const char*)filename, NULL);
if (!ok)
2020-10-07 16:41:31 +02:00
free(af->wav);
2020-10-09 18:30:26 +02:00
else {
2020-10-07 16:41:31 +02:00
af->type = st_audio_file_wav;
2020-10-09 18:30:26 +02:00
return af;
}
2020-10-07 16:41:31 +02:00
}
2020-10-09 18:30:26 +02:00
// Try FLAC
{
af->flac =
#if defined(_WIN32)
widepath ? drflac_open_file_w((const wchar_t*)filename, NULL) :
#endif
drflac_open_file((const char*)filename, NULL);
if (af->flac) {
2020-10-07 16:41:31 +02:00
af->type = st_audio_file_flac;
2020-10-09 18:30:26 +02:00
return af;
}
2020-10-07 16:41:31 +02:00
}
2020-10-31 11:59:45 +01:00
// Try AIFF
{
af->aiff =
#if defined(_WIN32)
widepath ? AIFF_OpenFileW((const wchar_t*)filename, F_RDONLY) :
#endif
AIFF_OpenFile((const char*)filename, F_RDONLY);
if (af->aiff) {
int channels;
double sample_rate;
uint64_t frames;
if (AIFF_GetAudioFormat(af->aiff, &frames, &channels, &sample_rate, NULL, NULL) == -1) {
AIFF_CloseFile(af->aiff);
free(af);
return NULL;
}
af->cache.aiff.channels = (uint32_t)channels;
af->cache.aiff.sample_rate = (float)sample_rate;
af->cache.aiff.frames = frames;
af->type = st_audio_file_aiff;
return af;
}
}
2020-10-09 18:30:26 +02:00
// Try OGG
{
af->ogg =
#if defined(_WIN32)
widepath ? stb_vorbis_open_filename_w((const wchar_t*)filename, NULL, NULL) :
#endif
stb_vorbis_open_filename((const char*)filename, NULL, NULL);
2020-10-09 17:29:53 +02:00
if (af->ogg) {
2020-10-09 18:30:26 +02:00
af->cache.ogg.frames = stb_vorbis_stream_length_in_samples(af->ogg);
if (af->cache.ogg.frames == 0) {
2020-10-09 17:29:53 +02:00
stb_vorbis_close(af->ogg);
2020-10-09 18:30:26 +02:00
free(af);
return NULL;
2020-10-09 17:29:53 +02:00
}
2020-10-09 18:30:26 +02:00
stb_vorbis_info info = stb_vorbis_get_info(af->ogg);
af->cache.ogg.channels = info.channels;
af->cache.ogg.sample_rate = info.sample_rate;
af->type = st_audio_file_ogg;
return af;
2020-10-09 17:29:53 +02:00
}
}
2020-10-09 18:30:26 +02:00
// Try MP3
{
2020-10-09 15:41:08 +02:00
af->mp3 = (drmp3*)malloc(sizeof(drmp3));
if (!af->mp3) {
free(af);
return NULL;
}
2020-10-09 18:30:26 +02:00
drmp3_bool32 ok =
#if defined(_WIN32)
widepath ? drmp3_init_file_w(af->mp3, (const wchar_t*)filename, NULL) :
#endif
drmp3_init_file(af->mp3, (const char*)filename, NULL);
if (!ok)
2020-10-09 15:41:08 +02:00
free(af->mp3);
2020-10-09 18:30:26 +02:00
else {
af->cache.mp3.frames = drmp3_get_pcm_frame_count(af->mp3);
if (af->cache.mp3.frames == 0) {
free(af->mp3);
free(af);
return NULL;
}
2020-10-09 15:41:08 +02:00
af->type = st_audio_file_mp3;
2020-10-09 18:30:26 +02:00
return af;
}
2020-10-09 15:41:08 +02:00
}
2020-10-09 18:30:26 +02:00
free(af);
return NULL;
}
2020-10-07 16:41:31 +02:00
2020-10-09 18:30:26 +02:00
st_audio_file* st_open_file(const char* filename)
{
return st_generic_open_file(filename, 0);
2020-10-07 16:41:31 +02:00
}
#if defined(_WIN32)
st_audio_file* st_open_file_w(const wchar_t* filename)
{
2020-10-09 18:30:26 +02:00
return st_generic_open_file(filename, 1);
2020-10-07 16:41:31 +02:00
}
#endif
void st_close(st_audio_file* af)
{
switch (af->type) {
case st_audio_file_wav:
drwav_uninit(af->wav);
free(af->wav);
break;
case st_audio_file_flac:
drflac_close(af->flac);
break;
2020-10-31 11:59:45 +01:00
case st_audio_file_aiff:
AIFF_CloseFile(af->aiff);
break;
2020-10-09 17:29:53 +02:00
case st_audio_file_ogg:
stb_vorbis_close(af->ogg);
break;
2020-10-09 15:41:08 +02:00
case st_audio_file_mp3:
drmp3_uninit(af->mp3);
free(af->mp3);
break;
2020-10-07 16:41:31 +02:00
}
free(af);
2020-10-07 16:41:31 +02:00
}
int st_get_type(st_audio_file* af)
{
return af->type;
}
uint32_t st_get_channels(st_audio_file* af)
{
uint32_t channels = 0;
switch (af->type) {
case st_audio_file_wav:
channels = af->wav->channels;
break;
case st_audio_file_flac:
channels = af->flac->channels;
break;
2020-10-31 11:59:45 +01:00
case st_audio_file_aiff:
channels = af->cache.aiff.channels;
break;
2020-10-09 17:29:53 +02:00
case st_audio_file_ogg:
channels = af->cache.ogg.channels;
break;
2020-10-09 15:41:08 +02:00
case st_audio_file_mp3:
channels = af->mp3->channels;
break;
2020-10-07 16:41:31 +02:00
}
return channels;
}
float st_get_sample_rate(st_audio_file* af)
{
float sample_rate = 0;
switch (af->type) {
case st_audio_file_wav:
sample_rate = af->wav->sampleRate;
break;
case st_audio_file_flac:
sample_rate = af->flac->sampleRate;
break;
2020-10-31 11:59:45 +01:00
case st_audio_file_aiff:
sample_rate = af->cache.aiff.sample_rate;
break;
2020-10-09 17:29:53 +02:00
case st_audio_file_ogg:
sample_rate = af->cache.ogg.sample_rate;
break;
2020-10-09 15:41:08 +02:00
case st_audio_file_mp3:
sample_rate = af->mp3->sampleRate;
break;
2020-10-07 16:41:31 +02:00
}
return sample_rate;
}
uint64_t st_get_frame_count(st_audio_file* af)
{
uint64_t frames = 0;
switch (af->type) {
case st_audio_file_wav:
frames = af->wav->totalPCMFrameCount;
break;
case st_audio_file_flac:
frames = af->flac->totalPCMFrameCount;
break;
2020-10-31 11:59:45 +01:00
case st_audio_file_aiff:
frames = af->cache.aiff.frames;
break;
2020-10-09 17:29:53 +02:00
case st_audio_file_ogg:
frames = af->cache.ogg.frames;
break;
2020-10-09 15:41:08 +02:00
case st_audio_file_mp3:
frames = af->cache.mp3.frames;
break;
2020-10-07 16:41:31 +02:00
}
return frames;
}
bool st_seek(st_audio_file* af, uint64_t frame)
{
bool success = false;
switch (af->type) {
case st_audio_file_wav:
success = drwav_seek_to_pcm_frame(af->wav, frame);
break;
case st_audio_file_flac:
success = drflac_seek_to_pcm_frame(af->flac, frame);
break;
2020-10-31 11:59:45 +01:00
case st_audio_file_aiff:
success = AIFF_Seek(af->aiff, frame) != -1;
break;
2020-10-09 17:29:53 +02:00
case st_audio_file_ogg:
success = stb_vorbis_seek(af->ogg, (unsigned)frame) != 0;
break;
2020-10-09 15:41:08 +02:00
case st_audio_file_mp3:
success = drmp3_seek_to_pcm_frame(af->mp3, frame);
break;
2020-10-07 16:41:31 +02:00
}
return success;
}
uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count)
{
switch (af->type) {
case st_audio_file_wav:
count = drwav_read_pcm_frames_s16(af->wav, count, buffer);
break;
case st_audio_file_flac:
count = drflac_read_pcm_frames_s16(af->flac, count, buffer);
break;
2020-10-31 11:59:45 +01:00
case st_audio_file_aiff:
{
uint32_t channels = af->cache.aiff.channels;
unsigned samples = AIFF_ReadSamples16Bit(af->aiff, buffer, (unsigned)(channels * count));
count = ((int)samples != -1) ? (samples / channels) : 0;
}
break;
2020-10-09 17:29:53 +02:00
case st_audio_file_ogg:
count = stb_vorbis_get_samples_short_interleaved(
af->ogg, af->cache.ogg.channels, buffer,
count * af->cache.ogg.channels);
break;
2020-10-09 15:41:08 +02:00
case st_audio_file_mp3:
count = drmp3_read_pcm_frames_s16(af->mp3, count, buffer);
break;
2020-10-07 16:41:31 +02:00
}
return count;
}
uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count)
{
switch (af->type) {
case st_audio_file_wav:
count = drwav_read_pcm_frames_f32(af->wav, count, buffer);
break;
case st_audio_file_flac:
count = drflac_read_pcm_frames_f32(af->flac, count, buffer);
break;
2020-10-31 11:59:45 +01:00
case st_audio_file_aiff:
{
uint32_t channels = af->cache.aiff.channels;
unsigned samples = AIFF_ReadSamplesFloat(af->aiff, buffer, (unsigned)(channels * count));
count = ((int)samples != -1) ? (samples / channels) : 0;
}
break;
2020-10-09 17:29:53 +02:00
case st_audio_file_ogg:
count = stb_vorbis_get_samples_float_interleaved(
af->ogg, af->cache.ogg.channels, buffer,
count * af->cache.ogg.channels);
break;
2020-10-09 15:41:08 +02:00
case st_audio_file_mp3:
count = drmp3_read_pcm_frames_f32(af->mp3, count, buffer);
break;
2020-10-07 16:41:31 +02:00
}
return count;
}
#endif // !defined(ST_AUDIO_FILE_USE_SNDFILE)