Skip to content

Commit 6c1f425

Browse files
committed
configurable music gap
1 parent 3115a7a commit 6c1f425

4 files changed

Lines changed: 67 additions & 3 deletions

File tree

examples/ppuc-pinmame.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ SpeechFile =
2929
# Optional comma-separated MP3 playlist for gameplay background music.
3030
MusicFiles =
3131

32+
# Optional gap between background music tracks in milliseconds.
33+
MusicGapMs = 2000
34+
3235
# Optional translite image for in-game mode.
3336
Translite =
3437

src/AudioOutput.cpp

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ constexpr float kMusicBaseGain = 0.28f;
1616
constexpr float kMusicDuckGain = 0.08f;
1717
constexpr float kMusicAttackPerSample = 0.00012f;
1818
constexpr float kMusicReleasePerSample = 0.00003f;
19-
2019
static int16_t ClampMixedSample(int value)
2120
{
2221
if (value > std::numeric_limits<int16_t>::max())
@@ -147,6 +146,10 @@ bool AudioOutput::LoadMusicFilesCsv(const char* csv, std::string* errorMessage)
147146
musicTrackIndex_ = 0;
148147
musicGain_ = 0.0f;
149148
musicEnabled_ = false;
149+
#if defined(PPUC_HAS_SDL3_MIXER)
150+
musicTrackStartPending_ = false;
151+
musicTrackStartTickMs_ = 0;
152+
#endif
150153

151154
#if defined(PPUC_HAS_SDL3_MIXER)
152155
return ReloadMusicTracksLocked(errorMessage);
@@ -162,6 +165,7 @@ bool AudioOutput::LoadMusicFilesCsv(const char* csv, std::string* errorMessage)
162165
void AudioOutput::SetMusicEnabled(bool enabled)
163166
{
164167
std::lock_guard<std::mutex> lock(mutex_);
168+
const bool wasEnabled = musicEnabled_;
165169
musicEnabled_ = enabled;
166170

167171
#if defined(PPUC_HAS_SDL3_MIXER)
@@ -176,7 +180,13 @@ void AudioOutput::SetMusicEnabled(bool enabled)
176180
return;
177181
}
178182

179-
if (MIX_TrackPaused(musicTrack_))
183+
if (!wasEnabled)
184+
{
185+
musicTrackStartPending_ = false;
186+
musicTrackStartTickMs_ = 0;
187+
StartCurrentMusicTrackLocked();
188+
}
189+
else if (MIX_TrackPaused(musicTrack_))
180190
{
181191
MIX_ResumeTrack(musicTrack_);
182192
}
@@ -187,6 +197,16 @@ void AudioOutput::SetMusicEnabled(bool enabled)
187197
#endif
188198
}
189199

