Skip to content
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 42 additions & 15 deletions src/core/SampleDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace lmms {

namespace {

using Decoder = std::optional<SampleDecoder::Result>(*)(const QString&);
using Decoder = std::optional<SampleDecoder::Result> (*)(const QString&);

auto decodeSampleSF(const QString& audioFile) -> std::optional<SampleDecoder::Result>;
auto decodeSampleDS(const QString& audioFile) -> std::optional<SampleDecoder::Result>;
Expand Down Expand Up @@ -116,15 +116,46 @@ auto decodeSampleDS(const QString& audioFile) -> std::optional<SampleDecoder::Re
#ifdef LMMS_HAVE_OGGVORBIS
auto decodeSampleOggVorbis(const QString& audioFile) -> std::optional<SampleDecoder::Result>
{
auto vorbisFile = OggVorbis_File{};
const auto openError = ov_fopen(audioFile.toLocal8Bit(), &vorbisFile);
static auto s_read = [](void* buffer, size_t size, size_t count, void* stream) -> size_t {
auto file = static_cast<QFile*>(stream);
return file->read(static_cast<char*>(buffer), size * count);
};

static auto s_seek = [](void* stream, ogg_int64_t offset, int whence) -> int {
auto file = static_cast<QFile*>(stream);
if (whence == SEEK_SET) { file->seek(offset); }
else if (whence == SEEK_CUR) { file->seek(file->pos() + offset); }
else if (whence == SEEK_END) { file->seek(file->size() + offset); }
else { return -1; }
return 0;
};

static auto s_close = [](void* stream) -> int {
auto file = static_cast<QFile*>(stream);
file->close();
return 0;
};

static auto s_tell = [](void* stream) -> long {
auto file = static_cast<QFile*>(stream);
return file->pos();
};

static ov_callbacks s_callbacks = {s_read, s_seek, s_close, s_tell};

if (openError != 0) { return std::nullopt; }
auto file = QFile{audioFile};
if (!file.open(QIODevice::ReadOnly)) { return std::nullopt; }

auto vorbisFile = OggVorbis_File{};
if (ov_open_callbacks(&file, &vorbisFile, nullptr, 0, s_callbacks) < 0) { return std::nullopt; }

const auto vorbisInfo = ov_info(&vorbisFile, -1);
if (vorbisInfo == nullptr) { return std::nullopt; }

const auto numChannels = vorbisInfo->channels;
const auto sampleRate = vorbisInfo->rate;
const auto numSamples = ov_pcm_total(&vorbisFile, -1);
if (numSamples < 0) { return std::nullopt; }

auto buffer = std::vector<float>(numSamples);
auto output = static_cast<float**>(nullptr);
Expand All @@ -141,23 +172,22 @@ auto decodeSampleOggVorbis(const QString& audioFile) -> std::optional<SampleDeco
totalSamplesRead += samplesRead;
}

ov_clear(&vorbisFile);
auto result = std::vector<sampleFrame>(numSamples / numChannels);
for (int i = 0; i < buffer.size(); ++i)
auto result = std::vector<sampleFrame>(totalSamplesRead / numChannels);
for (int i = 0; i < result.size(); ++i)
{
if (numChannels == 1) { result[i] = {buffer[i], buffer[i]}; }
else if (numChannels > 1) { result[i] = {buffer[i * numChannels], buffer[i * numChannels + 1]}; }
}

ov_clear(&vorbisFile);
return SampleDecoder::Result{std::move(result), static_cast<int>(sampleRate)};
}
#endif // LMMS_HAVE_OGGVORBIS
} // namespace

auto SampleDecoder::supportedAudioTypes() -> const std::vector<AudioType>&
{
static const auto s_audioTypes = []
{
static const auto s_audioTypes = [] {
auto types = std::vector<AudioType>();

// Add DrumSynth by default since that support comes from us
Expand All @@ -167,8 +197,8 @@ auto SampleDecoder::supportedAudioTypes() -> const std::vector<AudioType>&
auto simpleTypeCount = 0;
sf_command(nullptr, SFC_GET_SIMPLE_FORMAT_COUNT, &simpleTypeCount, sizeof(int));

// TODO: Ideally, this code should be iterating over the major formats, but some important extensions such as *.ogg
// are not included. This is planned for future versions of sndfile.
// TODO: Ideally, this code should be iterating over the major formats, but some important extensions such as
// *.ogg are not included. This is planned for future versions of sndfile.
for (int simple = 0; simple < simpleTypeCount; ++simple)
{
sfFormatInfo.format = simple;
Expand All @@ -182,12 +212,9 @@ auto SampleDecoder::supportedAudioTypes() -> const std::vector<AudioType>&
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char ch) { return std::toupper(ch); });

types.push_back(AudioType{std::move(name), sfFormatInfo.extension});

return types;
}

std::sort(types.begin(), types.end(),
[&](const AudioType& a, const AudioType& b) { return a.name < b.name; });
std::sort(types.begin(), types.end(), [&](const AudioType& a, const AudioType& b) { return a.name < b.name; });
return types;
}();
return s_audioTypes;
Expand Down