mirror of https://github.com/mgba-emu/mgba.git
GB Audio: Redo channels 1 and 2
This commit is contained in:
parent
5e6d063aa1
commit
68f628a211
|
@ -87,7 +87,6 @@ struct GBAudioSquareControl {
|
|||
int frequency;
|
||||
int length;
|
||||
bool stop;
|
||||
int hi;
|
||||
};
|
||||
|
||||
struct GBAudioSweep {
|
||||
|
@ -104,6 +103,8 @@ struct GBAudioSquareChannel {
|
|||
struct GBAudioSweep sweep;
|
||||
struct GBAudioEnvelope envelope;
|
||||
struct GBAudioSquareControl control;
|
||||
int32_t lastUpdate;
|
||||
uint8_t index;
|
||||
int8_t sample;
|
||||
};
|
||||
|
||||
|
@ -194,8 +195,6 @@ struct GBAudio {
|
|||
enum GBAudioStyle style;
|
||||
|
||||
struct mTimingEvent frameEvent;
|
||||
struct mTimingEvent ch1Event;
|
||||
struct mTimingEvent ch2Event;
|
||||
struct mTimingEvent ch3Event;
|
||||
struct mTimingEvent ch3Fade;
|
||||
struct mTimingEvent ch4Event;
|
||||
|
@ -239,6 +238,7 @@ void GBAudioWriteNR50(struct GBAudio* audio, uint8_t);
|
|||
void GBAudioWriteNR51(struct GBAudio* audio, uint8_t);
|
||||
void GBAudioWriteNR52(struct GBAudio* audio, uint8_t);
|
||||
|
||||
void GBAudioRun(struct GBAudio* audio, int32_t timestamp);
|
||||
void GBAudioUpdateFrame(struct GBAudio* audio);
|
||||
void GBAudioUpdateChannel4(struct GBAudio* audio);
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ extern MGBA_EXPORT const uint32_t GBSavestateVersion;
|
|||
mLOG_DECLARE_CATEGORY(GB_STATE);
|
||||
|
||||
/* Savestate format:
|
||||
* 0x00000 - 0x00003: Version Magic (0x01000002)
|
||||
* 0x00000 - 0x00003: Version Magic (0x00400003)
|
||||
* 0x00004 - 0x00007: ROM CRC32
|
||||
* 0x00008: Game Boy model
|
||||
* 0x00009 - 0x0000B: Reserved (leave zero)
|
||||
|
@ -56,20 +56,23 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
|
|||
* | bits 0 - 6: Remaining length
|
||||
* | bits 7 - 9: Next step
|
||||
* | bits 10 - 20: Shadow frequency register
|
||||
* | bits 21 - 31: Reserved
|
||||
* | bits 21 - 23: Duty index
|
||||
* | bits 24 - 31: Reserved
|
||||
* | 0x0004C - 0x0004F: Next frame
|
||||
* | 0x00050 - 0x00053: Next channel 3 fade
|
||||
* | 0x00054 - 0x00057: Sweep state
|
||||
* | bits 0 - 2: Timesteps
|
||||
* | bits 3 - 31: Reserved
|
||||
* | 0x00058 - 0x0005B: Next event
|
||||
* | 0x00058 - 0x0005B: Last update
|
||||
* 0x0005C - 0x0006B: Audio channel 2 state
|
||||
* | 0x0005C - 0x0005F: Envelepe timing
|
||||
* | bits 0 - 2: Remaining length
|
||||
* | bits 3 - 5: Next step
|
||||
* | bits 6 - 31: Reserved
|
||||
* | bits 6 - 20: Reserved
|
||||
* | bits 21 - 23: Duty index
|
||||
* | bits 24 - 31: Reserved
|
||||
* | 0x00060 - 0x00067: Reserved
|
||||
* | 0x00068 - 0x0006B: Next event
|
||||
* | 0x00068 - 0x0006B: Last update
|
||||
* 0x0006C - 0x00093: Audio channel 3 state
|
||||
* | 0x0006C - 0x0008B: Wave banks
|
||||
* | 0x0008C - 0x0008D: Remaining length
|
||||
|
@ -208,7 +211,7 @@ DECL_BITFIELD(GBSerializedAudioEnvelope, uint32_t);
|
|||
DECL_BITS(GBSerializedAudioEnvelope, Length, 0, 7);
|
||||
DECL_BITS(GBSerializedAudioEnvelope, NextStep, 7, 3);
|
||||
DECL_BITS(GBSerializedAudioEnvelope, Frequency, 10, 11);
|
||||
|
||||
DECL_BITS(GBSerializedAudioEnvelope, DutyIndex, 21, 3);
|
||||
|
||||
DECL_BITFIELD(GBSerializedAudioSweep, uint32_t);
|
||||
DECL_BITS(GBSerializedAudioSweep, Time, 0, 3);
|
||||
|
@ -219,12 +222,12 @@ struct GBSerializedPSGState {
|
|||
int32_t nextFrame;
|
||||
int32_t nextCh3Fade;
|
||||
GBSerializedAudioSweep sweep;
|
||||
uint32_t nextEvent;
|
||||
uint32_t lastUpdate;
|
||||
} ch1;
|
||||
struct {
|
||||
GBSerializedAudioEnvelope envelope;
|
||||
int32_t reserved[2];
|
||||
int32_t nextEvent;
|
||||
uint32_t lastUpdate;
|
||||
} ch2;
|
||||
struct {
|
||||
uint32_t wavebanks[8];
|
||||
|
|
|
@ -20,7 +20,7 @@ extern MGBA_EXPORT const uint32_t GBASavestateVersion;
|
|||
mLOG_DECLARE_CATEGORY(GBA_STATE);
|
||||
|
||||
/* Savestate format:
|
||||
* 0x00000 - 0x00003: Version Magic (0x01000004)
|
||||
* 0x00000 - 0x00003: Version Magic (0x01000005)
|
||||
* 0x00004 - 0x00007: BIOS checksum (e.g. 0xBAAE187F for official BIOS)
|
||||
* 0x00008 - 0x0000B: ROM CRC32
|
||||
* 0x0000C - 0x0000F: Master cycles
|
||||
|
@ -39,25 +39,28 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
|
|||
* | bits 0 - 6: Remaining length
|
||||
* | bits 7 - 9: Next step
|
||||
* | bits 10 - 20: Shadow frequency register
|
||||
* | bits 21 - 31: Reserved
|
||||
* | bits 21 - 23: Duty index
|
||||
* | bits 24 - 31: Reserved
|
||||
* | 0x00134 - 0x00137: Next frame
|
||||
* | 0x00138 - 0x0013B: Next channel 3 fade
|
||||
* | 0x0013C - 0x0013F: Sweep state
|
||||
* | bits 0 - 2: Timesteps
|
||||
* | bits 3 - 7: Reserved
|
||||
* | 0x00140 - 0x00143: Next event
|
||||
* | 0x00140 - 0x00143: Last update
|
||||
* 0x00144 - 0x00153: Audio channel 2 state
|
||||
* | 0x00144 - 0x00147: Envelepe timing
|
||||
* | bits 0 - 2: Remaining length
|
||||
* | bits 3 - 5: Next step
|
||||
* | bits 6 - 31: Reserved
|
||||
* | bits 6 - 20: Reserved
|
||||
* | bits 21 - 23: Duty index
|
||||
* | bits 24 - 31: Reserved
|
||||
* | 0x00148 - 0x0014F: Reserved
|
||||
* | 0x00150 - 0x00153: Next event
|
||||
* | 0x00150 - 0x00153: Last update
|
||||
* 0x00154 - 0x0017B: Audio channel 3 state
|
||||
* | 0x00154 - 0x00173: Wave banks
|
||||
* | 0x00174 - 0x00175: Remaining length
|
||||
* | 0x00176 - 0x00177: Reserved
|
||||
* | 0x00178 - 0x0017B: Next event
|
||||
* | 0x00178 - 0x0017B: Last update
|
||||
* 0x0017C - 0x0018B: Audio channel 4 state
|
||||
* | 0x0017C - 0x0017F: Linear feedback shift register state
|
||||
* | 0x00180 - 0x00183: Envelepe timing
|
||||
|
|
145
src/gb/audio.c
145
src/gb/audio.c
|
@ -35,19 +35,21 @@ static void _updateEnvelopeDead(struct GBAudioEnvelope* envelope);
|
|||
static bool _updateSweep(struct GBAudioSquareChannel* sweep, bool initial);
|
||||
|
||||
static void _updateSquareSample(struct GBAudioSquareChannel* ch);
|
||||
static int32_t _updateSquareChannel(struct GBAudioSquareChannel* ch);
|
||||
|
||||
static int32_t _cyclesToInvert(struct GBAudioSquareChannel* ch);
|
||||
|
||||
static int16_t _coalesceNoiseChannel(struct GBAudioNoiseChannel* ch);
|
||||
|
||||
static void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
static void _updateChannel1(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
static void _updateChannel2(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
static void _updateChannel3(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
static void _fadeChannel3(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
|
||||
static const int _squareChannelDuty[4][8] = {
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 1, 0, 0, 0, 0, 1, 1, 1 },
|
||||
{ 0, 1, 1, 1, 1, 1, 1, 0 },
|
||||
};
|
||||
|
||||
void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAudioStyle style) {
|
||||
audio->samples = samples;
|
||||
audio->left = blip_new(BLIP_BUFFER_SIZE);
|
||||
|
@ -73,14 +75,6 @@ void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAu
|
|||
audio->frameEvent.name = "GB Audio Frame Sequencer";
|
||||
audio->frameEvent.callback = _updateFrame;
|
||||
audio->frameEvent.priority = 0x10;
|
||||
audio->ch1Event.context = audio;
|
||||
audio->ch1Event.name = "GB Audio Channel 1";
|
||||
audio->ch1Event.callback = _updateChannel1;
|
||||
audio->ch1Event.priority = 0x11;
|
||||
audio->ch2Event.context = audio;
|
||||
audio->ch2Event.name = "GB Audio Channel 2";
|
||||
audio->ch2Event.callback = _updateChannel2;
|
||||
audio->ch2Event.priority = 0x12;
|
||||
audio->ch3Event.context = audio;
|
||||
audio->ch3Event.name = "GB Audio Channel 3";
|
||||
audio->ch3Event.callback = _updateChannel3;
|
||||
|
@ -106,8 +100,6 @@ void GBAudioDeinit(struct GBAudio* audio) {
|
|||
|
||||
void GBAudioReset(struct GBAudio* audio) {
|
||||
mTimingDeschedule(audio->timing, &audio->frameEvent);
|
||||
mTimingDeschedule(audio->timing, &audio->ch1Event);
|
||||
mTimingDeschedule(audio->timing, &audio->ch2Event);
|
||||
mTimingDeschedule(audio->timing, &audio->ch3Event);
|
||||
mTimingDeschedule(audio->timing, &audio->ch3Fade);
|
||||
mTimingDeschedule(audio->timing, &audio->ch4Event);
|
||||
|
@ -168,32 +160,35 @@ void GBAudioResizeBuffer(struct GBAudio* audio, size_t samples) {
|
|||
}
|
||||
|
||||
void GBAudioWriteNR10(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
if (!_writeSweep(&audio->ch1.sweep, value)) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch1Event);
|
||||
audio->playingCh1 = false;
|
||||
*audio->nr52 &= ~0x0001;
|
||||
}
|
||||
}
|
||||
|
||||
void GBAudioWriteNR11(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
_writeDuty(&audio->ch1.envelope, value);
|
||||
audio->ch1.control.length = 64 - audio->ch1.envelope.length;
|
||||
}
|
||||
|
||||
void GBAudioWriteNR12(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
if (!_writeEnvelope(&audio->ch1.envelope, value, audio->style)) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch1Event);
|
||||
audio->playingCh1 = false;
|
||||
*audio->nr52 &= ~0x0001;
|
||||
}
|
||||
}
|
||||
|
||||
void GBAudioWriteNR13(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
audio->ch1.control.frequency &= 0x700;
|
||||
audio->ch1.control.frequency |= GBAudioRegisterControlGetFrequency(value);
|
||||
}
|
||||
|
||||
void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
audio->ch1.control.frequency &= 0xFF;
|
||||
audio->ch1.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8);
|
||||
bool wasStop = audio->ch1.control.stop;
|
||||
|
@ -201,12 +196,10 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) {
|
|||
if (!wasStop && audio->ch1.control.stop && audio->ch1.control.length && !(audio->frame & 1)) {
|
||||
--audio->ch1.control.length;
|
||||
if (audio->ch1.control.length == 0) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch1Event);
|
||||
audio->playingCh1 = false;
|
||||
}
|
||||
}
|
||||
if (GBAudioRegisterControlIsRestart(value << 8)) {
|
||||
bool wasDead = !audio->playingCh1;
|
||||
audio->playingCh1 = _resetEnvelope(&audio->ch1.envelope);
|
||||
audio->ch1.sweep.realFrequency = audio->ch1.control.frequency;
|
||||
_resetSweep(&audio->ch1.sweep);
|
||||
|
@ -220,35 +213,33 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) {
|
|||
}
|
||||
}
|
||||
_updateSquareSample(&audio->ch1);
|
||||
if (wasDead && audio->playingCh1) {
|
||||
mTimingSchedule(audio->timing, &audio->ch1Event, _cyclesToInvert(&audio->ch1));
|
||||
} else if (!audio->playingCh1) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch1Event);
|
||||
}
|
||||
}
|
||||
*audio->nr52 &= ~0x0001;
|
||||
*audio->nr52 |= audio->playingCh1;
|
||||
}
|
||||
|
||||
void GBAudioWriteNR21(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
_writeDuty(&audio->ch2.envelope, value);
|
||||
audio->ch2.control.length = 64 - audio->ch2.envelope.length;
|
||||
}
|
||||
|
||||
void GBAudioWriteNR22(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
if (!_writeEnvelope(&audio->ch2.envelope, value, audio->style)) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch2Event);
|
||||
audio->playingCh2 = false;
|
||||
*audio->nr52 &= ~0x0002;
|
||||
}
|
||||
}
|
||||
|
||||
void GBAudioWriteNR23(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
audio->ch2.control.frequency &= 0x700;
|
||||
audio->ch2.control.frequency |= GBAudioRegisterControlGetFrequency(value);
|
||||
}
|
||||
|
||||
void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
audio->ch2.control.frequency &= 0xFF;
|
||||
audio->ch2.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8);
|
||||
bool wasStop = audio->ch2.control.stop;
|
||||
|
@ -256,12 +247,10 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) {
|
|||
if (!wasStop && audio->ch2.control.stop && audio->ch2.control.length && !(audio->frame & 1)) {
|
||||
--audio->ch2.control.length;
|
||||
if (audio->ch2.control.length == 0) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch2Event);
|
||||
audio->playingCh2 = false;
|
||||
}
|
||||
}
|
||||
if (GBAudioRegisterControlIsRestart(value << 8)) {
|
||||
bool wasDead = !audio->playingCh2;
|
||||
audio->playingCh2 = _resetEnvelope(&audio->ch2.envelope);
|
||||
|
||||
if (!audio->ch2.control.length) {
|
||||
|
@ -271,11 +260,6 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) {
|
|||
}
|
||||
}
|
||||
_updateSquareSample(&audio->ch2);
|
||||
if (wasDead && audio->playingCh2) {
|
||||
mTimingSchedule(audio->timing, &audio->ch2Event, _cyclesToInvert(&audio->ch2));
|
||||
} else if (!audio->playingCh2) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch2Event);
|
||||
}
|
||||
}
|
||||
*audio->nr52 &= ~0x0002;
|
||||
*audio->nr52 |= audio->playingCh2 << 1;
|
||||
|
@ -496,6 +480,26 @@ void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
|||
}
|
||||
}
|
||||
|
||||
void GBAudioRun(struct GBAudio* audio, int32_t timestamp) {
|
||||
if (!audio->enable) {
|
||||
return;
|
||||
}
|
||||
if (audio->playingCh1) {
|
||||
int period = 4 * (2048 - audio->ch1.control.frequency) * audio->timingFactor;
|
||||
int32_t diff = (timestamp - audio->ch1.lastUpdate) / period;
|
||||
audio->ch1.index = (audio->ch1.index + diff) & 7;
|
||||
audio->ch1.lastUpdate += diff * period;
|
||||
_updateSquareSample(&audio->ch1);
|
||||
}
|
||||
if (audio->playingCh2) {
|
||||
int period = 4 * (2048 - audio->ch2.control.frequency) * audio->timingFactor;
|
||||
int32_t diff = (timestamp - audio->ch2.lastUpdate) / period;
|
||||
audio->ch2.index = (audio->ch2.index + diff) & 7;
|
||||
audio->ch2.lastUpdate += diff * period;
|
||||
_updateSquareSample(&audio->ch2);
|
||||
}
|
||||
}
|
||||
|
||||
void GBAudioUpdateFrame(struct GBAudio* audio) {
|
||||
if (!audio->enable) {
|
||||
return;
|
||||
|
@ -504,6 +508,8 @@ void GBAudioUpdateFrame(struct GBAudio* audio) {
|
|||
audio->skipFrame = false;
|
||||
return;
|
||||
}
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
|
||||
int frame = (audio->frame + 1) & 7;
|
||||
audio->frame = frame;
|
||||
|
||||
|
@ -516,9 +522,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) {
|
|||
audio->playingCh1 = _updateSweep(&audio->ch1, false);
|
||||
*audio->nr52 &= ~0x0001;
|
||||
*audio->nr52 |= audio->playingCh1;
|
||||
if (!audio->playingCh1) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch1Event);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fall through
|
||||
|
@ -527,7 +530,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) {
|
|||
if (audio->ch1.control.length && audio->ch1.control.stop) {
|
||||
--audio->ch1.control.length;
|
||||
if (audio->ch1.control.length == 0) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch1Event);
|
||||
audio->playingCh1 = 0;
|
||||
*audio->nr52 &= ~0x0001;
|
||||
}
|
||||
|
@ -536,7 +538,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) {
|
|||
if (audio->ch2.control.length && audio->ch2.control.stop) {
|
||||
--audio->ch2.control.length;
|
||||
if (audio->ch2.control.length == 0) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch2Event);
|
||||
audio->playingCh2 = 0;
|
||||
*audio->nr52 &= ~0x0002;
|
||||
}
|
||||
|
@ -565,9 +566,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) {
|
|||
--audio->ch1.envelope.nextStep;
|
||||
if (audio->ch1.envelope.nextStep == 0) {
|
||||
_updateEnvelope(&audio->ch1.envelope);
|
||||
if (audio->ch1.envelope.dead == 2) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch1Event);
|
||||
}
|
||||
_updateSquareSample(&audio->ch1);
|
||||
}
|
||||
}
|
||||
|
@ -576,9 +574,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) {
|
|||
--audio->ch2.envelope.nextStep;
|
||||
if (audio->ch2.envelope.nextStep == 0) {
|
||||
_updateEnvelope(&audio->ch2.envelope);
|
||||
if (audio->ch2.envelope.dead == 2) {
|
||||
mTimingDeschedule(audio->timing, &audio->ch2Event);
|
||||
}
|
||||
_updateSquareSample(&audio->ch2);
|
||||
}
|
||||
}
|
||||
|
@ -626,6 +621,7 @@ void GBAudioUpdateChannel4(struct GBAudio* audio) {
|
|||
}
|
||||
|
||||
void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) {
|
||||
GBAudioRun(audio, mTimingCurrentTime(audio->timing));
|
||||
int dcOffset = audio->style == GB_AUDIO_GBA ? 0 : -0x8;
|
||||
int sampleLeft = dcOffset;
|
||||
int sampleRight = dcOffset;
|
||||
|
@ -775,30 +771,7 @@ bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value, enum GBAudi
|
|||
}
|
||||
|
||||
static void _updateSquareSample(struct GBAudioSquareChannel* ch) {
|
||||
ch->sample = ch->control.hi * ch->envelope.currentVolume;
|
||||
}
|
||||
|
||||
static int32_t _updateSquareChannel(struct GBAudioSquareChannel* ch) {
|
||||
ch->control.hi = !ch->control.hi;
|
||||
_updateSquareSample(ch);
|
||||
return _cyclesToInvert(ch);
|
||||
}
|
||||
|
||||
static int32_t _cyclesToInvert(struct GBAudioSquareChannel* ch) {
|
||||
int period = 4 * (2048 - ch->control.frequency);
|
||||
switch (ch->envelope.duty) {
|
||||
case 0:
|
||||
return ch->control.hi ? period : period * 7;
|
||||
case 1:
|
||||
return ch->control.hi ? period * 2 : period * 6;
|
||||
case 2:
|
||||
return period * 4;
|
||||
case 3:
|
||||
return ch->control.hi ? period * 6 : period * 2;
|
||||
default:
|
||||
// This should never be hit
|
||||
return period * 4;
|
||||
}
|
||||
ch->sample = _squareChannelDuty[ch->envelope.duty][ch->index] * ch->envelope.currentVolume;
|
||||
}
|
||||
|
||||
static int16_t _coalesceNoiseChannel(struct GBAudioNoiseChannel* ch) {
|
||||
|
@ -870,20 +843,6 @@ static bool _updateSweep(struct GBAudioSquareChannel* ch, bool initial) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void _updateChannel1(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
||||
struct GBAudio* audio = user;
|
||||
struct GBAudioSquareChannel* ch = &audio->ch1;
|
||||
int cycles = _updateSquareChannel(ch);
|
||||
mTimingSchedule(timing, &audio->ch1Event, audio->timingFactor * cycles - cyclesLate);
|
||||
}
|
||||
|
||||
static void _updateChannel2(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
||||
struct GBAudio* audio = user;
|
||||
struct GBAudioSquareChannel* ch = &audio->ch2;
|
||||
int cycles = _updateSquareChannel(ch);
|
||||
mTimingSchedule(timing, &audio->ch2Event, audio->timingFactor * cycles - cyclesLate);
|
||||
}
|
||||
|
||||
static void _updateChannel3(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
||||
struct GBAudio* audio = user;
|
||||
struct GBAudioWaveChannel* ch = &audio->ch3;
|
||||
|
@ -971,24 +930,24 @@ void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGStat
|
|||
|
||||
flags = GBSerializedAudioFlagsSetCh1Volume(flags, audio->ch1.envelope.currentVolume);
|
||||
flags = GBSerializedAudioFlagsSetCh1Dead(flags, audio->ch1.envelope.dead);
|
||||
flags = GBSerializedAudioFlagsSetCh1Hi(flags, audio->ch1.control.hi);
|
||||
flags = GBSerializedAudioFlagsSetCh1SweepEnabled(flags, audio->ch1.sweep.enable);
|
||||
flags = GBSerializedAudioFlagsSetCh1SweepOccurred(flags, audio->ch1.sweep.occurred);
|
||||
ch1Flags = GBSerializedAudioEnvelopeSetLength(ch1Flags, audio->ch1.control.length);
|
||||
ch1Flags = GBSerializedAudioEnvelopeSetNextStep(ch1Flags, audio->ch1.envelope.nextStep);
|
||||
ch1Flags = GBSerializedAudioEnvelopeSetFrequency(ch1Flags, audio->ch1.sweep.realFrequency);
|
||||
ch1Flags = GBSerializedAudioEnvelopeSetDutyIndex(ch1Flags, audio->ch1.index);
|
||||
sweep = GBSerializedAudioSweepSetTime(sweep, audio->ch1.sweep.time & 7);
|
||||
STORE_32LE(ch1Flags, 0, &state->ch1.envelope);
|
||||
STORE_32LE(sweep, 0, &state->ch1.sweep);
|
||||
STORE_32LE(audio->ch1Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch1.nextEvent);
|
||||
STORE_32LE(audio->ch1.lastUpdate - mTimingCurrentTime(audio->timing), 0, &state->ch1.lastUpdate);
|
||||
|
||||
flags = GBSerializedAudioFlagsSetCh2Volume(flags, audio->ch2.envelope.currentVolume);
|
||||
flags = GBSerializedAudioFlagsSetCh2Dead(flags, audio->ch2.envelope.dead);
|
||||
flags = GBSerializedAudioFlagsSetCh2Hi(flags, audio->ch2.control.hi);
|
||||
ch2Flags = GBSerializedAudioEnvelopeSetLength(ch2Flags, audio->ch2.control.length);
|
||||
ch2Flags = GBSerializedAudioEnvelopeSetNextStep(ch2Flags, audio->ch2.envelope.nextStep);
|
||||
ch2Flags = GBSerializedAudioEnvelopeSetDutyIndex(ch2Flags, audio->ch2.index);
|
||||
STORE_32LE(ch2Flags, 0, &state->ch2.envelope);
|
||||
STORE_32LE(audio->ch2Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch2.nextEvent);
|
||||
STORE_32LE(audio->ch2.lastUpdate - mTimingCurrentTime(audio->timing), 0, &state->ch2.lastUpdate);
|
||||
|
||||
flags = GBSerializedAudioFlagsSetCh3Readable(flags, audio->ch3.readable);
|
||||
memcpy(state->ch3.wavebanks, audio->ch3.wavedata32, sizeof(state->ch3.wavebanks));
|
||||
|
@ -1039,7 +998,6 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt
|
|||
LOAD_32LE(sweep, 0, &state->ch1.sweep);
|
||||
audio->ch1.envelope.currentVolume = GBSerializedAudioFlagsGetCh1Volume(flags);
|
||||
audio->ch1.envelope.dead = GBSerializedAudioFlagsGetCh1Dead(flags);
|
||||
audio->ch1.control.hi = GBSerializedAudioFlagsGetCh1Hi(flags);
|
||||
audio->ch1.sweep.enable = GBSerializedAudioFlagsGetCh1SweepEnabled(flags);
|
||||
audio->ch1.sweep.occurred = GBSerializedAudioFlagsGetCh1SweepOccurred(flags);
|
||||
audio->ch1.sweep.time = GBSerializedAudioSweepGetTime(sweep);
|
||||
|
@ -1049,21 +1007,18 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt
|
|||
audio->ch1.control.length = GBSerializedAudioEnvelopeGetLength(ch1Flags);
|
||||
audio->ch1.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch1Flags);
|
||||
audio->ch1.sweep.realFrequency = GBSerializedAudioEnvelopeGetFrequency(ch1Flags);
|
||||
LOAD_32LE(when, 0, &state->ch1.nextEvent);
|
||||
if (audio->ch1.envelope.dead < 2 && audio->playingCh1) {
|
||||
mTimingSchedule(audio->timing, &audio->ch1Event, when);
|
||||
}
|
||||
audio->ch1.index = GBSerializedAudioEnvelopeGetDutyIndex(ch1Flags);
|
||||
LOAD_32LE(audio->ch1.lastUpdate, 0, &state->ch1.lastUpdate);
|
||||
audio->ch1.lastUpdate += mTimingCurrentTime(audio->timing);
|
||||
|
||||
LOAD_32LE(ch2Flags, 0, &state->ch2.envelope);
|
||||
audio->ch2.envelope.currentVolume = GBSerializedAudioFlagsGetCh2Volume(flags);
|
||||
audio->ch2.envelope.dead = GBSerializedAudioFlagsGetCh2Dead(flags);
|
||||
audio->ch2.control.hi = GBSerializedAudioFlagsGetCh2Hi(flags);
|
||||
audio->ch2.control.length = GBSerializedAudioEnvelopeGetLength(ch2Flags);
|
||||
audio->ch2.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch2Flags);
|
||||
LOAD_32LE(when, 0, &state->ch2.nextEvent);
|
||||
if (audio->ch2.envelope.dead < 2 && audio->playingCh2) {
|
||||
mTimingSchedule(audio->timing, &audio->ch2Event, when);
|
||||
}
|
||||
audio->ch2.index = GBSerializedAudioEnvelopeGetDutyIndex(ch2Flags);
|
||||
LOAD_32LE(audio->ch2.lastUpdate, 0, &state->ch2.lastUpdate);
|
||||
audio->ch2.lastUpdate += mTimingCurrentTime(audio->timing);
|
||||
|
||||
audio->ch3.readable = GBSerializedAudioFlagsGetCh3Readable(flags);
|
||||
// TODO: Big endian?
|
||||
|
|
|
@ -620,6 +620,7 @@ uint8_t GBIORead(struct GB* gb, unsigned address) {
|
|||
if (gb->model < GB_MODEL_CGB) {
|
||||
mLOG(GB_IO, GAME_ERROR, "Reading from CGB register FF%02X in DMG mode", address);
|
||||
} else if (gb->audio.enable) {
|
||||
GBAudioRun(&gb->audio, mTimingCurrentTime(gb->audio.timing));
|
||||
return (gb->audio.ch1.sample) | (gb->audio.ch2.sample << 4);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate", "gb.serialize");
|
||||
|
||||
MGBA_EXPORT const uint32_t GBSavestateMagic = 0x00400000;
|
||||
MGBA_EXPORT const uint32_t GBSavestateVersion = 0x00000002;
|
||||
MGBA_EXPORT const uint32_t GBSavestateVersion = 0x00000003;
|
||||
|
||||
void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
|
||||
STORE_32LE(GBSavestateMagic + GBSavestateVersion, 0, &state->versionMagic);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
MGBA_EXPORT const uint32_t GBASavestateMagic = 0x01000000;
|
||||
MGBA_EXPORT const uint32_t GBASavestateVersion = 0x00000004;
|
||||
MGBA_EXPORT const uint32_t GBASavestateVersion = 0x00000005;
|
||||
|
||||
mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate", "gba.serialize");
|
||||
|
||||
|
|
Loading…
Reference in New Issue