200+
void AudioOutput::SetMusicTrackGapMs(Uint64 gapMs)
201+
{
202+
std::lock_guard<std::mutex> lock(mutex_);
203+
#if defined(PPUC_HAS_SDL3_MIXER)
204+
musicTrackGapMs_ = gapMs;
205+
#else
206+
(void)gapMs;
207+
#endif
208+
}
209+
190210
void AudioOutput::QueueGameFrames(const int16_t* samples, size_t frameCount)
191211
{
192212
if (samples == nullptr || frameCount == 0)
@@ -379,6 +399,22 @@ void AudioOutput::MixMusicLocked(int16_t* mixBuffer, size_t sampleCount,
379399
return;
380400
}
381401

402+
if (musicTrackStartPending_)
403+
{
404+
if (SDL_GetTicks() < musicTrackStartTickMs_)
405+
{
406+
return;
407+
}
408+
409+
musicTrackStartPending_ = false;
410+
musicTrackStartTickMs_ = 0;
411+
if (!StartCurrentMusicTrackLocked())
412+
{
413+
musicGain_ = 0.0f;
414+
return;
415+
}
416+
}
417+
382418
std::vector<int16_t> musicBuffer(sampleCount, 0);
383419
const int generatedBytes =
384420
MIX_Generate(musicMixer_, musicBuffer.data(),
@@ -542,6 +578,9 @@ bool AudioOutput::StartCurrentMusicTrackLocked()
542578
return true;
543579
}
544580

581+
musicTrackStartPending_ = false;
582+
musicTrackStartTickMs_ = 0;
583+
545584
for (size_t attempts = 0; attempts < musicTracks_.size(); ++attempts)
546585
{
547586
MusicTrack& currentTrack = musicTracks_[musicTrackIndex_];
@@ -563,6 +602,12 @@ bool AudioOutput::StartCurrentMusicTrackLocked()
563602
return true;
564603
}
565604

605+
void AudioOutput::ScheduleNextMusicTrackLocked()
606+
{
607+
musicTrackStartPending_ = true;
608+
musicTrackStartTickMs_ = SDL_GetTicks() + musicTrackGapMs_;
609+
}
610+
566611
void AudioOutput::AdvanceMusicTrackLocked()
567612
{
568613
if (!musicTracks_.empty())
@@ -581,7 +626,7 @@ void AudioOutput::HandleMusicTrackStoppedLocked(MIX_Track* track)
581626
AdvanceMusicTrackLocked();
582627
if (musicEnabled_)
583628
{
584-
StartCurrentMusicTrackLocked();
629+
ScheduleNextMusicTrackLocked();
585630
}
586631
}
587632
#endif

src/AudioOutput.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class AudioOutput
2626

2727
void ConfigureGameFormat(int frequency, int channels);
2828
bool LoadMusicFilesCsv(const char* csv, std::string* errorMessage);
29+
void SetMusicTrackGapMs(Uint64 gapMs);
2930
void SetMusicEnabled(bool enabled);
3031
void QueueGameFrames(const int16_t* samples, size_t frameCount);
3132
void QueueSpeechSamples(const int16_t* samples, size_t sampleCount,
@@ -70,6 +71,7 @@ class AudioOutput
7071
void DestroyMusicTracksLocked();
7172
bool ReloadMusicTracksLocked(std::string* errorMessage);
7273
bool StartCurrentMusicTrackLocked();
74+
void ScheduleNextMusicTrackLocked();
7375
void AdvanceMusicTrackLocked();
7476
void HandleMusicTrackStoppedLocked(MIX_Track* track);
7577
#endif
@@ -89,6 +91,9 @@ class AudioOutput
8991
#if defined(PPUC_HAS_SDL3_MIXER)
9092
MIX_Mixer* musicMixer_ = nullptr;
9193
MIX_Track* musicTrack_ = nullptr;
94+
bool musicTrackStartPending_ = false;
95+
Uint64 musicTrackStartTickMs_ = 0;
96+
Uint64 musicTrackGapMs_ = 2000;
9297
#endif
9398
size_t musicTrackIndex_ = 0;
9499
bool musicEnabled_ = false;

src/ppuc.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ bool opt_speech = false;
254254
bool opt_greeting = false;
255255
const char* opt_speech_file = NULL;
256256
const char* opt_music_files = NULL;
257+
uint32_t opt_music_gap_ms = 2000;
257258
const char* opt_speech_backend = "auto";
258259
const char* opt_speech_voice = NULL;
259260
const char* opt_speech_rate_arg = NULL;
@@ -1332,6 +1333,10 @@ static struct cag_option options[] = {
13321333
.access_name = "music-files",
13331334
.value_name = "VALUE",
13341335
.description = "Comma-separated MP3 playlist for in-game background music (optional)"},
1336+
{.identifier = 'q',
1337+
.access_name = "music-gap-ms",
1338+
.value_name = "VALUE",
1339+
.description = "Gap between background music tracks in milliseconds (optional, default 2000)"},
13351340
{.identifier = 'U',
13361341
.access_name = "speech-backend",
13371342
.value_name = "VALUE",
@@ -1951,6 +1956,8 @@ int main(int argc, char** argv)
19511956
opt_speech_file = DuplicateOptionalIniString(value);
19521957
else if (key == "MusicFiles")
19531958
opt_music_files = DuplicateOptionalIniString(value);
1959+
else if (key == "MusicGapMs")
1960+
opt_music_gap_ms = static_cast<uint32_t>(atoi(value.c_str()));
19541961
else if (key == "Translite")
19551962
opt_translite = DuplicateOptionalIniString(value);
19561963
else if (key == "TransliteAttract")
@@ -2124,6 +2131,9 @@ int main(int argc, char** argv)
21242131
case 'o':
21252132
opt_music_files = cag_option_get_value(&cag_context);
21262133
break;
2134+
case 'q':
2135+
opt_music_gap_ms = static_cast<uint32_t>(atoi(cag_option_get_value(&cag_context)));
2136+
break;
21272137
case 'U':
21282138
opt_speech_backend = cag_option_get_value(&cag_context);
21292139
break;
@@ -2370,6 +2380,7 @@ int main(int argc, char** argv)
23702380
printf("Audio output init failed: %s\n", SDL_GetError());
23712381
return 1;
23722382
}
2383+
pAudioOutput->SetMusicTrackGapMs(opt_music_gap_ms);
23732384

23742385
if (HasOptionValue(opt_music_files))
23752386
{

0 commit comments

Comments
 (0)