Merge pull request #482 from jpcima/st-audiofile

Audio file reader without sndfile
This commit is contained in:
JP Cimalando 2020-10-28 17:08:00 +01:00 committed by GitHub
commit 401e0a4e21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1072 additions and 128 deletions

8
.gitmodules vendored
View file

@ -19,3 +19,11 @@
path = editor/external/vstgui4
url = https://github.com/sfztools/vstgui.git
shallow = true
[submodule "external/st_audiofile/thirdparty/dr_libs"]
path = external/st_audiofile/thirdparty/dr_libs
url = https://github.com/mackron/dr_libs.git
shallow = true
[submodule "external/st_audiofile/thirdparty/stb_vorbis"]
path = external/st_audiofile/thirdparty/stb_vorbis
url = https://github.com/sfztools/stb_vorbis.git
shallow = true

View file

@ -29,6 +29,7 @@ option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF)
option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF)
option (SFIZZ_DEVTOOLS "Enable developer tools build [default: OFF]" OFF)
option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON)
option (SFIZZ_USE_SNDFILE "Enable use of the sndfile library [default: ON]" ON)
option (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg [default: OFF]" OFF)
option (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically [default: OFF]" OFF)
option (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds [default: OFF]" OFF)

View file

@ -146,16 +146,12 @@ static void doReaderBenchmark(const fs::path& path, std::vector<float> &buffer,
static void doEntireRead(const fs::path& path)
{
#if !defined(_WIN32)
SndfileHandle handle(path.c_str());
#else
SndfileHandle handle(path.wstring().c_str());
#endif
if (handle.error())
throw std::runtime_error("cannot open sound file for reading");
sfz::AudioReaderPtr reader = sfz::createAudioReader(path, false);
if (!reader)
return;
std::vector<float> buffer(static_cast<size_t>(2 * handle.frames()));
handle.read(buffer.data(), buffer.size());
std::vector<float> buffer(static_cast<size_t>(2 * reader->frames()));
reader->readNextBlock(buffer.data(), buffer.size());
}
BENCHMARK_DEFINE_F(AudioReaderFixture, EntireWav)(benchmark::State& state)
@ -214,12 +210,14 @@ BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardOgg)(benchmark::State& state)
}
}
//BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseOgg)(benchmark::State& state)
//{
// for (auto _ : state) {
// doReaderBenchmark(fileOgg.path(), workBuffer, sfz::AudioReaderType::Reverse);
// }
//}
#if !defined(ST_AUDIO_FILE_USE_SNDFILE)
BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseOgg)(benchmark::State& state)
{
for (auto _ : state) {
doReaderBenchmark(fileOgg.path(), workBuffer, sfz::AudioReaderType::Reverse);
}
}
#endif
BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardWav)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseWav)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
@ -228,6 +226,8 @@ BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardFlac)->RangeMultiplier(2)->Range
BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseFlac)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
BENCHMARK_REGISTER_F(AudioReaderFixture, EntireFlac)->Range(1, 1);
BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
//BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
#if !defined(ST_AUDIO_FILE_USE_SNDFILE)
BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
#endif
BENCHMARK_REGISTER_F(AudioReaderFixture, EntireOgg)->Range(1, 1);
BENCHMARK_MAIN();

View file

@ -86,7 +86,7 @@ sfizz_add_benchmark(bm_flacfile BM_flacfile.cpp)
target_link_libraries(bm_flacfile PRIVATE sfizz-sndfile)
sfizz_add_benchmark(bm_audioReaders BM_audioReaders.cpp ../src/sfizz/AudioReader.cpp)
target_link_libraries(bm_audioReaders PRIVATE sfizz-sndfile)
target_link_libraries(bm_audioReaders PRIVATE st_audiofile sfizz-sndfile)
sfizz_add_benchmark(bm_readChunk BM_readChunk.cpp)
target_link_libraries(bm_readChunk PRIVATE sfizz-sndfile)

View file

