mirror of https://github.com/mgba-emu/mgba.git
GBA Audio: Ability to mute individual audio channels
This commit is contained in:
parent
8533f01be5
commit
73e4516257
1
CHANGES
1
CHANGES
|
@ -1,6 +1,7 @@
|
||||||
0.3.0: (Future)
|
0.3.0: (Future)
|
||||||
Features:
|
Features:
|
||||||
- Ability to hide individual background layers, or OBJs
|
- Ability to hide individual background layers, or OBJs
|
||||||
|
- Ability to mute individual audio channels
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- GBA: Fix timers not updating timing when writing to only the reload register
|
- GBA: Fix timers not updating timing when writing to only the reload register
|
||||||
- All: Fix sanitize-deb script not cleaning up after itself
|
- All: Fix sanitize-deb script not cleaning up after itself
|
||||||
|
|
|
@ -41,6 +41,13 @@ void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
|
||||||
#endif
|
#endif
|
||||||
CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
|
CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
|
||||||
CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
|
CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
|
||||||
|
|
||||||
|
audio->forceDisableCh[0] = false;
|
||||||
|
audio->forceDisableCh[1] = false;
|
||||||
|
audio->forceDisableCh[2] = false;
|
||||||
|
audio->forceDisableCh[3] = false;
|
||||||
|
audio->forceDisableChA = false;
|
||||||
|
audio->forceDisableChB = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAAudioReset(struct GBAAudio* audio) {
|
void GBAAudioReset(struct GBAAudio* audio) {
|
||||||
|
@ -750,55 +757,67 @@ static void _sample(struct GBAAudio* audio) {
|
||||||
int16_t sampleRight = 0;
|
int16_t sampleRight = 0;
|
||||||
int psgShift = 5 - audio->volume;
|
int psgShift = 5 - audio->volume;
|
||||||
|
|
||||||
if (audio->ch1Left) {
|
if (audio->playingCh1 && !audio->forceDisableCh[0]) {
|
||||||
sampleLeft += audio->ch1.sample;
|
if (audio->ch1Left) {
|
||||||
|
sampleLeft += audio->ch1.sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio->ch1Right) {
|
||||||
|
sampleRight += audio->ch1.sample;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio->ch1Right) {
|
if (audio->playingCh2 && !audio->forceDisableCh[1]) {
|
||||||
sampleRight += audio->ch1.sample;
|
if (audio->ch2Left) {
|
||||||
|
sampleLeft += audio->ch2.sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio->ch2Right) {
|
||||||
|
sampleRight += audio->ch2.sample;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio->ch2Left) {
|
if (audio->playingCh3 && !audio->forceDisableCh[2]) {
|
||||||
sampleLeft += audio->ch2.sample;
|
if (audio->ch3Left) {
|
||||||
|
sampleLeft += audio->ch3.sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio->ch3Right) {
|
||||||
|
sampleRight += audio->ch3.sample;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio->ch2Right) {
|
if (audio->playingCh4 && !audio->forceDisableCh[3]) {
|
||||||
sampleRight += audio->ch2.sample;
|
if (audio->ch4Left) {
|
||||||
}
|
sampleLeft += audio->ch4.sample;
|
||||||
|
}
|
||||||
|
|
||||||
if (audio->ch3Left) {
|
if (audio->ch4Right) {
|
||||||
sampleLeft += audio->ch3.sample;
|
sampleRight += audio->ch4.sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio->ch3Right) {
|
|
||||||
sampleRight += audio->ch3.sample;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audio->ch4Left) {
|
|
||||||
sampleLeft += audio->ch4.sample;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audio->ch4Right) {
|
|
||||||
sampleRight += audio->ch4.sample;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleLeft = (sampleLeft * (1 + audio->volumeLeft)) >> psgShift;
|
sampleLeft = (sampleLeft * (1 + audio->volumeLeft)) >> psgShift;
|
||||||
sampleRight = (sampleRight * (1 + audio->volumeRight)) >> psgShift;
|
sampleRight = (sampleRight * (1 + audio->volumeRight)) >> psgShift;
|
||||||
|
|
||||||
if (audio->chALeft) {
|
if (!audio->forceDisableChA) {
|
||||||
sampleLeft += (audio->chA.sample << 2) >> !audio->volumeChA;
|
if (audio->chALeft) {
|
||||||
|
sampleLeft += (audio->chA.sample << 2) >> !audio->volumeChA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio->chARight) {
|
||||||
|
sampleRight += (audio->chA.sample << 2) >> !audio->volumeChA;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio->chARight) {
|
if (!audio->forceDisableChB) {
|
||||||
sampleRight += (audio->chA.sample << 2) >> !audio->volumeChA;
|
if (audio->chBLeft) {
|
||||||
}
|
sampleLeft += (audio->chB.sample << 2) >> !audio->volumeChB;
|
||||||
|
}
|
||||||
|
|
||||||
if (audio->chBLeft) {
|
if (audio->chBRight) {
|
||||||
sampleLeft += (audio->chB.sample << 2) >> !audio->volumeChB;
|
sampleRight += (audio->chB.sample << 2) >> !audio->volumeChB;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio->chBRight) {
|
|
||||||
sampleRight += (audio->chB.sample << 2) >> !audio->volumeChB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleLeft = _applyBias(audio, sampleLeft);
|
sampleLeft = _applyBias(audio, sampleLeft);
|
||||||
|
|
|
@ -236,6 +236,10 @@ struct GBAAudio {
|
||||||
int32_t nextSample;
|
int32_t nextSample;
|
||||||
|
|
||||||
int32_t sampleInterval;
|
int32_t sampleInterval;
|
||||||
|
|
||||||
|
bool forceDisableCh[4];
|
||||||
|
bool forceDisableChA;
|
||||||
|
bool forceDisableChB;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBAStereoSample {
|
struct GBAStereoSample {
|
||||||
|
|
|
@ -818,6 +818,31 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
m_gameActions.append(enableObj);
|
m_gameActions.append(enableObj);
|
||||||
addControlledAction(videoLayers, enableObj, "enableOBJ");
|
addControlledAction(videoLayers, enableObj, "enableOBJ");
|
||||||
|
|
||||||
|
QMenu* audioChannels = avMenu->addMenu(tr("Audio channels"));
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
QAction* enableCh = new QAction(tr("Channel %0").arg(i + 1), audioChannels);
|
||||||
|
enableCh->setCheckable(true);
|
||||||
|
enableCh->setChecked(true);
|
||||||
|
connect(enableCh, &QAction::triggered, [this, i](bool enable) { m_controller->thread()->gba->audio.forceDisableCh[i] = !enable; });
|
||||||
|
m_gameActions.append(enableCh);
|
||||||
|
addControlledAction(audioChannels, enableCh, QString("enableCh%0").arg(i + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction* enableChA = new QAction(tr("Channel A"), audioChannels);
|
||||||
|
enableChA->setCheckable(true);
|
||||||
|
enableChA->setChecked(true);
|
||||||
|
connect(enableChA, &QAction::triggered, [this, i](bool enable) { m_controller->thread()->gba->audio.forceDisableChA = !enable; });
|
||||||
|
m_gameActions.append(enableChA);
|
||||||
|
addControlledAction(audioChannels, enableChA, QString("enableChA"));
|
||||||
|
|
||||||
|
QAction* enableChB = new QAction(tr("Channel B"), audioChannels);
|
||||||
|
enableChB->setCheckable(true);
|
||||||
|
enableChB->setChecked(true);
|
||||||
|
connect(enableChB, &QAction::triggered, [this, i](bool enable) { m_controller->thread()->gba->audio.forceDisableChB = !enable; });
|
||||||
|
m_gameActions.append(enableChB);
|
||||||
|
addControlledAction(audioChannels, enableChB, QString("enableChB"));
|
||||||
|
|
||||||
QMenu* toolsMenu = menubar->addMenu(tr("&Tools"));
|
QMenu* toolsMenu = menubar->addMenu(tr("&Tools"));
|
||||||
m_shortcutController->addMenu(toolsMenu);
|
m_shortcutController->addMenu(toolsMenu);
|
||||||
QAction* viewLogs = new QAction(tr("View &logs..."), toolsMenu);
|
QAction* viewLogs = new QAction(tr("View &logs..."), toolsMenu);
|
||||||
|
|
Loading…
Reference in New Issue