diff --git a/.gitmodules b/.gitmodules index 1247ca5f..f4453c71 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,7 @@ 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 diff --git a/external/st_audiofile/CMakeLists.txt b/external/st_audiofile/CMakeLists.txt new file mode 100644 index 00000000..137f3201 --- /dev/null +++ b/external/st_audiofile/CMakeLists.txt @@ -0,0 +1,37 @@ +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") + +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 + PRIVATE "${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() diff --git a/external/st_audiofile/LICENSE.md b/external/st_audiofile/LICENSE.md new file mode 100644 index 00000000..bb52be90 --- /dev/null +++ b/external/st_audiofile/LICENSE.md @@ -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. diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c new file mode 100644 index 00000000..efaccb85 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile.c @@ -0,0 +1,206 @@ +// 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 + +struct st_audio_file { + int type; + union { + drwav *wav; + drflac *flac; + }; +}; + +enum { + st_audio_file_null = -1, +}; + +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->type = st_audio_file_null; + + if (af->type == st_audio_file_null) { + af->wav = (drwav*)malloc(sizeof(drwav)); + if (!af->wav) { + free(af); + return NULL; + } + if (!drwav_init_file(af->wav, filename, NULL)) + free(af->wav); + else + af->type = st_audio_file_wav; + } + + if (af->type == st_audio_file_null) { + af->flac = drflac_open_file(filename, NULL); + if (af->flac) + af->type = st_audio_file_flac; + } + + if (af->type == st_audio_file_null) { + free(af); + af = 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->type = st_audio_file_null; + + if (af->type == st_audio_file_null) { + af->wav = (drwav*)malloc(sizeof(drwav)); + if (!af->wav) { + free(af); + return NULL; + } + if (!drwav_init_file_w(af->wav, filename, NULL)) + free(af->wav); + else + af->type = st_audio_file_wav; + } + + if (af->type == st_audio_file_null) { + af->flac = drflac_open_file_w(filename, NULL); + if (af->flac) + af->type = st_audio_file_flac; + } + + if (af->type == st_audio_file_null) { + free(af); + af = NULL; + } + + return af; +} +#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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + return count; +} + +#endif // !defined(ST_AUDIO_FILE_USE_SNDFILE) diff --git a/external/st_audiofile/src/st_audiofile.h b/external/st_audiofile/src/st_audiofile.h new file mode 100644 index 00000000..704addb8 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile.h @@ -0,0 +1,52 @@ +// 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 +#endif +#include +#include +#if defined(_WIN32) +#include +#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_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 diff --git a/external/st_audiofile/src/st_audiofile.hpp b/external/st_audiofile/src/st_audiofile.hpp new file mode 100644 index 00000000..c30da975 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile.hpp @@ -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 diff --git a/external/st_audiofile/src/st_audiofile_common.c b/external/st_audiofile/src/st_audiofile_common.c new file mode 100644 index 00000000..2b6e5d34 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile_common.c @@ -0,0 +1,35 @@ +// 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 + +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_other: + type_string = "other"; + break; + } + + return type_string; +} diff --git a/external/st_audiofile/src/st_audiofile_libs.c b/external/st_audiofile/src/st_audiofile_libs.c new file mode 100644 index 00000000..77ae28c2 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile_libs.c @@ -0,0 +1,9 @@ +// 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 +#include "st_audiofile_libs.h" diff --git a/external/st_audiofile/src/st_audiofile_libs.h b/external/st_audiofile/src/st_audiofile_libs.h new file mode 100644 index 00000000..8620cdce --- /dev/null +++ b/external/st_audiofile/src/st_audiofile_libs.h @@ -0,0 +1,9 @@ +// 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" diff --git a/external/st_audiofile/src/st_audiofile_sndfile.c b/external/st_audiofile/src/st_audiofile_sndfile.c new file mode 100644 index 00000000..5b3e9b9e --- /dev/null +++ b/external/st_audiofile/src/st_audiofile_sndfile.c @@ -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 +#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 +#endif +#include +#include + +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) diff --git a/external/st_audiofile/src/st_info.c b/external/st_audiofile/src/st_info.c new file mode 100644 index 00000000..dc5680f4 --- /dev/null +++ b/external/st_audiofile/src/st_info.c @@ -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 +#include + +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; +} diff --git a/external/st_audiofile/thirdparty/dr_libs b/external/st_audiofile/thirdparty/dr_libs new file mode 160000 index 00000000..cac1785c --- /dev/null +++ b/external/st_audiofile/thirdparty/dr_libs @@ -0,0 +1 @@ +Subproject commit cac1785cee4abb455817b43d5dee33b49d61be2f