@ -79,30 +79,40 @@ function(sfizz_enable_fast_math NAME)
endif()
endfunction()
# The sndfile library
add_library(sfizz-sndfile INTERFACE)
# The jsl utility library for C++
add_library(sfizz-jsl INTERFACE)
target_include_directories(sfizz-jsl INTERFACE "external/jsl/include")
if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
find_package(SndFile CONFIG REQUIRED)
find_path(SNDFILE_INCLUDE_DIR sndfile.hh)
target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}")
target_link_libraries(sfizz-sndfile INTERFACE SndFile::sndfile)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(SNDFILE "sndfile" REQUIRED)
target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS})
if (SFIZZ_STATIC_DEPENDENCIES)
target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES})
# The sndfile library
if (SFIZZ_USE_SNDFILE OR SFIZZ_TESTS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER)
add_library(sfizz-sndfile INTERFACE)
if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
find_package(SndFile CONFIG REQUIRED)
find_path(SNDFILE_INCLUDE_DIR "sndfile.hh")
target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}")
target_link_libraries(sfizz-sndfile INTERFACE SndFile::sndfile)
else()
target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES})
find_package(PkgConfig REQUIRED)
pkg_check_modules(SNDFILE "sndfile" REQUIRED)
target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS})
if (SFIZZ_STATIC_DEPENDENCIES)
target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES})
else()
target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES})
endif()
link_directories(${SNDFILE_LIBRARY_DIRS})
endif()
link_directories(${SNDFILE_LIBRARY_DIRS})
endif()
# The st_audiofile library
if (SFIZZ_USE_SNDFILE)
set(ST_AUDIO_FILE_USE_SNDFILE ON CACHE BOOL "" FORCE)
set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "sfizz-sndfile" CACHE STRING "" FORCE)
else()
set(ST_AUDIO_FILE_USE_SNDFILE OFF CACHE BOOL "" FORCE)
set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "" CACHE STRING "" FORCE)
endif()
add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL)
# If we build with Clang, optionally use libc++. Enabled by default on Apple OS.
cmake_dependent_option(USE_LIBCPP "Use libc++ with clang" "${APPLE}"
@ -154,6 +164,7 @@ Build VST plug-in: ${SFIZZ_VST}
Build AU plug-in: ${SFIZZ_AU}
Build benchmarks: ${SFIZZ_BENCHMARKS}
Build tests: ${SFIZZ_TESTS}
Use sndfile: ${SFIZZ_USE_SNDFILE}
Use vcpkg: ${SFIZZ_USE_VCPKG}
Statically link dependencies: ${SFIZZ_STATIC_DEPENDENCIES}
Link libatomic: ${SFIZZ_LINK_LIBATOMIC}

View file

@ -4,6 +4,10 @@ ifndef SFIZZ_DIR
$(error sfizz: The source directory must be set before including)
endif
### Options
SFIZZ_USE_SNDFILE ?= 1
###
SFIZZ_MACHINE := $(shell $(CC) -dumpmachine)
@ -125,13 +129,32 @@ SFIZZ_PKG_CONFIG ?= pkg-config
# Sndfile dependency
ifeq ($(SFIZZ_USE_SNDFILE),1)
SFIZZ_SNDFILE_C_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --cflags sndfile)
SFIZZ_SNDFILE_CXX_FLAGS ?= $(SFIZZ_SNDFILE_C_FLAGS)
SFIZZ_SNDFILE_LINK_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --libs sndfile)
endif
SFIZZ_C_FLAGS += $(SFIZZ_SNDFILE_C_FLAGS)
SFIZZ_CXX_FLAGS += $(SFIZZ_SNDFILE_CXX_FLAGS)
# st_audiofile dependency
SFIZZ_SOURCES += \
$(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile.c \
$(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_common.c \
$(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_libs.c \
$(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_sndfile.c
SFIZZ_C_FLAGS += \
-I$(SFIZZ_DIR)/external/st_audiofile/src \
-I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/dr_libs
SFIZZ_CXX_FLAGS += \
-I$(SFIZZ_DIR)/external/st_audiofile/src \
-I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/dr_libs
ifeq ($(SFIZZ_USE_SNDFILE),1)
SFIZZ_C_FLAGS += $(SFIZZ_SNDFILE_C_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1
SFIZZ_CXX_FLAGS += $(SFIZZ_SNDFILE_CXX_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1
SFIZZ_LINK_FLAGS += $(SFIZZ_SNDFILE_LINK_FLAGS)
endif
### Abseil dependency

38
external/st_audiofile/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,38 @@
cmake_minimum_required(VERSION 3.5)
project(st_audiofile)
option(ST_AUDIO_FILE_USE_SNDFILE "Use sndfile" OFF)
set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "" CACHE STRING "Name of external sndfile target")
add_library(st_audiofile STATIC
"src/st_audiofile.c"
"src/st_audiofile_common.c"
"src/st_audiofile_libs.c"
"src/st_audiofile_sndfile.c")
target_include_directories(st_audiofile
PUBLIC "src"
PUBLIC "thirdparty/dr_libs"
PUBLIC "thirdparty/stb_vorbis")
add_executable(st_info
"src/st_info.c")
target_link_libraries(st_info
PRIVATE st_audiofile)
if(ST_AUDIO_FILE_USE_SNDFILE)
target_compile_definitions(st_audiofile
PUBLIC "ST_AUDIO_FILE_USE_SNDFILE=1")
if(ST_AUDIO_FILE_EXTERNAL_SNDFILE)
target_link_libraries(st_audiofile
PUBLIC "${ST_AUDIO_FILE_EXTERNAL_SNDFILE}")
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(Sndfile "sndfile" REQUIRED)
target_include_directories(st_audiofile
PUBLIC ${Sndfile_INCLUDE_DIRS})
target_link_libraries(st_audiofile
PUBLIC ${Sndfile_LIBRARIES})
link_directories(
${Sndfile_LIBRARY_DIRS})
endif()
endif()

25
external/st_audiofile/LICENSE.md vendored Normal file
View file

@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2020, Jean-Pierre Cimalando
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

298
external/st_audiofile/src/st_audiofile.c vendored Normal file
View file

@ -0,0 +1,298 @@
// 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;
drmp3 *mp3;
stb_vorbis* ogg;
};
union {
struct { uint64_t frames; } mp3;
struct { uint32_t channels; float sample_rate; uint64_t frames; } ogg;
} cache;
};
enum {
st_audio_file_null = -1,
};
static st_audio_file* st_generic_open_file(const void* filename, int widepath)
{
#if !defined(_WIN32)
if (widepath)
return NULL;
#endif
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 =
#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)
free(af->wav);
else {
af->type = st_audio_file_wav;
return af;
}
}
// 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) {
af->type = st_audio_file_flac;
return af;
}
}
// 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);
if (af->ogg) {
af->cache.ogg.frames = stb_vorbis_stream_length_in_samples(af->ogg);
if (af->cache.ogg.frames == 0) {
stb_vorbis_close(af->ogg);
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
if (af->type == st_audio_file_null) {
af->mp3 = (drmp3*)malloc(sizeof(drmp3));
if (!af->mp3) {
free(af);
return NULL;
}
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)
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);
}
#if defined(_WIN32)
st_audio_file* st_open_file_w(const wchar_t* filename)
{
return st_generic_open_file(filename, 1);
}
#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;
case st_audio_file_ogg:
stb_vorbis_close(af->ogg);
break;
case st_audio_file_mp3:
drmp3_uninit(af->mp3);
free(af->mp3);
break;
}
af->type = st_audio_file_null;
}
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;
case st_audio_file_ogg:
channels = af->cache.ogg.channels;
break;
case st_audio_file_mp3:
channels = af->mp3->channels;
break;
}
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;
case st_audio_file_ogg:
sample_rate = af->cache.ogg.sample_rate;
break;
case st_audio_file_mp3:
sample_rate = af->mp3->sampleRate;
break;
}
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;
case st_audio_file_ogg:
frames = af->cache.ogg.frames;
break;
case st_audio_file_mp3:
frames = af->cache.mp3.frames;
break;
}
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;
case st_audio_file_ogg:
success = stb_vorbis_seek(af->ogg, (unsigned)frame) != 0;
break;
case st_audio_file_mp3:
success = drmp3_seek_to_pcm_frame(af->mp3, frame);
break;
}
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;
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;
case st_audio_file_mp3:
count = drmp3_read_pcm_frames_s16(af->mp3, count, buffer);
break;
}
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;
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;
case st_audio_file_mp3:
count = drmp3_read_pcm_frames_f32(af->mp3, count, buffer);
break;
}
return count;
}
#endif // !defined(ST_AUDIO_FILE_USE_SNDFILE)

