Added global looping option to the GmeDecoder and fixed the way the end

of song is detected.
This commit is contained in:
casey langen 2019-01-05 16:36:06 -08:00
parent 87c9598c97
commit 3888535c83
4 changed files with 78 additions and 28 deletions

View File

@ -189,7 +189,16 @@ struct musik::cube::TransportDisplayCache {
return stringToColumns[str];
}
std::string CurrentTime(int secondsCurrent) {
if (secondsTotal != INT_MIN) {
secondsCurrent = std::min(secondsCurrent, secondsTotal);
}
return musik::core::duration::Duration(secondsCurrent);
}
void Update(ITransport& transport, TrackPtr track) {
/* some params don't update regularly at all, so we can safely
cache them as long as the track hasn't actually changed. */
if (this->track != track) {
this->Reset();
@ -207,21 +216,32 @@ struct musik::cube::TransportDisplayCache {
artist = this->track->GetString(constants::Track::ARTIST);
artist = artist.size() ? artist : Strings.EMPTY_ARTIST;
artistCols = u8cols(artist);
secondsTotal = (int)transport.GetDuration();
if (secondsTotal <= 0) {
std::string duration =
this->track->GetString(constants::Track::DURATION);
if (duration.size()) {
secondsTotal = boost::lexical_cast<int>(duration);
}
}
totalTime = musik::core::duration::Duration(secondsTotal);
totalTimeCols = u8cols(totalTime);
}
}
/* we check duration even if the track is the same because
looping params may have changed. */
auto updatedTotal = (int)transport.GetDuration();
if (updatedTotal != secondsTotal) {
secondsTotal = updatedTotal;
if (secondsTotal <= 0 && secondsTotal != INT_MIN) {
std::string duration =
this->track->GetString(constants::Track::DURATION);
if (duration.size()) {
secondsTotal = boost::lexical_cast<int>(duration);
}
}
if (secondsTotal >= 0) {
totalTime = musik::core::duration::Duration(secondsTotal);
}
else {
totalTime = "";
}
totalTimeCols = u8cols(totalTime);
}
}
};
@ -657,8 +677,8 @@ void TransportWindow::Update(TimeMode timeMode) {
secondsCurrent = (int) round(this->lastTime);
}
const std::string currentTime = musik::core::duration::Duration(
std::min(secondsCurrent, displayCache->secondsTotal));
const std::string currentTime =
displayCache->CurrentTime(secondsCurrent);
const std::string replayGain = replayGainEnabled ? "rg" : "";

View File

