Skip to content

Commit

Permalink
Implement Get MIDI Ticks for non-MIDI formats by returning the playba…
Browse files Browse the repository at this point in the history
…ck position in seconds.

Implemented for mpg123, libvorbisfile and libopusfile.
Works for EmptyAudio and SDLAudio by approximating it through the frame count.

When no BGM is playing the returned value is 0.

Fix EasyRPG#1517
  • Loading branch information
Ghabry authored and fmatthew5876 committed Dec 5, 2018
1 parent 0c4d7ca commit 7c84426
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 12 deletions.
16 changes: 14 additions & 2 deletions src/audio.cpp
Expand Up @@ -20,6 +20,7 @@
#include "system.h"
#include "baseui.h"
#include "player.h"
#include "graphics.h"

AudioInterface& Audio() {
static EmptyAudio default_;
Expand All @@ -32,12 +33,23 @@ AudioInterface& Audio() {

void EmptyAudio::BGM_Play(std::string const&, int, int, int) {
bgm_starttick = Player::GetFrames();
playing = true;
}

void EmptyAudio::BGM_Stop() {
playing = false;
}

unsigned EmptyAudio::BGM_GetTicks() const {
return (Player::GetFrames() - bgm_starttick) * 500; // Arbitrary
if (!playing) {
return 0;
}

// Time since BGM_Play was called, works for everything except MIDI
return (Player::GetFrames() - bgm_starttick + 1) / Graphics::GetDefaultFps();
}

bool EmptyAudio::BGM_PlayedOnce() const {
return BGM_GetTicks() > 5000; // Arbitrary
// 5 seconds, arbitrary
return BGM_GetTicks() > (Graphics::GetDefaultFps() * 5);
}
10 changes: 7 additions & 3 deletions src/audio.h
Expand Up @@ -51,10 +51,10 @@ struct AudioInterface {
* Returns whether the background music has played at least once.
*/
virtual bool BGM_PlayedOnce() const = 0;

/**
* Reports if a music file is currently being played.
*
*
* @return true when BGM is playing
*/
virtual bool BGM_IsPlaying() const = 0;
Expand Down Expand Up @@ -112,10 +112,11 @@ struct AudioInterface {
};

struct EmptyAudio : public AudioInterface {
public:
void BGM_Play(std::string const&, int, int, int) override;
void BGM_Pause() override {}
void BGM_Resume() override {}
void BGM_Stop() override {}
void BGM_Stop() override;
bool BGM_PlayedOnce() const override;
bool BGM_IsPlaying() const override { return false; }
unsigned BGM_GetTicks() const override;
Expand All @@ -126,7 +127,10 @@ struct EmptyAudio : public AudioInterface {
void SE_Stop() override {}
void Update() override {}

private:
unsigned bgm_starttick = 0;

bool playing = false;
};

AudioInterface& Audio();
Expand Down
8 changes: 5 additions & 3 deletions src/audio_decoder.h
Expand Up @@ -249,7 +249,7 @@ class AudioDecoder {
* 200 = double speed and so on
* Not all audio decoders support this. Using the audio hardware is
* recommended.
*
*
* @param pitch Pitch multiplier to use
* @return true if pitch was set, false otherwise
*/
Expand All @@ -275,9 +275,11 @@ class AudioDecoder {
virtual size_t Tell() const;

/**
* Returns amount of executed ticks. Only useful for MIDI format.
* Returns a value suitable for the GetMidiTicks command.
* For MIDI this is the amount of MIDI ticks, for other
* formats usually the playback position in seconds.
*
* @return Amount of MIDI ticks.
* @return Amount of MIDI ticks or position in seconds
*/
virtual int GetTicks() const;

Expand Down
1 change: 1 addition & 0 deletions src/audio_generic.cpp
Expand Up @@ -113,6 +113,7 @@ unsigned GenericAudio::BGM_GetTicks() const {
for (unsigned i = 0; i < nr_of_bgm_channels; i++) {
if (BGM_Channels[i].decoder) {
ticks = BGM_Channels[i].decoder->GetTicks();
break;
}
}
UnlockMutex();
Expand Down
8 changes: 6 additions & 2 deletions src/audio_sdl_mixer.cpp
Expand Up @@ -455,12 +455,16 @@ bool SdlMixerAudio::BGM_IsPlaying() const {
}

unsigned SdlMixerAudio::BGM_GetTicks() const {
if (!BGM_IsPlaying()) {
return 0;
}

if (audio_decoder) {
return audio_decoder->GetTicks();
}

// TODO: Implement properly. This is an approximation.
return SDL_GetTicks() - bgm_starttick;
// Should work for everything except MIDI
return SDL_GetTicks() + 1 - bgm_starttick;
}

void SdlMixerAudio::BGM_Volume(int volume) {
Expand Down
16 changes: 15 additions & 1 deletion src/decoder_mpg123.cpp
Expand Up @@ -94,6 +94,11 @@ bool Mpg123Decoder::Open(FILE* file) {
return false;
}

// Samplerate cached, regularly needed for Ticks function
int ch;
int fmt;
mpg123_getformat(handle.get(), &samplerate, &ch, &fmt);

return true;
}

Expand Down Expand Up @@ -185,6 +190,15 @@ bool Mpg123Decoder::SetFormat(int freq, AudioDecoder::Format fmt, int channels)
return err == MPG123_OK;
}

int Mpg123Decoder::GetTicks() const {
if (samplerate == 0) {
return 0;
}

off_t pos = mpg123_tell(handle.get());
return pos / samplerate;
}

bool Mpg123Decoder::IsMp3(FILE* stream) {
Mpg123Decoder decoder;
// Prevent stream handle destruction
Expand All @@ -199,7 +213,7 @@ bool Mpg123Decoder::IsMp3(FILE* stream) {
int err = 0;
size_t done = 0;
int err_count = 0;

// Read beginning of assumed MP3 file and count errors as an heuristic to detect MP3
for (int i = 0; i < 10; ++i) {
err = mpg123_read(decoder.handle.get(), buffer, 1024, &done);
Expand Down
4 changes: 4 additions & 0 deletions src/decoder_mpg123.h
Expand Up @@ -47,6 +47,8 @@ class Mpg123Decoder : public AudioDecoder {

bool SetFormat(int frequency, AudioDecoder::Format format, int channels) override;

int GetTicks() const override;

static bool IsMp3(FILE* stream);
private:
int FillBuffer(uint8_t* buffer, int length) override;
Expand All @@ -56,6 +58,8 @@ class Mpg123Decoder : public AudioDecoder {
#endif
int err = 0;
bool finished = false;

long samplerate = 0;
};

#endif
9 changes: 8 additions & 1 deletion src/decoder_oggvorbis.cpp
Expand Up @@ -68,7 +68,6 @@ bool OggVorbisDecoder::Open(FILE* file) {
return false;
}

// (long)ov_pcm_total(ovf, -1)) -> decoded length in samples, maybe useful for ticks later?
frequency = vi->rate;
channels = vi->channels;

Expand Down Expand Up @@ -107,6 +106,14 @@ bool OggVorbisDecoder::SetFormat(int freq, AudioDecoder::Format format, int chan
return true;
}

int OggVorbisDecoder::GetTicks() const {
if (!ovf) {
return 0;
}

return (int)ov_time_tell(ovf);
}

int OggVorbisDecoder::FillBuffer(uint8_t* buffer, int length) {
if (!ovf)
return -1;
Expand Down
2 changes: 2 additions & 0 deletions src/decoder_oggvorbis.h
Expand Up @@ -49,6 +49,8 @@ class OggVorbisDecoder : public AudioDecoder {
void GetFormat(int& frequency, AudioDecoder::Format& format, int& channels) const override;

bool SetFormat(int frequency, AudioDecoder::Format format, int channels) override;

int GetTicks() const override;
private:
int FillBuffer(uint8_t* buffer, int length) override;

Expand Down
9 changes: 9 additions & 0 deletions src/decoder_opus.cpp
Expand Up @@ -103,6 +103,15 @@ bool OpusDecoder::SetFormat(int freq, AudioDecoder::Format format, int chans) {
return true;
}

int OpusDecoder::GetTicks() const {
if (!oof) {
return 0;
}

// According to the docs it is number of samples at 48 kHz
return op_pcm_tell(oof) / 48000;
}

int OpusDecoder::FillBuffer(uint8_t* buffer, int length) {
if (!oof)
return -1;
Expand Down
2 changes: 2 additions & 0 deletions src/decoder_opus.h
Expand Up @@ -42,6 +42,8 @@ class OpusDecoder : public AudioDecoder {
void GetFormat(int& frequency, AudioDecoder::Format& format, int& channels) const override;

bool SetFormat(int frequency, AudioDecoder::Format format, int channels) override;

int GetTicks() const override;
private:
int FillBuffer(uint8_t* buffer, int length) override;

Expand Down

0 comments on commit 7c84426

Please sign in to comment.