View file

@ -0,0 +1,53 @@
// 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
#pragma once
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
#include <sndfile.h>
#endif
#include <stdint.h>
#include <stdbool.h>
#if defined(_WIN32)
#include <wchar.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct st_audio_file st_audio_file;
typedef enum st_audio_file_type {
st_audio_file_wav,
st_audio_file_flac,
st_audio_file_ogg,
st_audio_file_mp3,
st_audio_file_other,
} st_audio_file_type;
st_audio_file* st_open_file(const char* filename);
#if defined(_WIN32)
st_audio_file* st_open_file_w(const wchar_t* filename);
#endif
void st_close(st_audio_file* af);
int st_get_type(st_audio_file* af);
const char* st_get_type_string(st_audio_file* af);
const char* st_type_string(int type);
uint32_t st_get_channels(st_audio_file* af);
float st_get_sample_rate(st_audio_file* af);
uint64_t st_get_frame_count(st_audio_file* af);
bool st_seek(st_audio_file* af, uint64_t frame);
uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count);
uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count);
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
SNDFILE* st_get_sndfile_handle(st_audio_file* af);
int st_get_sndfile_format(st_audio_file* af);
#endif
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -0,0 +1,168 @@
// 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
#pragma once
#include "st_audiofile.h"
class ST_AudioFile {
public:
constexpr ST_AudioFile() noexcept;
~ST_AudioFile() noexcept;
ST_AudioFile(ST_AudioFile&&) noexcept;
ST_AudioFile& operator=(ST_AudioFile&&) noexcept;
ST_AudioFile(const ST_AudioFile&) = delete;
ST_AudioFile& operator=(const ST_AudioFile&) = delete;
explicit operator bool() const noexcept;
void reset(st_audio_file* new_af = nullptr) noexcept;
bool open_file(const char* filename);
#if defined(_WIN32)
bool open_file_w(const wchar_t* filename);
#endif
int get_type() const noexcept;
const char* get_type_string() const noexcept;
static const char* type_string(int type) noexcept;
uint32_t get_channels() const noexcept;
float get_sample_rate() const noexcept;
uint64_t get_frame_count() const noexcept;
bool seek(uint64_t frame) noexcept;
uint64_t read_s16(int16_t* buffer, uint64_t count) noexcept;
uint64_t read_f32(float* buffer, uint64_t count) noexcept;
st_audio_file* get_handle() const noexcept;
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
void* get_sndfile_handle() const noexcept;
int get_sndfile_format() const noexcept;
#endif
private:
st_audio_file* af_ = nullptr;
};
//------------------------------------------------------------------------------
inline constexpr ST_AudioFile::ST_AudioFile() noexcept
{
}
inline ST_AudioFile::~ST_AudioFile() noexcept
{
reset();
}
ST_AudioFile::ST_AudioFile(ST_AudioFile&& other) noexcept
: af_(other.af_)
{
other.af_ = nullptr;
}
ST_AudioFile& ST_AudioFile::operator=(ST_AudioFile&& other) noexcept
{
if (this != &other) {
if (af_)
st_close(af_);
af_ = other.af_;
other.af_ = nullptr;
}
return *this;
}
inline ST_AudioFile::operator bool() const noexcept
{
return af_ != nullptr;
}
inline void ST_AudioFile::reset(st_audio_file* new_af) noexcept
{
if (af_ != new_af) {
if (af_)
st_close(af_);
af_ = new_af;
}
}
bool ST_AudioFile::open_file(const char* filename)
{
st_audio_file* new_af = st_open_file(filename);
reset(new_af);
return new_af != nullptr;
}
#if defined(_WIN32)
inline bool ST_AudioFile::open_file_w(const wchar_t* filename)
{
st_audio_file* new_af = st_open_file_w(filename);
reset(new_af);
return new_af != nullptr;
}
#endif
inline int ST_AudioFile::get_type() const noexcept
{
return st_get_type(af_);
}
inline const char* ST_AudioFile::get_type_string() const noexcept
{
return st_get_type_string(af_);
}
inline const char* ST_AudioFile::type_string(int type) noexcept
{
return st_type_string(type);
}
inline uint32_t ST_AudioFile::get_channels() const noexcept
{
return st_get_channels(af_);
}
inline float ST_AudioFile::get_sample_rate() const noexcept
{
return st_get_sample_rate(af_);
}
inline uint64_t ST_AudioFile::get_frame_count() const noexcept
{
return st_get_frame_count(af_);
}
inline bool ST_AudioFile::seek(uint64_t frame) noexcept
{
return st_seek(af_, frame);
}
inline uint64_t ST_AudioFile::read_s16(int16_t* buffer, uint64_t count) noexcept
{
return st_read_s16(af_, buffer, count);
}
inline uint64_t ST_AudioFile::read_f32(float* buffer, uint64_t count) noexcept
{
return st_read_f32(af_, buffer, count);
}
inline st_audio_file* ST_AudioFile::get_handle() const noexcept
{
return af_;
}
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
inline void* ST_AudioFile::get_sndfile_handle() const noexcept
{
return st_get_sndfile_handle(af_);
}
int ST_AudioFile::get_sndfile_format() const noexcept
{
return st_get_sndfile_format(af_);
}
#endif

