mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Player was skipping to next track when pausing for more than X seconds and then resuming playback, etc.
239 lines
7.5 KiB
C++
239 lines
7.5 KiB
C++
#include "pch.h"
|
|
#include "Shared/Audio/AudioPlayerHud.h"
|
|
#include "Shared/Audio/SoundMixer.h"
|
|
#include "Shared/Video/DebugHud.h"
|
|
#include "Shared/Emulator.h"
|
|
#include "Shared/EmuSettings.h"
|
|
#include "Shared/Video/DrawStringCommand.h"
|
|
|
|
static constexpr double PI = 3.14159265358979323846;
|
|
|
|
AudioPlayerHud::AudioPlayerHud(Emulator* emu)
|
|
{
|
|
_emu = emu;
|
|
_mixer = emu->GetSoundMixer();
|
|
_hud = emu->GetDebugHud();
|
|
|
|
for(int i = 0; i < N; i++) {
|
|
_hannWindow[i] = 0.5f * (1.0f - cos(2.0f * PI * (float)(i) / (float)(N - 1.0f)));
|
|
}
|
|
}
|
|
|
|
string AudioPlayerHud::FormatSeconds(uint32_t s)
|
|
{
|
|
string seconds = std::to_string(s % 60);
|
|
if(seconds.size() == 1) {
|
|
seconds = "0" + seconds;
|
|
}
|
|
return std::to_string(s / 60) + ":" + seconds;
|
|
}
|
|
|
|
void AudioPlayerHud::Draw(uint32_t frameCounter, double fps)
|
|
{
|
|
AudioTrackInfo trackInfo = _emu->GetAudioTrackInfo();
|
|
if(trackInfo.Position <= 1) {
|
|
_changeTrackPending = false;
|
|
}
|
|
|
|
_hud->DrawRectangle(0, 0, 256, 240, 0, true, 1);
|
|
|
|
int y = 12;
|
|
auto drawLabel = [=, &y](string label, string content) {
|
|
if(content.size() > 0 && content[0] != 0) {
|
|
_hud->DrawString(10, y, label, 0xBBBBBB, 0, 1);
|
|
_hud->DrawString(57, y, content, 0xFFFFFF, 0, 1);
|
|
y += 10;
|
|
}
|
|
};
|
|
|
|
drawLabel("Game:", trackInfo.GameTitle);
|
|
drawLabel("Artist:", trackInfo.Artist);
|
|
drawLabel("Comment:", trackInfo.Comment);
|
|
|
|
string position = FormatSeconds((uint32_t)trackInfo.Position);
|
|
|
|
string track = "Track: " + std::to_string(trackInfo.TrackNumber) + " / " + std::to_string(trackInfo.TrackCount);
|
|
TextSize size = DrawStringCommand::MeasureString(track);
|
|
uint32_t trackPosX = 256 - size.X - 14;
|
|
_hud->DrawString(trackPosX, 218, track, 0xFFFFFF, 0, 1);
|
|
|
|
string trackName;
|
|
if(trackInfo.SongTitle.size() > 0 && trackInfo.SongTitle[0] != 0) {
|
|
trackName = trackInfo.SongTitle;
|
|
} else {
|
|
trackName = _emu->GetRomInfo().RomFile.GetFileName();
|
|
}
|
|
_hud->DrawString(15, 208, trackName, 0xFFFFFF, 0, 1, -1, trackPosX - 20);
|
|
|
|
if(trackInfo.Length <= 0) {
|
|
_hud->DrawString(215, 208, " " + position + " ", 0xFFFFFF, 0, 1);
|
|
} else {
|
|
position += " / " + FormatSeconds((uint32_t)trackInfo.Length);
|
|
_hud->DrawString(177, 208, " " + position + " ", 0xFFFFFF, 0, 1);
|
|
|
|
constexpr int barWidth = 222;
|
|
_hud->DrawRectangle(15, 199, barWidth + 4, 6, 0xBBBBBB, false, 1);
|
|
//_hud->DrawRectangle(16, 200, barWidth + 2, 4, 0, true, 1);
|
|
_hud->DrawRectangle(17, 201, (int)(std::min(1.0, trackInfo.Position / trackInfo.Length) * barWidth), 2, 0x77BBFF, false, 1);
|
|
}
|
|
|
|
//Arbitrary ranges to split the graph into (8 equally sized sections on the screen that contain a specific freq range)
|
|
static constexpr double ranges[8][3] {
|
|
{ 20, 150, 0.5 },
|
|
{ 150, 400, 0.5 },
|
|
{ 400, 700, 0.75 },
|
|
{ 700, 1000, 0.75 },
|
|
{ 1000, 2000, 1 },
|
|
{ 2000, 4000, 1 },
|
|
{ 4000, 6000, 1.25 },
|
|
{ 6000, 20000, 1.25 }
|
|
};
|
|
|
|
static constexpr int maxVal = 140;
|
|
|
|
int top = 191 - maxVal;
|
|
int bottom = 190;
|
|
int fgColor = 0x555555;
|
|
int fgColor2 = 0x666666;
|
|
int bgColor = 0x222222;
|
|
_hud->DrawLine(0, top - 1, 255, top - 1, fgColor, 1);
|
|
_hud->DrawLine(0, bottom + 1, 255, bottom + 1, fgColor, 1);
|
|
_hud->DrawRectangle(0, top, 256, 140, bgColor, true, 1);
|
|
_hud->DrawLine(192, top, 192, bottom, fgColor, 1);
|
|
_hud->DrawLine(128, top, 128, bottom, fgColor, 1);
|
|
_hud->DrawLine(64, top, 64, bottom, fgColor, 1);
|
|
|
|
_hud->DrawLine(224, top, 224, bottom, fgColor2, 1);
|
|
_hud->DrawLine(160, top, 160, bottom, fgColor2, 1);
|
|
_hud->DrawLine(96, top, 96, bottom, fgColor2, 1);
|
|
_hud->DrawLine(32, top, 32, bottom, fgColor2, 1);
|
|
|
|
_hud->DrawString(3, top + 10, "20Hz", fgColor, bgColor, 1);
|
|
_hud->DrawString(19, top + 30, "150Hz", fgColor2, bgColor, 1);
|
|
_hud->DrawString(51, top + 10, "400Hz", fgColor, bgColor, 1);
|
|
_hud->DrawString(83, top + 30, "700Hz", fgColor2, bgColor, 1);
|
|
_hud->DrawString(117, top + 10, "1kHz", fgColor, bgColor, 1);
|
|
_hud->DrawString(150, top + 30, "2kHz", fgColor2, bgColor, 1);
|
|
_hud->DrawString(182, top + 10, "4kHz", fgColor, bgColor, 1);
|
|
_hud->DrawString(214, top + 30, "6kHz", fgColor2, bgColor, 1);
|
|
_hud->DrawString(228, top + 10, "20kHz", fgColor, bgColor, 1);
|
|
|
|
if(_amplitudes.size() >= N / 2) {
|
|
bool silent = true;
|
|
for(int i = 0; i < 8; i++) {
|
|
for(int j = 0; j < 32; j++) {
|
|
double freqRange = ranges[i][1] - ranges[i][0];
|
|
double startFreq = ranges[i][0] + freqRange * j / 32;
|
|
double endFreq = ranges[i][0] + freqRange * (j + 1) / 32;
|
|
|
|
int startIndex = (int)(startFreq / (_sampleRate / N));
|
|
int endIndex = (int)(endFreq / (_sampleRate / N));
|
|
|
|
double avgAmp = 0;
|
|
for(int ampIndex = startIndex; ampIndex <= endIndex && ampIndex < _amplitudes.size(); ampIndex++) {
|
|
avgAmp += _amplitudes[ampIndex];
|
|
}
|
|
avgAmp /= (endIndex - startIndex + 1);
|
|
avgAmp *= ranges[i][2];
|
|
avgAmp = std::min<double>(maxVal, avgAmp);
|
|
|
|
if(avgAmp >= 1) {
|
|
silent = false;
|
|
}
|
|
|
|
int red = std::min(255, (int)(256 * (avgAmp / maxVal) * 2));
|
|
int green = std::max(0, std::min(255, (int)(256 * ((maxVal - avgAmp) / maxVal) * 2)));
|
|
_hud->DrawRectangle(i*32+j, 190, 1, (int)-avgAmp, red << 16 | green << 8, true, 1);
|
|
}
|
|
}
|
|
|
|
if(_prevFrameCounter + 1 != frameCounter || _prevFps != fps || _lastAudioFrame > frameCounter) {
|
|
//Region changed, save state loaded, etc. - reset silence processing
|
|
_prevFrameCounter = frameCounter;
|
|
_lastAudioFrame = frameCounter;
|
|
_prevFps = fps;
|
|
} else {
|
|
_prevFrameCounter = frameCounter;
|
|
if(!silent) {
|
|
_lastAudioFrame = frameCounter;
|
|
} else {
|
|
AudioConfig audioCfg = _emu->GetSettings()->GetAudioConfig();
|
|
double silenceLength = (double)(frameCounter - _lastAudioFrame) / fps;
|
|
if(audioCfg.AudioPlayerAutoDetectSilence && silenceLength >= audioCfg.AudioPlayerSilenceDelay) {
|
|
//Silence detected, move to next track
|
|
MoveToNextTrack();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AudioPlayerHud::MoveToNextTrack()
|
|
{
|
|
if(!_changeTrackPending) {
|
|
_changeTrackPending = true;
|
|
AudioPlayerActionParams params = {};
|
|
|
|
AudioPlayerConfig cfg = _emu->GetSettings()->GetAudioPlayerConfig();
|
|
AudioTrackInfo track = _emu->GetAudioTrackInfo();
|
|
if(!cfg.Repeat) {
|
|
if(cfg.Shuffle) {
|
|
std::random_device rd;
|
|
std::mt19937 mt(rd());
|
|
std::uniform_int_distribution<> dist(0, track.TrackCount - 1);
|
|
params.Action = AudioPlayerAction::SelectTrack;
|
|
params.TrackNumber = dist(mt);
|
|
} else {
|
|
params.Action = AudioPlayerAction::NextTrack;
|
|
}
|
|
} else {
|
|
params.Action = AudioPlayerAction::SelectTrack;
|
|
params.TrackNumber = track.TrackNumber - 1;
|
|
}
|
|
_emu->ProcessAudioPlayerAction(params);
|
|
}
|
|
}
|
|
|
|
uint32_t AudioPlayerHud::GetVolume()
|
|
{
|
|
AudioTrackInfo info = _emu->GetAudioTrackInfo();
|
|
|
|
if(info.Length > 0) {
|
|
if(info.Position >= info.Length) {
|
|
//Switch to next track
|
|
MoveToNextTrack();
|
|
return 0;
|
|
} else if(info.Position >= info.Length - info.FadeLength) {
|
|
double fadeStart = info.Length - info.FadeLength;
|
|
double ratio = 1.0 - ((info.Position - fadeStart) / info.FadeLength);
|
|
return (uint32_t)(ratio * _emu->GetSettings()->GetAudioPlayerConfig().Volume);
|
|
}
|
|
}
|
|
return _emu->GetSettings()->GetAudioPlayerConfig().Volume;
|
|
}
|
|
|
|
void AudioPlayerHud::ProcessSamples(int16_t* samples, size_t sampleCount, uint32_t sampleRate)
|
|
{
|
|
_sampleRate = sampleRate;
|
|
for(int i = 0; i < sampleCount; i++) {
|
|
_samples.push_back((samples[i * 2] + samples[i * 2 + 1]) / 2);
|
|
if(_samples.size() > N) {
|
|
_samples.pop_front();
|
|
}
|
|
}
|
|
|
|
if(_samples.size() >= N) {
|
|
for(int i = 0; i < N; i++) {
|
|
_input[i] = _samples[i] * _hannWindow[i];
|
|
}
|
|
|
|
_fft.transform_real(_input, _out);
|
|
|
|
_amplitudes.clear();
|
|
for(int i = 0; i < N / 2; i++) {
|
|
std::complex<double> c = _out[i];
|
|
double amp = sqrt(c.real() * c.real() + c.imag() * c.imag());
|
|
_amplitudes.push_back(amp / N);
|
|
}
|
|
}
|
|
}
|