Skip to content

Commit

Permalink
Parse <sample> with base64 data
Browse files Browse the repository at this point in the history
Also added the necessary plumbing to load from RAM
It's missing AIFF, and metadata reading since those API
are heavily file-based for now.
  • Loading branch information
paulfd committed Nov 21, 2021
1 parent 2aab560 commit 252a50f
Show file tree
Hide file tree
Showing 11 changed files with 456 additions and 61 deletions.
105 changes: 105 additions & 0 deletions external/st_audiofile/src/st_audiofile.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,111 @@ static st_audio_file* st_generic_open_file(const void* filename, int widepath)
return NULL;
}

st_audio_file* st_open_memory(const void* memory, size_t length)
{
st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file));
if (!af)
return NULL;

// Try WAV
{
af->wav = (drwav*)malloc(sizeof(drwav));
if (!af->wav) {
free(af);
return NULL;
}
drwav_bool32 ok =
drwav_init_memory(af->wav, memory, length, NULL);
if (!ok)
free(af->wav);
else {
af->type = st_audio_file_wav;
return af;
}
}

// Try FLAC
{
af->flac =
drflac_open_memory(memory, length, NULL);
if (af->flac) {
af->type = st_audio_file_flac;
return af;
}
}

// Try OGG
{
int err = 0;
char* alloc_buffer = NULL;
int alloc_size = 0;
const int alloc_max_size = 16 * 1024 * 1024;

af->alloc.ogg.alloc_buffer = NULL;
af->alloc.ogg.alloc_buffer_length_in_bytes = 0;

int try_again;
do {
af->ogg =
stb_vorbis_open_memory(memory, length, &err, &af->alloc.ogg);
try_again = 0;
if (!af->ogg && err == VORBIS_outofmem) {
int next_size = alloc_size ? (int)(alloc_size * 3L / 2) : (128 * 1024);
if (next_size <= alloc_max_size) {
free(alloc_buffer);
alloc_size = next_size;
alloc_buffer = (char*)malloc(alloc_size);
af->alloc.ogg.alloc_buffer = alloc_buffer;
af->alloc.ogg.alloc_buffer_length_in_bytes = alloc_size;
try_again = alloc_buffer != NULL;
}
}
} while (try_again);

if (!af->ogg)
free(alloc_buffer);
else {
af->cache.ogg.frames = stb_vorbis_stream_length_in_samples(af->ogg);
if (af->cache.ogg.frames == 0) {
stb_vorbis_close(af->ogg);
free(alloc_buffer);
free(af);
return NULL;
}
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;
}
}

// Try MP3
{
af->mp3 = (drmp3*)malloc(sizeof(drmp3));
if (!af->mp3) {
free(af);
return NULL;
}
drmp3_bool32 ok = drmp3_init_memory(af->mp3, memory, length, NULL);
if (!ok)
free(af->mp3);
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;
}
af->type = st_audio_file_mp3;
return af;
}
}

free(af);
return NULL;
}