View file

@ -0,0 +1,38 @@
// 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"
#include <stddef.h>
const char* st_get_type_string(st_audio_file* af)
{
return st_type_string(st_get_type(af));
}
const char* st_type_string(int type)
{
const char *type_string = NULL;
switch (type) {
case st_audio_file_wav:
type_string = "WAV";
break;
case st_audio_file_flac:
type_string = "FLAC";
break;
case st_audio_file_ogg:
type_string = "OGG";
break;
case st_audio_file_mp3:
type_string = "MP3";
break;
case st_audio_file_other:
type_string = "other";
break;
}
return type_string;
}

View file

@ -0,0 +1,29 @@
// 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
#define DR_WAV_IMPLEMENTATION
#define DR_FLAC_IMPLEMENTATION
#define DR_MP3_IMPLEMENTATION
#define STB_VORBIS_HEADER_ONLY 0
#include "st_audiofile_libs.h"
#if defined(_WIN32)
stb_vorbis* stb_vorbis_open_filename_w(const wchar_t* filename, int* error, const stb_vorbis_alloc* alloc)
{
FILE* f;
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
if (0 != _wfopen_s(&f, filename, L"rb"))
f = NULL;
#else
f = _wfopen(filename, L"rb");
#endif
if (f)
return stb_vorbis_open_file(f, TRUE, error, alloc);
if (error)
*error = VORBIS_file_open_failure;
return NULL;
}
#endif

View file

@ -0,0 +1,21 @@
// 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
#pragma once
#include "dr_wav.h"
#include "dr_flac.h"
#include "dr_mp3.h"
#if !defined(STB_VORBIS_HEADER_ONLY)
# define STB_VORBIS_HEADER_ONLY 1
#elif STB_VORBIS_HEADER_ONLY == 0
# undef STB_VORBIS_HEADER_ONLY
#endif
#include "stb_vorbis.c"
#if defined(_WIN32)
#include <wchar.h>
stb_vorbis* stb_vorbis_open_filename_w(const wchar_t* filename, int* error, const stb_vorbis_alloc* alloc);
#endif

View file

@ -0,0 +1,120 @@
// 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)
#if defined(_WIN32)
#include <windows.h>
#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
#endif
#include <sndfile.h>
#include <stdlib.h>
struct st_audio_file {
SNDFILE* snd;
SF_INFO info;
};
st_audio_file* st_open_file(const char* filename)
{
st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file));
if (!af)
return NULL;
af->snd = sf_open(filename, SFM_READ, &af->info);
if (!af->snd) {
free(af);
return NULL;
}
return af;
}
#if defined(_WIN32)
st_audio_file* st_open_file_w(const wchar_t* filename)
{
st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file));
if (!af)
return NULL;
af->snd = sf_wchar_open(filename, SFM_READ, &af->info);
if (!af->snd) {
free(af);
return NULL;
}
return af;
}
#endif
void st_close(st_audio_file* af)
{
if (af->snd) {
sf_close(af->snd);
af->snd = NULL;
}
}
int st_get_type(st_audio_file* af)
{
int type = st_audio_file_other;
switch (af->info.format & SF_FORMAT_TYPEMASK) {
case SF_FORMAT_WAV:
type = st_audio_file_wav;
break;
case SF_FORMAT_FLAC:
type = st_audio_file_flac;
break;
case SF_FORMAT_OGG:
type = st_audio_file_ogg;
break;
}
return type;
}
uint32_t st_get_channels(st_audio_file* af)
{
return af->info.channels;
}
float st_get_sample_rate(st_audio_file* af)
{
return af->info.samplerate;
}
uint64_t st_get_frame_count(st_audio_file* af)
{
return af->info.frames;
}
bool st_seek(st_audio_file* af, uint64_t frame)
{
return sf_seek(af->snd, frame, SEEK_SET) != -1;
}
uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count)
{
return sf_readf_short(af->snd, buffer, count);
}
uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count)
{
return sf_readf_float(af->snd, buffer, count);
}
SNDFILE* st_get_sndfile_handle(st_audio_file* af)
{
return af->snd;
}
int st_get_sndfile_format(st_audio_file* af)
{
return af->info.format;
}
#endif // defined(ST_AUDIO_FILE_USE_SNDFILE)

33
external/st_audiofile/src/st_info.c vendored Normal file
View file