@ -57,6 +57,8 @@
static const char* PLUGIN_NAME = "GME IDecoder";
static const char* KEY_ALWAYS_LOOP_FOREVER = "always_loop_forever";
static const bool DEFAULT_ALWAYS_LOOP_FOREVER = false;
static const char* KEY_DEFAULT_TRACK_LENGTH = "default_track_length_secs";
static const double DEFAULT_TRACK_LENGTH = 60.0 * 3.0;
static const char* KEY_TRACK_FADE_OUT_LENGTH = "track_fade_out_length_secs";
@ -94,6 +96,7 @@ static inline std::wstring u8to16(const char* utf8) {
static inline musik::core::sdk::ISchema* CreateSchema() {
auto schema = new musik::core::sdk::TSchema<>();
schema->AddBool(KEY_ALWAYS_LOOP_FOREVER, DEFAULT_ALWAYS_LOOP_FOREVER);
schema->AddDouble(KEY_DEFAULT_TRACK_LENGTH, DEFAULT_TRACK_LENGTH);
schema->AddDouble(KEY_TRACK_FADE_OUT_LENGTH, DEFAULT_FADE_OUT_LENGTH);
schema->AddBool(KEY_ENABLE_M3U, DEFAULT_ENABLE_M3U);

View File

@ -35,15 +35,18 @@
#include "Constants.h"
#include "GmeDecoder.h"
#include <core/sdk/IPreferences.h>
#include <core/sdk/IDebug.h>
#include <cassert>
static const int BUFFER_SAMPLE_COUNT = 2048;
static const int CHANNELS = 2;
static const int SAMPLE_RATE = 44100;
static const int SAMPLE_RATE = 48000;
static const int SAMPLES_PER_MS = (SAMPLE_RATE * CHANNELS) / 1000;
static const double LENGTH_FOREVER = INT_MIN;
static const float F_SHRT_MAX = (float) SHRT_MAX;
extern IPreferences* prefs;
extern IDebug* debug;
GmeDecoder::GmeDecoder() {
this->buffer = new short[BUFFER_SAMPLE_COUNT];
@ -84,7 +87,10 @@ bool GmeDecoder::Open(musik::core::sdk::IDataStream *stream) {
this->info = nullptr;
}
else {
if (this->info->length == -1) {
if (prefs->GetBool(KEY_ALWAYS_LOOP_FOREVER, DEFAULT_ALWAYS_LOOP_FOREVER)) {
this->length = LENGTH_FOREVER;
}
else if (this->info->length == -1) {
this->length = prefs->GetDouble(
KEY_DEFAULT_TRACK_LENGTH, DEFAULT_TRACK_LENGTH);
@ -97,9 +103,11 @@ bool GmeDecoder::Open(musik::core::sdk::IDataStream *stream) {
(int)(fadeLength * 1000.0));
}
else {
this->length = (double) this->info->length / 1000.0;
this->length = (double) this->info->play_length / 1000.0;
}
}
this->totalSamples = (int)(this->length * SAMPLE_RATE * CHANNELS);
}
}
delete[] data;
@ -111,9 +119,13 @@ void GmeDecoder::Release() {
}
double GmeDecoder::SetPosition(double seconds) {
std::unique_lock<decltype(this->mutex)> lock(this->mutex);
if (this->gme) {
gme_seek(this->gme, (int)(seconds * 1000.0));
return (double) gme_tell(this->gme) / 1000.0;
auto err = gme_seek(this->gme, (int)(seconds * 1000.0));
if (err) { debug->Error(PLUGIN_NAME, err); }
double position = (double)gme_tell(this->gme) / 1000.0;
this->samplesPlayed = (int)(position * SAMPLE_RATE * CHANNELS);
return position;
}
return 0.0;
}
@ -123,26 +135,36 @@ double GmeDecoder::GetDuration() {
}
bool GmeDecoder::GetBuffer(IBuffer *target) {
std::unique_lock<decltype(this->mutex)> lock(this->mutex);
if (this->gme) {
if (!gme_track_ended(this->gme) &&
!gme_play(this->gme, BUFFER_SAMPLE_COUNT, this->buffer))
int samplesRemaining = totalSamples - samplesPlayed;
bool playFullBuffer =
(samplesRemaining > BUFFER_SAMPLE_COUNT) ||
(this->length == LENGTH_FOREVER);
int bufferSamples = playFullBuffer
? BUFFER_SAMPLE_COUNT : samplesRemaining;
if (bufferSamples > 0 &&
!gme_play(this->gme, bufferSamples, this->buffer))
{
target->SetChannels(CHANNELS);
target->SetSampleRate(SAMPLE_RATE);
target->SetSamples(BUFFER_SAMPLE_COUNT);
target->SetSamples(bufferSamples);
float* dst = target->BufferPointer();
for (size_t i = 0; i < BUFFER_SAMPLE_COUNT; i++) {
dst[i] = (float) this->buffer[i] / F_SHRT_MAX;
}
samplesPlayed += bufferSamples;
return true;
}
}
this->exhausted = true;
return false;
}
bool GmeDecoder::Exhausted() {
if (this->gme) {
return gme_track_ended(this->gme);
}
return true;
return this->exhausted;
}

View File

@ -40,6 +40,7 @@
#include "GmeDataStream.h"
#include <stddef.h>
#include <gme.h>
#include <mutex>
using namespace musik::core::sdk;
@ -60,5 +61,9 @@ class GmeDecoder: public musik::core::sdk::IDecoder {
gme_t* gme { nullptr };
gme_info_t* info { nullptr };
short* buffer;
double length = -1.0;
double length{ -1.0 };
int totalSamples { 0 };
int samplesPlayed { 0 };
bool exhausted { false };
std::mutex mutex;
};