st_audio_file* st_open_file(const char* filename)
{
return st_generic_open_file(filename, 0);
Expand Down
2 changes: 2 additions & 0 deletions external/st_audiofile/src/st_audiofile.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#if defined(_WIN32)
#include <wchar.h>
#endif
Expand All @@ -33,6 +34,7 @@ typedef enum st_audio_file_type {
st_audio_file_other,
} st_audio_file_type;

st_audio_file* st_open_memory(const void* memory, size_t length);
st_audio_file* st_open_file(const char* filename);
#if defined(_WIN32)
st_audio_file* st_open_file_w(const wchar_t* filename);
Expand Down
8 changes: 8 additions & 0 deletions external/st_audiofile/src/st_audiofile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class ST_AudioFile {
#if defined(_WIN32)
bool open_file_w(const wchar_t* filename);
#endif
bool open_memory(const void* memory, size_t length);

int get_type() const noexcept;
const char* get_type_string() const noexcept;
Expand Down Expand Up @@ -96,6 +97,13 @@ bool ST_AudioFile::open_file(const char* filename)
reset(new_af);
return new_af != nullptr;
}

bool ST_AudioFile::open_memory(const void* memory, size_t length)
{
st_audio_file* new_af = st_open_memory(memory, length);
reset(new_af);
return new_af != nullptr;
}
#if defined(_WIN32)
inline bool ST_AudioFile::open_file_w(const wchar_t* filename)
{
Expand Down
54 changes: 32 additions & 22 deletions src/sfizz/AudioReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@ namespace sfz {

class BasicSndfileReader : public AudioReader {
public:
explicit BasicSndfileReader(ST_AudioFile handle) : handle_(std::move(handle)) {}
explicit BasicSndfileReader(ST_AudioFile handle, fs::path path)
: handle_(std::move(handle)), path_(std::move(path)) {}
virtual ~BasicSndfileReader() {}

int format() const override;
int64_t frames() const override;
unsigned channels() const override;
unsigned sampleRate() const override;
bool getInstrument(InstrumentInfo* instrument) override;

const fs::path& getPath() const override { return path_; }
protected:
ST_AudioFile handle_;
fs::path path_;
};

int BasicSndfileReader::format() const
Expand Down Expand Up @@ -69,13 +71,13 @@ bool BasicSndfileReader::getInstrument(InstrumentInfo* instrument)
*/
class ForwardReader : public BasicSndfileReader {
public:
explicit ForwardReader(ST_AudioFile handle);
explicit ForwardReader(ST_AudioFile handle, fs::path path);
AudioReaderType type() const override;
size_t readNextBlock(float* buffer, size_t frames) override;
};

ForwardReader::ForwardReader(ST_AudioFile handle)
: BasicSndfileReader(std::move(handle))
ForwardReader::ForwardReader(ST_AudioFile handle, fs::path path)
: BasicSndfileReader(std::move(handle), std::move(path))
{
}

Expand Down Expand Up @@ -138,16 +140,16 @@ static void reverse_frames(float* data, size_t frames, unsigned channels)
*/
class ReverseReader : public BasicSndfileReader {
public:
explicit ReverseReader(ST_AudioFile handle);
explicit ReverseReader(ST_AudioFile handle, fs::path path);
AudioReaderType type() const override;
size_t readNextBlock(float* buffer, size_t frames) override;

private:
uint64_t position_ {};
};

ReverseReader::ReverseReader(ST_AudioFile handle)
: BasicSndfileReader(std::move(handle))
ReverseReader::ReverseReader(ST_AudioFile handle, fs::path path)
: BasicSndfileReader(std::move(handle), std::move(path))
{
position_ = handle_.get_frame_count();
}
Expand Down Expand Up @@ -183,7 +185,7 @@ size_t ReverseReader::readNextBlock(float* buffer, size_t frames)
*/
class NoSeekReverseReader : public BasicSndfileReader {
public:
explicit NoSeekReverseReader(ST_AudioFile handle);
explicit NoSeekReverseReader(ST_AudioFile handle, fs::path path);
AudioReaderType type() const override;
size_t readNextBlock(float* buffer, size_t frames) override;

Expand All @@ -195,8 +197,8 @@ class NoSeekReverseReader : public BasicSndfileReader {
uint64_t fileFramesLeft_ { 0 };
};

NoSeekReverseReader::NoSeekReverseReader(ST_AudioFile handle)
: BasicSndfileReader(std::move(handle))
NoSeekReverseReader::NoSeekReverseReader(ST_AudioFile handle, fs::path path)
: BasicSndfileReader(std::move(handle), std::move(path))
{
}

Expand Down Expand Up @@ -281,6 +283,7 @@ const std::error_category& undetailed_category()
}

//------------------------------------------------------------------------------
static fs::path emptyPath_ {};

class DummyAudioReader : public AudioReader {
public:
Expand All @@ -292,7 +295,7 @@ class DummyAudioReader : public AudioReader {
unsigned sampleRate() const override { return 44100; }
size_t readNextBlock(float*, size_t) override { return 0; }
bool getInstrument(InstrumentInfo* ) override { return false; }

const fs::path& getPath() const override { return emptyPath_; }
private:
AudioReaderType type_ {};
};
Expand Down Expand Up @@ -334,7 +337,7 @@ static bool formatHasFastSeeking(int format)
}
#endif

static AudioReaderPtr createAudioReaderWithHandle(ST_AudioFile handle, bool reverse, std::error_code* ec)
static AudioReaderPtr createAudioReaderWithHandle(ST_AudioFile handle, const fs::path& path, bool reverse, std::error_code* ec)
{
AudioReaderPtr reader;

Expand All @@ -347,17 +350,17 @@ static AudioReaderPtr createAudioReaderWithHandle(ST_AudioFile handle, bool reve
reader.reset(new DummyAudioReader(reverse ? AudioReaderType::Reverse : AudioReaderType::Forward));
}
else if (!reverse)
reader.reset(new ForwardReader(std::move(handle)));
reader.reset(new ForwardReader(std::move(handle), path));
else {
#if defined(SFIZZ_USE_SNDFILE)
bool hasFastSeeking = formatHasFastSeeking(handle.get_sndfile_format());
#else
bool hasFastSeeking = true;
#endif
if (hasFastSeeking)
reader.reset(new ReverseReader(std::move(handle)));
reader.reset(new ReverseReader(std::move(handle), path));
else
reader.reset(new NoSeekReverseReader(std::move(handle)));
reader.reset(new NoSeekReverseReader(std::move(handle), path));
}

return reader;
Expand All @@ -371,10 +374,17 @@ AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_
#else
handle.open_file(path.c_str());
#endif
return createAudioReaderWithHandle(std::move(handle), reverse, ec);
return createAudioReaderWithHandle(std::move(handle), path, reverse, ec);
}

AudioReaderPtr createAudioReaderFromMemory(const void* memory, size_t length, bool reverse, std::error_code* ec)
{
ST_AudioFile handle;
handle.open_memory(memory, length);
return createAudioReaderWithHandle(std::move(handle), {}, reverse, ec);
}

static AudioReaderPtr createExplicitAudioReaderWithHandle(ST_AudioFile handle, AudioReaderType type, std::error_code* ec)
static AudioReaderPtr createExplicitAudioReaderWithHandle(ST_AudioFile handle, const fs::path& path, AudioReaderType type, std::error_code* ec)
{
AudioReaderPtr reader;

Expand All @@ -389,13 +399,13 @@ static AudioReaderPtr createExplicitAudioReaderWithHandle(ST_AudioFile handle, A
else {
switch (type) {
case AudioReaderType::Forward:
reader.reset(new ForwardReader(std::move(handle)));
reader.reset(new ForwardReader(std::move(handle), path));
break;
case AudioReaderType::Reverse:
reader.reset(new ReverseReader(std::move(handle)));
reader.reset(new ReverseReader(std::move(handle), path));
break;
case AudioReaderType::NoSeekReverse:
reader.reset(new NoSeekReverseReader(std::move(handle)));
reader.reset(new NoSeekReverseReader(std::move(handle), path));
break;
}
}
Expand All @@ -411,7 +421,7 @@ AudioReaderPtr createExplicitAudioReader(const fs::path& path, AudioReaderType t
#else
handle.open_file(path.c_str());
#endif
return createExplicitAudioReaderWithHandle(std::move(handle), type, ec);
return createExplicitAudioReaderWithHandle(std::move(handle), path, type, ec);
}

} // namespace sfz
6 changes: 6 additions & 0 deletions src/sfizz/AudioReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class AudioReader {
virtual unsigned sampleRate() const = 0;
virtual size_t readNextBlock(float* buffer, size_t frames) = 0;
virtual bool getInstrument(InstrumentInfo* instrument) = 0;
virtual const fs::path& getPath() const = 0;
};

typedef std::unique_ptr<AudioReader> AudioReaderPtr;
Expand All @@ -49,6 +50,11 @@ typedef std::unique_ptr<AudioReader> AudioReaderPtr;
*/
AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_code* ec = nullptr);

/**
* @brief Create a memory reader of detected type.
*/
AudioReaderPtr createAudioReaderFromMemory(const void* memory, size_t length, bool reverse, std::error_code* ec = nullptr);

/**
* @brief Create a file reader of explicit type. (for testing purposes)
*/
Expand Down
Loading

0 comments on commit 252a50f

Please sign in to comment.