@ -0,0 +1,33 @@
// 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"
#include <stdio.h>
#include <inttypes.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
fprintf(stderr, "Please indicate a sound file.\n");
return 1;
}
const char* filename = argv[1];
st_audio_file* af = st_open_file(filename);
if (!af) {
fprintf(stderr, "Could not open the sound file.\n");
return 1;
}
printf("File name : %s\n", filename);
printf("File type : %s\n", st_get_type_string(af));
printf("Channels : %u\n", st_get_channels(af));
printf("Sample rate : %f\n", st_get_sample_rate(af));
printf("Frames : %" PRIu64 "\n", st_get_frame_count(af));
return 0;
}

@ -0,0 +1 @@
Subproject commit cac1785cee4abb455817b43d5dee33b49d61be2f

@ -0,0 +1 @@
Subproject commit fc0bd698b26888da0a632da33f4c49b90763e69b

View file

@ -29,6 +29,7 @@
#
# SFIZZ_RACK_PLUGIN_DIR = <the root directory of the Rack plugin>
# SFIZZ_PKG_CONFIG = <a custom pkg-config command>
# SFIZZ_USE_SNDFILE = <0 disabled, 1 enabled (default)>
# SFIZZ_SNDFILE_C_FLAGS = <compiler flags of sndfile for C>
# SFIZZ_SNDFILE_CXX_FLAGS = <compiler flags of sndfile for C++>
# SFIZZ_SNDFILE_LINK_FLAGS = <linker flags of sndfile>

View file

@ -31,6 +31,7 @@ clang-tidy \
vst/SfizzVstEditor.cpp \
vst/SfizzVstState.cpp \
-- -Iexternal/abseil-cpp -Iexternal/jsl/include -Isrc/external -Isrc/external/pugixml/src \
-Iexternal/st_audiofile/src -Iexternal/st_audiofile/thirdparty/dr_libs \
-Isrc/sfizz -Isrc -Isrc/external/spline -Isrc/external/cpuid/src \
-Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer \
-Ieditor/src \

View file

@ -218,7 +218,7 @@ target_sources(sfizz_static PRIVATE
target_include_directories (sfizz_static PUBLIC .)
target_include_directories (sfizz_static PUBLIC external)
target_link_libraries (sfizz_static PUBLIC absl::strings absl::span)
target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic)
target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic)
set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp")
if (WIN32)
target_compile_definitions (sfizz_static PRIVATE _USE_MATH_DEFINES)
@ -245,7 +245,7 @@ if (SFIZZ_SHARED)
${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp)
target_include_directories (sfizz_shared PRIVATE .)
target_include_directories (sfizz_shared PRIVATE external)
target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic)
target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic)
if (WIN32)
target_compile_definitions (sfizz_shared PRIVATE _USE_MATH_DEFINES)
endif()

View file

