Eliminate the strict requirement of libsndfile
This commit is contained in:
parent
ff1d749ee7
commit
d5aad58366
11 changed files with 196 additions and 110 deletions
|
|
@ -29,6 +29,7 @@ option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF)
|
||||||
option (SFIZZ_TESTS "Enable tests 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_DEVTOOLS "Enable developer tools build [default: OFF]" OFF)
|
||||||
option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON)
|
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_USE_VCPKG "Assume that sfizz is build using vcpkg [default: OFF]" OFF)
|
||||||
option (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically [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)
|
option (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds [default: OFF]" OFF)
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ sfizz_add_benchmark(bm_flacfile BM_flacfile.cpp)
|
||||||
target_link_libraries(bm_flacfile PRIVATE sfizz-sndfile)
|
target_link_libraries(bm_flacfile PRIVATE sfizz-sndfile)
|
||||||
|
|
||||||
sfizz_add_benchmark(bm_audioReaders BM_audioReaders.cpp ../src/sfizz/AudioReader.cpp)
|
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)
|
sfizz_add_benchmark(bm_readChunk BM_readChunk.cpp)
|
||||||
target_link_libraries(bm_readChunk PRIVATE sfizz-sndfile)
|
target_link_libraries(bm_readChunk PRIVATE sfizz-sndfile)
|
||||||
|
|
|
||||||
|
|
@ -79,30 +79,40 @@ function(sfizz_enable_fast_math NAME)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# The sndfile library
|
|
||||||
add_library(sfizz-sndfile INTERFACE)
|
|
||||||
|
|
||||||
# The jsl utility library for C++
|
# The jsl utility library for C++
|
||||||
add_library(sfizz-jsl INTERFACE)
|
add_library(sfizz-jsl INTERFACE)
|
||||||
target_include_directories(sfizz-jsl INTERFACE "external/jsl/include")
|
target_include_directories(sfizz-jsl INTERFACE "external/jsl/include")
|
||||||
|
|
||||||
if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
# The sndfile library
|
||||||
find_package(SndFile CONFIG REQUIRED)
|
if (SFIZZ_USE_SNDFILE OR SFIZZ_TESTS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER)
|
||||||
find_path(SNDFILE_INCLUDE_DIR sndfile.hh)
|
add_library(sfizz-sndfile INTERFACE)
|
||||||
target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}")
|
if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||||
target_link_libraries(sfizz-sndfile INTERFACE SndFile::sndfile)
|
find_package(SndFile CONFIG REQUIRED)
|
||||||
else()
|
find_path(SNDFILE_INCLUDE_DIR "sndfile.hh")
|
||||||
find_package(PkgConfig REQUIRED)
|
target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}")
|
||||||
pkg_check_modules(SNDFILE "sndfile" REQUIRED)
|
target_link_libraries(sfizz-sndfile INTERFACE SndFile::sndfile)
|
||||||
target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS})
|
|
||||||
if (SFIZZ_STATIC_DEPENDENCIES)
|
|
||||||
target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES})
|
|
||||||
else()
|
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()
|
endif()
|
||||||
link_directories(${SNDFILE_LIBRARY_DIRS})
|
|
||||||
endif()
|
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.
|
# If we build with Clang, optionally use libc++. Enabled by default on Apple OS.
|
||||||
cmake_dependent_option(USE_LIBCPP "Use libc++ with clang" "${APPLE}"
|
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 AU plug-in: ${SFIZZ_AU}
|
||||||
Build benchmarks: ${SFIZZ_BENCHMARKS}
|
Build benchmarks: ${SFIZZ_BENCHMARKS}
|
||||||
Build tests: ${SFIZZ_TESTS}
|
Build tests: ${SFIZZ_TESTS}
|
||||||
|
Use sndfile: ${SFIZZ_USE_SNDFILE}
|
||||||
Use vcpkg: ${SFIZZ_USE_VCPKG}
|
Use vcpkg: ${SFIZZ_USE_VCPKG}
|
||||||
Statically link dependencies: ${SFIZZ_STATIC_DEPENDENCIES}
|
Statically link dependencies: ${SFIZZ_STATIC_DEPENDENCIES}
|
||||||
Link libatomic: ${SFIZZ_LINK_LIBATOMIC}
|
Link libatomic: ${SFIZZ_LINK_LIBATOMIC}
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ target_sources(sfizz_static PRIVATE
|
||||||
target_include_directories (sfizz_static PUBLIC .)
|
target_include_directories (sfizz_static PUBLIC .)
|
||||||
target_include_directories (sfizz_static PUBLIC external)
|
target_include_directories (sfizz_static PUBLIC external)
|
||||||
target_link_libraries (sfizz_static PUBLIC absl::strings absl::span)
|
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")
|
set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp")
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_compile_definitions (sfizz_static PRIVATE _USE_MATH_DEFINES)
|
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)
|
${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 .)
|
||||||
target_include_directories (sfizz_shared PRIVATE external)
|
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)
|
if (WIN32)
|
||||||
target_compile_definitions (sfizz_shared PRIVATE _USE_MATH_DEFINES)
|
target_compile_definitions (sfizz_shared PRIVATE _USE_MATH_DEFINES)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -5,51 +5,60 @@
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#include "AudioReader.h"
|
#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>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace sfz {
|
namespace sfz {
|
||||||
|
|
||||||
class BasicSndfileReader : public AudioReader {
|
class BasicSndfileReader : public AudioReader {
|
||||||
public:
|
public:
|
||||||
explicit BasicSndfileReader(SndfileHandle handle) : handle_(handle) {}
|
explicit BasicSndfileReader(ST_AudioFile handle) : handle_(std::move(handle)) {}
|
||||||
virtual ~BasicSndfileReader() {}
|
virtual ~BasicSndfileReader() {}
|
||||||
|
|
||||||
int format() const override;
|
int format() const override;
|
||||||
int64_t frames() const override;
|
int64_t frames() const override;
|
||||||
unsigned channels() const override;
|
unsigned channels() const override;
|
||||||
unsigned sampleRate() const override;
|
unsigned sampleRate() const override;
|
||||||
bool getInstrument(SF_INSTRUMENT* instrument) override;
|
bool getInstrument(InstrumentInfo* instrument) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SndfileHandle handle_;
|
ST_AudioFile handle_;
|
||||||
};
|
};
|
||||||
|
|
||||||
int BasicSndfileReader::format() const
|
int BasicSndfileReader::format() const
|
||||||
{
|
{
|
||||||
return handle_.format();
|
return handle_.get_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t BasicSndfileReader::frames() const
|
int64_t BasicSndfileReader::frames() const
|
||||||
{
|
{
|
||||||
return handle_.frames();
|
return handle_.get_frame_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned BasicSndfileReader::channels() const
|
unsigned BasicSndfileReader::channels() const
|
||||||
{
|
{
|
||||||
return handle_.channels();
|
return handle_.get_channels();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned BasicSndfileReader::sampleRate() const
|
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)
|
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
|
||||||
return false;
|
SNDFILE* sndfile = reinterpret_cast<SNDFILE*>(handle_.get_sndfile_handle());
|
||||||
return true;
|
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 {
|
class ForwardReader : public BasicSndfileReader {
|
||||||
public:
|
public:
|
||||||
explicit ForwardReader(SndfileHandle handle);
|
explicit ForwardReader(ST_AudioFile handle);
|
||||||
AudioReaderType type() const override;
|
AudioReaderType type() const override;
|
||||||
size_t readNextBlock(float* buffer, size_t frames) override;
|
size_t readNextBlock(float* buffer, size_t frames) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
ForwardReader::ForwardReader(SndfileHandle handle)
|
ForwardReader::ForwardReader(ST_AudioFile handle)
|
||||||
: BasicSndfileReader(handle)
|
: BasicSndfileReader(std::move(handle))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +85,7 @@ AudioReaderType ForwardReader::type() const
|
||||||
|
|
||||||
size_t ForwardReader::readNextBlock(float* buffer, size_t frames)
|
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)
|
if (frames <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -93,7 +102,7 @@ struct AudioFrame {
|
||||||
/**
|
/**
|
||||||
* @brief Reorder a sequence of frames in reverse
|
* @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) {
|
switch (channels) {
|
||||||
|
|
||||||
|
|
@ -108,8 +117,8 @@ static void reverse_frames(float* data, sf_count_t frames, unsigned channels)
|
||||||
SPECIALIZE_FOR(2);
|
SPECIALIZE_FOR(2);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
for (sf_count_t i = 0; i < frames / 2; ++i) {
|
for (size_t i = 0; i < frames / 2; ++i) {
|
||||||
sf_count_t j = frames - 1 - i;
|
size_t j = frames - 1 - i;
|
||||||
float* frame1 = &data[i * channels];
|
float* frame1 = &data[i * channels];
|
||||||
float* frame2 = &data[j * channels];
|
float* frame2 = &data[j * channels];
|
||||||
for (unsigned c = 0; c < channels; ++c)
|
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 {
|
class ReverseReader : public BasicSndfileReader {
|
||||||
public:
|
public:
|
||||||
explicit ReverseReader(SndfileHandle handle);
|
explicit ReverseReader(ST_AudioFile handle);
|
||||||
AudioReaderType type() const override;
|
AudioReaderType type() const override;
|
||||||
size_t readNextBlock(float* buffer, size_t frames) override;
|
size_t readNextBlock(float* buffer, size_t frames) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf_count_t position_ {};
|
uint64_t position_ {};
|
||||||
};
|
};
|
||||||
|
|
||||||
ReverseReader::ReverseReader(SndfileHandle handle)
|
ReverseReader::ReverseReader(ST_AudioFile handle)
|
||||||
: BasicSndfileReader(handle)
|
: BasicSndfileReader(std::move(handle))
|
||||||
{
|
{
|
||||||
position_ = handle.seek(0, SEEK_END);
|
position_ = handle_.get_frame_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioReaderType ReverseReader::type() const
|
AudioReaderType ReverseReader::type() const
|
||||||
|
|
@ -149,16 +158,16 @@ AudioReaderType ReverseReader::type() const
|
||||||
|
|
||||||
size_t ReverseReader::readNextBlock(float* buffer, size_t frames)
|
size_t ReverseReader::readNextBlock(float* buffer, size_t frames)
|
||||||
{
|
{
|
||||||
sf_count_t position = position_;
|
uint64_t position = position_;
|
||||||
const unsigned channels = handle_.channels();
|
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)
|
if (readFrames <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
position -= readFrames;
|
position -= readFrames;
|
||||||
if (handle_.seek(position, SEEK_SET) != position ||
|
if (!handle_.seek(position) ||
|
||||||
handle_.readf(buffer, readFrames) != readFrames)
|
handle_.read_f32(buffer, readFrames) != readFrames)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
position_ = position;
|
position_ = position;
|
||||||
|
|
@ -173,7 +182,7 @@ size_t ReverseReader::readNextBlock(float* buffer, size_t frames)
|
||||||
*/
|
*/
|
||||||
class NoSeekReverseReader : public BasicSndfileReader {
|
class NoSeekReverseReader : public BasicSndfileReader {
|
||||||
public:
|
public:
|
||||||
explicit NoSeekReverseReader(SndfileHandle handle);
|
explicit NoSeekReverseReader(ST_AudioFile handle);
|
||||||
AudioReaderType type() const override;
|
AudioReaderType type() const override;
|
||||||
size_t readNextBlock(float* buffer, size_t frames) override;
|
size_t readNextBlock(float* buffer, size_t frames) override;
|
||||||
|
|
||||||
|
|
@ -182,11 +191,11 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<float[]> fileBuffer_;
|
std::unique_ptr<float[]> fileBuffer_;
|
||||||
sf_count_t fileFramesLeft_ { 0 };
|
uint64_t fileFramesLeft_ { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
NoSeekReverseReader::NoSeekReverseReader(SndfileHandle handle)
|
NoSeekReverseReader::NoSeekReverseReader(ST_AudioFile handle)
|
||||||
: BasicSndfileReader(handle)
|
: BasicSndfileReader(std::move(handle))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,9 +212,9 @@ size_t NoSeekReverseReader::readNextBlock(float* buffer, size_t frames)
|
||||||
fileBuffer = fileBuffer_.get();
|
fileBuffer = fileBuffer_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned channels = handle_.channels();
|
const unsigned channels = handle_.get_channels();
|
||||||
const sf_count_t fileFramesLeft = fileFramesLeft_;
|
const uint64_t fileFramesLeft = fileFramesLeft_;
|
||||||
sf_count_t readFrames = std::min<sf_count_t>(frames, fileFramesLeft);
|
uint64_t readFrames = std::min<uint64_t>(frames, fileFramesLeft);
|
||||||
if (readFrames <= 0)
|
if (readFrames <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -220,15 +229,16 @@ size_t NoSeekReverseReader::readNextBlock(float* buffer, size_t frames)
|
||||||
|
|
||||||
void NoSeekReverseReader::readWholeFile()
|
void NoSeekReverseReader::readWholeFile()
|
||||||
{
|
{
|
||||||
const sf_count_t frames = handle_.frames();
|
const uint64_t frames = handle_.get_frame_count();
|
||||||
const unsigned channels = handle_.channels();
|
const unsigned channels = handle_.get_channels();
|
||||||
float* fileBuffer = new float[channels * frames];
|
float* fileBuffer = new float[channels * frames];
|
||||||
fileBuffer_.reset(fileBuffer);
|
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()
|
const std::error_category& sndfile_category()
|
||||||
{
|
{
|
||||||
class sndfile_category : public std::error_category {
|
class sndfile_category : public std::error_category {
|
||||||
|
|
@ -248,6 +258,26 @@ const std::error_category& sndfile_category()
|
||||||
static const sndfile_category cat;
|
static const sndfile_category cat;
|
||||||
return 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 channels() const override { return 1; }
|
||||||
unsigned sampleRate() const override { return 44100; }
|
unsigned sampleRate() const override { return 44100; }
|
||||||
size_t readNextBlock(float*, size_t) override { return 0; }
|
size_t readNextBlock(float*, size_t) override { return 0; }
|
||||||
bool getInstrument(SF_INSTRUMENT* ) override { return false; }
|
bool getInstrument(InstrumentInfo* ) override { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioReaderType type_ {};
|
AudioReaderType type_ {};
|
||||||
|
|
@ -268,6 +298,7 @@ private:
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
|
||||||
static bool formatHasFastSeeking(int format)
|
static bool formatHasFastSeeking(int format)
|
||||||
{
|
{
|
||||||
bool fast;
|
bool fast;
|
||||||
|
|
@ -300,8 +331,9 @@ static bool formatHasFastSeeking(int format)
|
||||||
|
|
||||||
return fast;
|
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;
|
AudioReaderPtr reader;
|
||||||
|
|
||||||
|
|
@ -310,30 +342,38 @@ static AudioReaderPtr createAudioReaderWithHandle(SndfileHandle handle, bool rev
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
if (ec)
|
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));
|
reader.reset(new DummyAudioReader(reverse ? AudioReaderType::Reverse : AudioReaderType::Forward));
|
||||||
}
|
}
|
||||||
else if (!reverse)
|
else if (!reverse)
|
||||||
reader.reset(new ForwardReader(handle));
|
reader.reset(new ForwardReader(std::move(handle)));
|
||||||
else if (formatHasFastSeeking(handle.format()))
|
else {
|
||||||
reader.reset(new ReverseReader(handle));
|
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
|
||||||
else
|
bool hasFastSeeking = formatHasFastSeeking(handle.get_sndfile_format());
|
||||||
reader.reset(new NoSeekReverseReader(handle));
|
#else
|
||||||
|
bool hasFastSeeking = true;
|
||||||
|
#endif
|
||||||
|
if (hasFastSeeking)
|
||||||
|
reader.reset(new ReverseReader(std::move(handle)));
|
||||||
|
else
|
||||||
|
reader.reset(new NoSeekReverseReader(std::move(handle)));
|
||||||
|
}
|
||||||
|
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_code* ec)
|
AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_code* ec)
|
||||||
{
|
{
|
||||||
|
ST_AudioFile handle;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
SndfileHandle handle(path.wstring().c_str());
|
handle.open_file_w(path.wstring().c_str());
|
||||||
#else
|
#else
|
||||||
SndfileHandle handle(path.c_str());
|
handle.open_file(path.c_str());
|
||||||
#endif
|
#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;
|
AudioReaderPtr reader;
|
||||||
|
|
||||||
|
|
@ -342,19 +382,19 @@ static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle,
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
if (ec)
|
if (ec)
|
||||||
*ec = std::error_code(handle.error(), sndfile_category());
|
*ec = std::error_code(1, undetailed_category());
|
||||||
reader.reset(new DummyAudioReader(type));
|
reader.reset(new DummyAudioReader(type));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AudioReaderType::Forward:
|
case AudioReaderType::Forward:
|
||||||
reader.reset(new ForwardReader(handle));
|
reader.reset(new ForwardReader(std::move(handle)));
|
||||||
break;
|
break;
|
||||||
case AudioReaderType::Reverse:
|
case AudioReaderType::Reverse:
|
||||||
reader.reset(new ReverseReader(handle));
|
reader.reset(new ReverseReader(std::move(handle)));
|
||||||
break;
|
break;
|
||||||
case AudioReaderType::NoSeekReverse:
|
case AudioReaderType::NoSeekReverse:
|
||||||
reader.reset(new NoSeekReverseReader(handle));
|
reader.reset(new NoSeekReverseReader(std::move(handle)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -364,12 +404,13 @@ static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle,
|
||||||
|
|
||||||
AudioReaderPtr createExplicitAudioReader(const fs::path& path, AudioReaderType type, std::error_code* ec)
|
AudioReaderPtr createExplicitAudioReader(const fs::path& path, AudioReaderType type, std::error_code* ec)
|
||||||
{
|
{
|
||||||
|
ST_AudioFile handle;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
SndfileHandle handle(path.wstring().c_str());
|
handle.open_file_w(path.wstring().c_str());
|
||||||
#else
|
#else
|
||||||
SndfileHandle handle(path.c_str());
|
handle.open_file(path.c_str());
|
||||||
#endif
|
#endif
|
||||||
return createExplicitAudioReaderWithHandle(handle, type, ec);
|
return createExplicitAudioReaderWithHandle(std::move(handle), type, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sfz
|
} // namespace sfz
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "absl/types/span.h"
|
#include "absl/types/span.h"
|
||||||
#include "ghc/fs_std.hpp"
|
#include "ghc/fs_std.hpp"
|
||||||
|
#include <st_audiofile.h>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#if defined(_WIN32)
|
|
||||||
#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sndfile.h>
|
|
||||||
|
|
||||||
namespace sfz {
|
namespace sfz {
|
||||||
|
struct InstrumentInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Designation of a particular kind of audio reader
|
* @brief Designation of a particular kind of audio reader
|
||||||
|
|
@ -42,7 +39,7 @@ public:
|
||||||
virtual unsigned channels() const = 0;
|
virtual unsigned channels() const = 0;
|
||||||
virtual unsigned sampleRate() const = 0;
|
virtual unsigned sampleRate() const = 0;
|
||||||
virtual size_t readNextBlock(float* buffer, size_t frames) = 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;
|
typedef std::unique_ptr<AudioReader> AudioReaderPtr;
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ size_t FileMetadataReader::Impl::readRiffData(size_t index, void* buffer, size_t
|
||||||
return fread(buffer, 1, count, stream);
|
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'});
|
const RiffChunkInfo* riff = riffChunkById(RiffChunkId{'s', 'm', 'p', 'l'});
|
||||||
if (!riff)
|
if (!riff)
|
||||||
|
|
@ -278,16 +278,16 @@ bool FileMetadataReader::extractRiffInstrument(SF_INSTRUMENT& ins)
|
||||||
|
|
||||||
switch (extractU32(loopOffset + 0x04)) {
|
switch (extractU32(loopOffset + 0x04)) {
|
||||||
default:
|
default:
|
||||||
ins.loops[i].mode = SF_LOOP_NONE;
|
ins.loops[i].mode = LoopNone;
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
ins.loops[i].mode = SF_LOOP_FORWARD;
|
ins.loops[i].mode = LoopForward;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
ins.loops[i].mode = SF_LOOP_ALTERNATING;
|
ins.loops[i].mode = LoopAlternating;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
ins.loops[i].mode = SF_LOOP_BACKWARD;
|
ins.loops[i].mode = LoopBackward;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,13 @@
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#if defined(ST_AUDIO_FILE_USE_SNDFILE)
|
||||||
|
#include <sndfile.h>
|
||||||
|
#endif
|
||||||
#include "ghc/fs_std.hpp"
|
#include "ghc/fs_std.hpp"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#if defined(_WIN32)
|
|
||||||
#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sndfile.h>
|
|
||||||
|
|
||||||
namespace sfz {
|
namespace sfz {
|
||||||
|
|
||||||
|
|
@ -26,6 +24,44 @@ struct RiffChunkInfo {
|
||||||
uint32_t length;
|
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 {
|
struct WavetableInfo {
|
||||||
/**
|
/**
|
||||||
@brief Size of each successive table in the file
|
@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
|
* @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
|
* @brief Extract the wavetable information from various relevant RIFF chunks
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <sndfile.hh>
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
|
|
@ -235,7 +234,7 @@ absl::optional<sfz::FileInformation> sfz::FilePool::getFileInformation(const Fil
|
||||||
returnedValue.sampleRate = static_cast<double>(reader->sampleRate());
|
returnedValue.sampleRate = static_cast<double>(reader->sampleRate());
|
||||||
returnedValue.numChannels = reader->channels();
|
returnedValue.numChannels = reader->channels();
|
||||||
|
|
||||||
SF_INSTRUMENT instrumentInfo {};
|
InstrumentInfo instrumentInfo {};
|
||||||
bool haveInstrumentInfo = reader->getInstrument(&instrumentInfo);
|
bool haveInstrumentInfo = reader->getInstrument(&instrumentInfo);
|
||||||
|
|
||||||
FileMetadataReader mdReader;
|
FileMetadataReader mdReader;
|
||||||
|
|
|
||||||
|
|
@ -88,10 +88,10 @@ if(JACK_FOUND AND TARGET Qt5::Widgets)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(eq_apply EQ.cpp)
|
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)
|
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)
|
add_executable(sfizz_plot_curve PlotCurve.cpp)
|
||||||
target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz)
|
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)
|
target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::sfizz)
|
||||||
|
|
||||||
add_executable(sfizz_plot_lfo PlotLFO.cpp)
|
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)
|
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)
|
add_executable(sfizz_file_wavetable FileWavetable.cpp)
|
||||||
target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::sfizz)
|
target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::sfizz)
|
||||||
|
|
|
||||||
|
|
@ -12,20 +12,21 @@
|
||||||
static const char* modeString(int mode, const char* valueFallback = nullptr)
|
static const char* modeString(int mode, const char* valueFallback = nullptr)
|
||||||
{
|
{
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case SF_LOOP_NONE:
|
case sfz::LoopNone:
|
||||||
return "none";
|
return "none";
|
||||||
case SF_LOOP_FORWARD:
|
case sfz::LoopForward:
|
||||||
return "forward";
|
return "forward";
|
||||||
case SF_LOOP_BACKWARD:
|
case sfz::LoopBackward:
|
||||||
return "backward";
|
return "backward";
|
||||||
case SF_LOOP_ALTERNATING:
|
case sfz::LoopAlternating:
|
||||||
return "alternating";
|
return "alternating";
|
||||||
default:
|
default:
|
||||||
return valueFallback;
|
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("Gain: %d\n", ins.gain);
|
||||||
printf("Base note: %d\n", ins.basenote);
|
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("Key: %d:%d\n", ins.key_lo, ins.key_hi);
|
||||||
printf("Loop count: %d\n", ins.loop_count);
|
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("\nLoop %d:\n", i + 1);
|
||||||
printf("\tMode: %s\n", modeString(ins.loops[i].mode, "(unknown)"));
|
printf("\tMode: %s\n", modeString(ins.loops[i].mode, "(unknown)"));
|
||||||
printf("\tStart: %u\n", ins.loops[i].start);
|
printf("\tStart: %u\n", ins.loops[i].start);
|
||||||
|
|
@ -83,18 +84,18 @@ int main(int argc, char *argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SF_INSTRUMENT ins {};
|
|
||||||
|
|
||||||
if (method == kMethodRiff) {
|
if (method == kMethodRiff) {
|
||||||
sfz::FileMetadataReader reader;
|
sfz::FileMetadataReader reader;
|
||||||
if (!reader.open(path)) {
|
if (!reader.open(path)) {
|
||||||
fprintf(stderr, "Cannot open file\n");
|
fprintf(stderr, "Cannot open file\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
sfz::InstrumentInfo ins {};
|
||||||
if (!reader.extractRiffInstrument(ins)) {
|
if (!reader.extractRiffInstrument(ins)) {
|
||||||
fprintf(stderr, "Cannot get instrument\n");
|
fprintf(stderr, "Cannot get instrument\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
printInstrument(ins);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SndfileHandle sndFile(path);
|
SndfileHandle sndFile(path);
|
||||||
|
|
@ -102,13 +103,13 @@ int main(int argc, char *argv[])
|
||||||
fprintf(stderr, "Cannot open file\n");
|
fprintf(stderr, "Cannot open file\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
SF_INSTRUMENT ins {};
|
||||||
if (sndFile.command(SFC_GET_INSTRUMENT, &ins, sizeof(ins)) != 1) {
|
if (sndFile.command(SFC_GET_INSTRUMENT, &ins, sizeof(ins)) != 1) {
|
||||||
fprintf(stderr, "Cannot get instrument\n");
|
fprintf(stderr, "Cannot get instrument\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
printInstrument(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
printInstrument(ins);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue