// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include #include #include "Decoder.hpp" #include "decoderMP3.hpp" #include "decoderFLAC.hpp" #include "decoderWAV.hpp" #include "fileref.h" #include "tag.h" #include "tfilestream.h" namespace audio { Decoder::Decoder(const char *fileName) : filePath(fileName), workerBuffer(std::make_unique(workerBufferSize)), tag(std::make_unique()) { fd = std::fopen(fileName, "r"); if (fd == NULL) { return; } std::fseek(fd, 0, SEEK_END); fileSize = std::ftell(fd); std::rewind(fd); } Decoder::~Decoder() { if (audioWorker) { audioWorker->close(); } if (fd) { std::fclose(fd); } } std::unique_ptr Decoder::fetchTags() { if (fd) { auto inPos = std::ftell(fd); std::rewind(fd); TagLib::FileStream fileStream(fd); TagLib::FileRef tagReader(&fileStream); if (!tagReader.isNull() && tagReader.tag()) { TagLib::Tag *tags = tagReader.tag(); TagLib::AudioProperties *properties = tagReader.audioProperties(); tag->title = tags->title().to8Bit(); tag->artist = tags->artist().to8Bit(); tag->album = tags->album().to8Bit(); tag->genre = tags->genre().to8Bit(); tag->year = std::to_string(tags->year()); tag->total_duration_s = properties->length(); tag->duration_min = tag->total_duration_s / utils::secondsInMinute; tag->duration_hour = tag->duration_min / utils::secondsInMinute; tag->duration_sec = tag->total_duration_s % utils::secondsInMinute; tag->sample_rate = properties->sampleRate(); tag->num_channel = properties->channels(); tag->bitrate = properties->bitrate(); } std::rewind(fd); fetchTagsSpecific(); std::fseek(fd, inPos, SEEK_SET); } tag->filePath.append(filePath); // If title tag empty fill it with raw file name if (tag->title.size() == 0) { if (const auto pos = filePath.rfind("/"); pos == std::string::npos) { tag->title.append(filePath); } else { tag->title.append(&filePath[pos + 1]); } } return std::make_unique(*tag); } std::unique_ptr Decoder::Create(const char *file) { std::unique_ptr dec; if ((strstr(file, ".wav") != NULL) || (strstr(file, ".WAV") != NULL)) { dec = std::make_unique(file); } else if ((strstr(file, ".mp3") != NULL) || (strstr(file, ".MP3") != NULL)) { dec = std::make_unique(file); } else if ((strstr(file, ".flac") != NULL) || (strstr(file, ".FLAC") != NULL)) { dec = std::make_unique(file); } else { return nullptr; } if (!dec->isInitialized) { return nullptr; } else { return dec; } } void Decoder::convertmono2stereo(int16_t *pcm, uint32_t samplecount) { uint32_t i = 0, j = 0; memset(workerBuffer.get(), 0, workerBufferSize * sizeof(int16_t)); for (; j < samplecount; j++) { workerBuffer[i++] = pcm[j]; workerBuffer[i++] = pcm[j]; } memcpy(pcm, &workerBuffer[0], samplecount * 2 * sizeof(int16_t)); } void Decoder::startDecodingWorker(DecoderWorker::EndOfFileCallback endOfFileCallback) { assert(_stream != nullptr); if (!audioWorker) { audioWorker = std::make_unique(_stream, this, endOfFileCallback); audioWorker->init(); audioWorker->run(); } else { LOG_DEBUG("AudioWorker already running."); } } void Decoder::stopDecodingWorker() { if (audioWorker) { audioWorker->close(); } audioWorker = nullptr; } void Decoder::onDataReceive() { audioWorker->enablePlayback(); } void Decoder::enableInput() { audioWorker->enablePlayback(); } void Decoder::disableInput() { audioWorker->disablePlayback(); } } // namespace audio