@ -5,51 +5,60 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "AudioReader.h"
#include <sndfile.hh>
#include "FileMetadata.h"
#include <st_audiofile.hpp>
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
#include <sndfile.h>
#endif
#include <algorithm>
namespace sfz {
class BasicSndfileReader : public AudioReader {
public:
explicit BasicSndfileReader(SndfileHandle handle) : handle_(handle) {}
explicit BasicSndfileReader(ST_AudioFile handle) : handle_(std::move(handle)) {}
virtual ~BasicSndfileReader() {}
int format() const override;
int64_t frames() const override;
unsigned channels() const override;
unsigned sampleRate() const override;
bool getInstrument(SF_INSTRUMENT* instrument) override;
bool getInstrument(InstrumentInfo* instrument) override;
protected:
SndfileHandle handle_;
ST_AudioFile handle_;
};
int BasicSndfileReader::format() const
{
return handle_.format();
return handle_.get_type();
}
int64_t BasicSndfileReader::frames() const
{
return handle_.frames();
return handle_.get_frame_count();
}
unsigned BasicSndfileReader::channels() const
{
return handle_.channels();
return handle_.get_channels();
}
unsigned BasicSndfileReader::sampleRate() const
{
return handle_.samplerate();
return handle_.get_sample_rate();
}
bool BasicSndfileReader::getInstrument(SF_INSTRUMENT* instrument)
bool BasicSndfileReader::getInstrument(InstrumentInfo* instrument)
{
if (handle_.command(SFC_GET_INSTRUMENT, instrument, sizeof(SF_INSTRUMENT)) == SF_FALSE)
return false;
return true;
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
SNDFILE* sndfile = reinterpret_cast<SNDFILE*>(handle_.get_sndfile_handle());
if (sf_command(sndfile, SFC_GET_INSTRUMENT, &instrument, sizeof(instrument)) == SF_TRUE)
return true;
#else
(void)instrument;
#endif
return false;
}
//------------------------------------------------------------------------------
@ -59,13 +68,13 @@ bool BasicSndfileReader::getInstrument(SF_INSTRUMENT* instrument)
*/
class ForwardReader : public BasicSndfileReader {
public:
explicit ForwardReader(SndfileHandle handle);
explicit ForwardReader(ST_AudioFile handle);
AudioReaderType type() const override;
size_t readNextBlock(float* buffer, size_t frames) override;
};
ForwardReader::ForwardReader(SndfileHandle handle)
: BasicSndfileReader(handle)
ForwardReader::ForwardReader(ST_AudioFile handle)
: BasicSndfileReader(std::move(handle))
{
}
@ -76,7 +85,7 @@ AudioReaderType ForwardReader::type() const
size_t ForwardReader::readNextBlock(float* buffer, size_t frames)
{
sf_count_t readFrames = handle_.readf(buffer, frames);
uint64_t readFrames = handle_.read_f32(buffer, frames);
if (frames <= 0)
return 0;
@ -93,7 +102,7 @@ struct AudioFrame {
/**
* @brief Reorder a sequence of frames in reverse
*/
static void reverse_frames(float* data, sf_count_t frames, unsigned channels)
static void reverse_frames(float* data, size_t frames, unsigned channels)
{
switch (channels) {
@ -108,8 +117,8 @@ static void reverse_frames(float* data, sf_count_t frames, unsigned channels)
SPECIALIZE_FOR(2);
default:
for (sf_count_t i = 0; i < frames / 2; ++i) {
sf_count_t j = frames - 1 - i;
for (size_t i = 0; i < frames / 2; ++i) {
size_t j = frames - 1 - i;
float* frame1 = &data[i * channels];
float* frame2 = &data[j * channels];
for (unsigned c = 0; c < channels; ++c)
@ -128,18 +137,18 @@ static void reverse_frames(float* data, sf_count_t frames, unsigned channels)
*/
class ReverseReader : public BasicSndfileReader {
public:
explicit ReverseReader(SndfileHandle handle);
explicit ReverseReader(ST_AudioFile handle);
AudioReaderType type() const override;
size_t readNextBlock(float* buffer, size_t frames) override;
private:
sf_count_t position_ {};
uint64_t position_ {};
};
ReverseReader::ReverseReader(SndfileHandle handle)
: BasicSndfileReader(handle)
ReverseReader::ReverseReader(ST_AudioFile handle)
: BasicSndfileReader(std::move(handle))
{
position_ = handle.seek(0, SEEK_END);
position_ = handle_.get_frame_count();
}
AudioReaderType ReverseReader::type() const
@ -149,16 +158,16 @@ AudioReaderType ReverseReader::type() const
size_t ReverseReader::readNextBlock(float* buffer, size_t frames)
{
sf_count_t position = position_;
const unsigned channels = handle_.channels();
uint64_t position = position_;
const unsigned channels = handle_.get_channels();
const sf_count_t readFrames = std::min<sf_count_t>(frames, position);
const uint64_t readFrames = std::min<uint64_t>(frames, position);
if (readFrames <= 0)
return false;
position -= readFrames;
if (handle_.seek(position, SEEK_SET) != position ||
handle_.readf(buffer, readFrames) != readFrames)
if (!handle_.seek(position) ||
handle_.read_f32(buffer, readFrames) != readFrames)
return false;
position_ = position;
@ -173,7 +182,7 @@ size_t ReverseReader::readNextBlock(float* buffer, size_t frames)
*/
class NoSeekReverseReader : public BasicSndfileReader {
public:
explicit NoSeekReverseReader(SndfileHandle handle);
explicit NoSeekReverseReader(ST_AudioFile handle);
AudioReaderType type() const override;
size_t readNextBlock(float* buffer, size_t frames) override;
@ -182,11 +191,11 @@ private:
private:
std::unique_ptr<float[]> fileBuffer_;
sf_count_t fileFramesLeft_ { 0 };
uint64_t fileFramesLeft_ { 0 };
};
NoSeekReverseReader::NoSeekReverseReader(SndfileHandle handle)
: BasicSndfileReader(handle)
NoSeekReverseReader::NoSeekReverseReader(ST_AudioFile handle)
: BasicSndfileReader(std::move(handle))
{
}
@ -203,9 +212,9 @@ size_t NoSeekReverseReader::readNextBlock(float* buffer, size_t frames)
fileBuffer = fileBuffer_.get();
}
const unsigned channels = handle_.channels();
const sf_count_t fileFramesLeft = fileFramesLeft_;
sf_count_t readFrames = std::min<sf_count_t>(frames, fileFramesLeft);
const unsigned channels = handle_.get_channels();
const uint64_t fileFramesLeft = fileFramesLeft_;
uint64_t readFrames = std::min<uint64_t>(frames, fileFramesLeft);
if (readFrames <= 0)
return 0;
@ -220,15 +229,16 @@ size_t NoSeekReverseReader::readNextBlock(float* buffer, size_t frames)
void NoSeekReverseReader::readWholeFile()
{
const sf_count_t frames = handle_.frames();
const unsigned channels = handle_.channels();
const uint64_t frames = handle_.get_frame_count();
const unsigned channels = handle_.get_channels();
float* fileBuffer = new float[channels * frames];
fileBuffer_.reset(fileBuffer);
fileFramesLeft_ = handle_.readf(fileBuffer, frames);
fileFramesLeft_ = handle_.read_f32(fileBuffer, frames);
}
//------------------------------------------------------------------------------
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
const std::error_category& sndfile_category()
{
class sndfile_category : public std::error_category {
@ -248,6 +258,26 @@ const std::error_category& sndfile_category()
static const sndfile_category cat;
return cat;
}
#endif
const std::error_category& undetailed_category()
{
class undetailed_category : public std::error_category {
public:
const char* name() const noexcept override
{
return "undetailed";
}
std::string message(int condition) const override
{
return (condition == 0) ? "success" : "failure";
}
};
static const undetailed_category cat;
return cat;
}
//------------------------------------------------------------------------------
@ -260,7 +290,7 @@ public:
unsigned channels() const override { return 1; }
unsigned sampleRate() const override { return 44100; }
size_t readNextBlock(float*, size_t) override { return 0; }
bool getInstrument(SF_INSTRUMENT* ) override { return false; }
bool getInstrument(InstrumentInfo* ) override { return false; }
private:
AudioReaderType type_ {};
@ -268,6 +298,7 @@ private:
//------------------------------------------------------------------------------
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
static bool formatHasFastSeeking(int format)
{
bool fast;
@ -300,8 +331,9 @@ static bool formatHasFastSeeking(int format)
return fast;
}
#endif
static AudioReaderPtr createAudioReaderWithHandle(SndfileHandle handle, bool reverse, std::error_code* ec)
static AudioReaderPtr createAudioReaderWithHandle(ST_AudioFile handle, bool reverse, std::error_code* ec)
{
AudioReaderPtr reader;
@ -310,30 +342,38 @@ static AudioReaderPtr createAudioReaderWithHandle(SndfileHandle handle, bool rev
if (!handle) {
if (ec)
*ec = std::error_code(handle.error(), sndfile_category());
*ec = std::error_code(1, undetailed_category());
reader.reset(new DummyAudioReader(reverse ? AudioReaderType::Reverse : AudioReaderType::Forward));
}
else if (!reverse)
reader.reset(new ForwardReader(handle));
else if (formatHasFastSeeking(handle.format()))
reader.reset(new ReverseReader(handle));
else
reader.reset(new NoSeekReverseReader(handle));
reader.reset(new ForwardReader(std::move(handle)));
else {
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
bool hasFastSeeking = formatHasFastSeeking(handle.get_sndfile_format());
#else
bool hasFastSeeking = true;
#endif
if (hasFastSeeking)
reader.reset(new ReverseReader(std::move(handle)));
else
reader.reset(new NoSeekReverseReader(std::move(handle)));
}
return reader;
}
AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_code* ec)
{
ST_AudioFile handle;
#if defined(_WIN32)
SndfileHandle handle(path.wstring().c_str());
handle.open_file_w(path.wstring().c_str());
#else
SndfileHandle handle(path.c_str());
handle.open_file(path.c_str());
#endif
return createAudioReaderWithHandle(handle, reverse, ec);
return createAudioReaderWithHandle(std::move(handle), reverse, ec);
}
static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle, AudioReaderType type, std::error_code* ec)
static AudioReaderPtr createExplicitAudioReaderWithHandle(ST_AudioFile handle, AudioReaderType type, std::error_code* ec)
{
AudioReaderPtr reader;
@ -342,19 +382,19 @@ static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle,
if (!handle) {
if (ec)
*ec = std::error_code(handle.error(), sndfile_category());
*ec = std::error_code(1, undetailed_category());
reader.reset(new DummyAudioReader(type));
}
else {
switch (type) {
case AudioReaderType::Forward:
reader.reset(new ForwardReader(handle));
reader.reset(new ForwardReader(std::move(handle)));
break;
case AudioReaderType::Reverse:
reader.reset(new ReverseReader(handle));
reader.reset(new ReverseReader(std::move(handle)));
break;
case AudioReaderType::NoSeekReverse:
reader.reset(new NoSeekReverseReader(handle));
reader.reset(new NoSeekReverseReader(std::move(handle)));
break;
}
}
@ -364,12 +404,13 @@ static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle,
AudioReaderPtr createExplicitAudioReader(const fs::path& path, AudioReaderType type, std::error_code* ec)
{
ST_AudioFile handle;
#if defined(_WIN32)
SndfileHandle handle(path.wstring().c_str());
handle.open_file_w(path.wstring().c_str());
#else
SndfileHandle handle(path.c_str());
handle.open_file(path.c_str());
#endif
return createExplicitAudioReaderWithHandle(handle, type, ec);
return createExplicitAudioReaderWithHandle(std::move(handle), type, ec);
}
} // namespace sfz

View file

@ -7,16 +7,13 @@
#pragma once
#include "absl/types/span.h"
#include "ghc/fs_std.hpp"
#include <st_audiofile.h>
#include <system_error>
#include <memory>
#include <cstdio>
#if defined(_WIN32)
#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
#include <windows.h>
#endif
#include <sndfile.h>
namespace sfz {
struct InstrumentInfo;
/**
* @brief Designation of a particular kind of audio reader
@ -42,7 +39,7 @@ public:
virtual unsigned channels() const = 0;
virtual unsigned sampleRate() const = 0;
virtual size_t readNextBlock(float* buffer, size_t frames) = 0;
virtual bool getInstrument(SF_INSTRUMENT* instrument) = 0;
virtual bool getInstrument(InstrumentInfo* instrument) = 0;
};
typedef std::unique_ptr<AudioReader> AudioReaderPtr;

View file

@ -242,7 +242,7 @@ size_t FileMetadataReader::Impl::readRiffData(size_t index, void* buffer, size_t
return fread(buffer, 1, count, stream);
}
bool FileMetadataReader::extractRiffInstrument(SF_INSTRUMENT& ins)
bool FileMetadataReader::extractRiffInstrument(InstrumentInfo& ins)
{
const RiffChunkInfo* riff = riffChunkById(RiffChunkId{'s', 'm', 'p', 'l'});
if (!riff)
@ -278,16 +278,16 @@ bool FileMetadataReader::extractRiffInstrument(SF_INSTRUMENT& ins)
switch (extractU32(loopOffset + 0x04)) {
default:
ins.loops[i].mode = SF_LOOP_NONE;
ins.loops[i].mode = LoopNone;
break;
case 0:
ins.loops[i].mode = SF_LOOP_FORWARD;
ins.loops[i].mode = LoopForward;
break;
case 1:
ins.loops[i].mode = SF_LOOP_ALTERNATING;
ins.loops[i].mode = LoopAlternating;
break;
case 2:
ins.loops[i].mode = SF_LOOP_BACKWARD;
ins.loops[i].mode = LoopBackward;
break;
}

View file

@ -5,15 +5,13 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
#include <sndfile.h>
#endif
#include "ghc/fs_std.hpp"
#include <array>
#include <memory>
#include <cstdio>
#if defined(_WIN32)
#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
#include <windows.h>
#endif
#include <sndfile.h>
namespace sfz {
@ -26,6 +24,44 @@ struct RiffChunkInfo {
uint32_t length;
};
#if !defined(ST_AUDIO_FILE_USE_SNDFILE)
/**
@brief Loop mode, like SF_LOOP_*
*/
enum LoopMode {
LoopNone,
LoopForward,
LoopBackward,
LoopAlternating,
};
/**
@brief Instrument information, like SF_INSTRUMENT
*/
struct InstrumentInfo {
int gain;
int8_t basenote, detune;
int8_t velocity_lo, velocity_hi;
int8_t key_lo, key_hi;
int loop_count;
struct {
int mode;
uint32_t start;
uint32_t end;
uint32_t count;
} loops[16];
};
#else
enum LoopMode {
LoopNone = SF_LOOP_NONE,
LoopForward = SF_LOOP_FORWARD,
LoopBackward = SF_LOOP_BACKWARD,
LoopAlternating = SF_LOOP_ALTERNATING,
};
struct InstrumentInfo : SF_INSTRUMENT {};
#endif
struct WavetableInfo {
/**
@brief Size of each successive table in the file
@ -79,7 +115,7 @@ public:
/**
* @brief Extract the RIFF 'smpl' data and convert it to sndfile instrument
*/
bool extractRiffInstrument(SF_INSTRUMENT& ins);
bool extractRiffInstrument(InstrumentInfo& ins);
/**
* @brief Extract the wavetable information from various relevant RIFF chunks

View file

@ -39,7 +39,6 @@
#include <memory>
#include <thread>
#include <system_error>
#include <sndfile.hh>
#if defined(_WIN32)
#include <windows.h>
#else
@ -235,7 +234,7 @@ absl::optional<sfz::FileInformation> sfz::FilePool::getFileInformation(const Fil
returnedValue.sampleRate = static_cast<double>(reader->sampleRate());
returnedValue.numChannels = reader->channels();
SF_INSTRUMENT instrumentInfo {};
InstrumentInfo instrumentInfo {};
bool haveInstrumentInfo = reader->getInstrument(&instrumentInfo);
FileMetadataReader mdReader;

View file

@ -88,10 +88,10 @@ if(JACK_FOUND AND TARGET Qt5::Widgets)
endif()
add_executable(eq_apply EQ.cpp)
target_link_libraries(eq_apply PRIVATE sfizz::sfizz)
target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz-sndfile)
add_executable(filter_apply Filter.cpp)
target_link_libraries(filter_apply PRIVATE sfizz::sfizz)
target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz-sndfile)
add_executable(sfizz_plot_curve PlotCurve.cpp)
target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz)
@ -100,10 +100,10 @@ add_executable(sfizz_plot_wavetables PlotWavetables.cpp)
target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::sfizz)
add_executable(sfizz_plot_lfo PlotLFO.cpp)
target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz)
target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz sfizz-sndfile)
add_executable(sfizz_file_instrument FileInstrument.cpp)
target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz)
target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz sfizz-sndfile)
add_executable(sfizz_file_wavetable FileWavetable.cpp)
target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::sfizz)

View file

@ -12,20 +12,21 @@
static const char* modeString(int mode, const char* valueFallback = nullptr)
{
switch (mode) {
case SF_LOOP_NONE:
case sfz::LoopNone:
return "none";
case SF_LOOP_FORWARD:
case sfz::LoopForward:
return "forward";
case SF_LOOP_BACKWARD:
case sfz::LoopBackward:
return "backward";
case SF_LOOP_ALTERNATING:
case sfz::LoopAlternating:
return "alternating";
default:
return valueFallback;
}
}
static void printInstrument(const SF_INSTRUMENT& ins)
template <class Instrument>
static void printInstrument(const Instrument& ins)
{
printf("Gain: %d\n", ins.gain);
printf("Base note: %d\n", ins.basenote);
@ -34,7 +35,7 @@ static void printInstrument(const SF_INSTRUMENT& ins)
printf("Key: %d:%d\n", ins.key_lo, ins.key_hi);
printf("Loop count: %d\n", ins.loop_count);
for (int i = 0; i < ins.loop_count; ++i) {
for (unsigned i = 0, n = ins.loop_count; i < n; ++i) {
printf("\nLoop %d:\n", i + 1);
printf("\tMode: %s\n", modeString(ins.loops[i].mode, "(unknown)"));
printf("\tStart: %u\n", ins.loops[i].start);
@ -83,18 +84,18 @@ int main(int argc, char *argv[])
return 1;
}
SF_INSTRUMENT ins {};
if (method == kMethodRiff) {
sfz::FileMetadataReader reader;
if (!reader.open(path)) {
fprintf(stderr, "Cannot open file\n");
return 1;
}
sfz::InstrumentInfo ins {};
if (!reader.extractRiffInstrument(ins)) {
fprintf(stderr, "Cannot get instrument\n");
return 1;
}
printInstrument(ins);
}
else {
SndfileHandle sndFile(path);
@ -102,13 +103,13 @@ int main(int argc, char *argv[])
fprintf(stderr, "Cannot open file\n");
return 1;
}
SF_INSTRUMENT ins {};
if (sndFile.command(SFC_GET_INSTRUMENT, &ins, sizeof(ins)) != 1) {
fprintf(stderr, "Cannot get instrument\n");
return 1;
}
printInstrument(ins);
}
printInstrument(ins);
return 0;
}