psemek/libs/audio/source/track_wav.cpp
2023-07-18 20:40:53 +03:00

81 lines
1.9 KiB
C++

#include <psemek/audio/track.hpp>
#include <psemek/audio/constants.hpp>
#include <psemek/audio/detail/resampler.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/at_scope_exit.hpp>
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
#include <psemek/audio/audio_file/AudioFile.h>
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
namespace psemek::audio
{
namespace
{
std::vector<float> convert_audio(std::vector<std::vector<float>> const & channels, int frequency)
{
if (channels.empty() || channels.size() > 2)
throw std::runtime_error(util::to_string("Can't convert audio with ", static_cast<int>(channels.size()), " channels"));
std::vector<float> result(channels[0].size() * 2);
auto out = result.begin();
if (channels.size() == 1)
{
for (auto p = channels[0].begin(); p != channels[0].end(); ++p)
{
*out++ = *p;
*out++ = *p;
}
}
else if (channels.size() == 2)
{
for (auto p0 = channels[0].begin(), p1 = channels[1].begin(); p0 != channels[0].end(); ++p0, ++p1)
{
*out++ = *p0;
*out++ = *p1;
}
}
if (frequency != audio::frequency)
{
audio::resampler resampler(audio::frequency * 1.f / frequency);
resampler.feed(result);
result = resampler.grab_result();
}
return result;
}
}
track_ptr load_wav(util::span<char const> data)
{
std::vector<std::uint8_t> data_u8(data.size());
std::copy(data.begin(), data.end(), reinterpret_cast<char *>(data_u8.data()));
AudioFile<float> audio_file;
audio_file.shouldLogErrorsToConsole(false);
audio_file.onError = [](std::string const & error) {
throw std::runtime_error("failed to load WAV file: " + error);
};
audio_file.loadFromMemory(data_u8);
return load_raw(convert_audio(audio_file.samples, audio_file.getSampleRate()));
}
track_ptr load_wav(std::vector<char> const & data)
{
return load_wav(util::span<char const>(data));
}
}