From 4fdadc585d2f5d7e389b8b23f737ef13f1c99852 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 17 Mar 2024 19:53:41 -0700 Subject: [PATCH] GB Audio: Fix audio envelope timing resetting too often (fixes #3164) --- CHANGES | 1 + .../nrx2_speed_change/xbaseline_0000.png | Bin 1388 -> 1193 bytes .../nrx2_speed_change/xbaseline_0000.png | Bin 1402 -> 1201 bytes src/gb/audio.c | 27 +++++++++++------- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index d850f2002..efb7d494e 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,7 @@ Features: - New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81 - Debugger: Add range watchpoints Emulation fixes: + - GB Audio: Fix audio envelope timing resetting too often (fixes mgba.io/i/3164) - GB I/O: Fix STAT writing IRQ trigger conditions (fixes mgba.io/i/2501) - GB Serialize: Add missing Pocket Cam state to savestates - GB Video: Implement DMG-style sprite ordering diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/xbaseline_0000.png index 0032b919f1aaef5acc9573be68705c0633b9bf45..e541e5c0ba570a3e33559ffc29e4b643a51c3c73 100644 GIT binary patch literal 1193 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|QHer;B4q#hkZu1B)Ij2)I1G zGVen9ly#nVD`bV)QW`sX=YF>fQeM_O;kJNUk!CbU;{ETsKrC?RK-v6W&HF{`wjT?4 zR9gGGBJHw!(&@(r*}r;kL~XjUea`E*lbkxQe_i`{rmwuyjqiW!_Ag%<&GE2ocVxe2 z=5OtdU(?zRzvX6gD=@k_tG|2QecN)a`yNj#ka0iLoAv$Xj8D4BU#~^%`PAQ&zWTqA&HMZNpTzvXaFb`-OXmlm^fa>{Pd3f2l3rn7yvU^Puyt*q{iO$= zeXqHv`2_w9DZa?iy*+pL{rCP~3x93id@;IoE1S{rT(LatkxJ7T@-=UUhfVw&UHJ_l?5l@0=k3FN~9eE`1C0%@xR;^KVZP z;|uFA`gisAgzn3~{iW#3{#EbIf4G)Ev@N-IaK~<*hsC7@AFo^f+F11}q4d!6R}WPG z32oVP&!(gE;YQvQ$G7VIYW(%b&}*Oac~M@ULno|e{61(rNq4Pg=I-lrwx`S$f2=xf z$JMVu@3OpuyY9+C?U!epXGqB1Zm5Yly-0q=az3%;|0^$kJ3Y0kJZsZZQ`Ox3t8l%x zr3Uxs#&sUhi;D7>UBhP_5tA=>8o1K7c~bc2O{ZLZnw_ox3pkUTl<+LSGO zLnoKU^-Pa=6m~tBeYNlnS5UAVeOcpoEv(AO>io%Bf%(Q3YU_?H{Ip`tBD<-ng}U8! zOYY4s&x@#v$T{+0HTVS|N)4j)_h&}7~}l3@QPfcfnQP!Z(m>gTe~DWM4f DU*lx* literal 1388 zcmdUv?N<^86vk;4^a8lrI-w4A&6m^4Nz+I{GZQu6h}2Wl&}4W{h%|J)fRRXyEmKOQQc@iFPQo!3MuI2}|BQXO&pr2kxaapgA8rK>8v|MAwhjOQ zKw|e{lAOK4SygL3b1FbRuLb~C2gYI|QVKY;H&ul#UZ0o!afI7X4WbrB_ni-OKXwiv zSog{nuux6Jt2W37gD6^iwg&%1n60JBJKp{CIR7tNKs6O-hXL|jMED8Z0j$LnG4b^sdS4Ef+3rd3q;+xBd{d$V(ICH&Wtxge|ueP zAdsD_diOxqL+7hf+;G7)O~u@E}wyB zfb2EmKeyxaS zZM#Z26=Ay4+06r`<&;MoDi5GjqG$2BSS6~1v{=2v6LRTeA#a&enRPn=yfvhl@D|nK zo8*Dv%0i}M5}Q|ySwH2&L)kL;X3SIpv;0hyBW?+59A$QVBSp#)B_JTB9h=s#P|URq zE~7Z_f|~5I%CjNM`ET^%s(b&I3lN7QOdjIKI>YqArGW{N%AVPb8!Em7%^464zPL3o zgj{%5d*wnD&21=Ca_#PJHTvrAj3{;04}aUarBZZ)OkblJQ{GtF&=sjm2CaW2MQ0Cl7UC^SKyE&JB$5PA zpz>tlhd_S1KE7z+J~X=9IVj(UQcg<>+Nrf7;vVr$W3v|LS#p_)ZQ`q{BHCN&F*J_^ z4*GpvE7?1){^$L_T&hb~qG0eV_R!kGZWN5maD9%ldPr8KUtC)c(iie|8ZRZ?=wi(^ z7$I1LT^f+4#iyDw%3jPJ?HeUnLWry`9(0<-BmJ4TDeR8cbLN#3#BbMJ>$sV`=t}2r zcKHaM6N2}N@+7a_4Yp7iC)u;^a=qPr=HFj2qQNSJ_D%)UPm??{o~2&4khckPmjnl6 z_4CIbecEN{m#Vt_P6kOIfC-)`fp(d1)1EkH4Hu---+XSi}S?G3TQZVo{`lh^CaO~>;2Ucf4UI`8oG4x^`n*p{CA)Q9yH zM6i76==L8KeCc=I6OnY;Z?e(;%u~k^!9lRE+`v!>upCJL|E>GNckJxus7M#&%U?7$ L3X2i!%`E*7PTjq& diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/xbaseline_0000.png index 2804b6f3a5f9ecfc563b1f9f493e383099380a35..5173a31fdeba2b6065b2a4d660eecb5cf72d6bd5 100644 GIT binary patch literal 1201 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|QHir;B4q#hkZuFHU--AmCb< zwf{oBPu=9&1>3q?8yqBBUt9X;7CU!@PnZ`W`FyW^-(gpo;}7@FpK(6gIe4BYN0S$S z`Io(qBYovL)=qt0+WEpf>9k7Wyq$X)h+lg}(>=pIk1x=O^1egYw;0?=S5>vF6ssx~s7zwR2v-zQ4Kq+r_$9LHEB4 zw!QsPcy8|VpB)zGjklaV^?dC@&GUCI&R%fo@a*G{|NTFe{oY>Y(z^9u^NlUyI-VUn z>6HX@_~Q7reBW|Qv*vhSd-&~R$d{D|PclkN#$1nyO9=nZ{LAHA(I2;hs;;_a2fzAW zlTPz-4K`eJk>RxU^Lgi=d)Lm`xA*VywZZr1m%e@wSNn3s&R>lmpC7#Q?{(Fy2ak5o z>1O{`zh_Nw{+IiQ`iu2+)|yF0XQn@0d-Yod*lEY#FXLUX&b+XDU%AcCUzXedyV;g* zu&R5ZA6)4hbm{i#4Uaim9x0wbvS9vVbABghZyD*A%6eZn8g+WFeUbi3I5|#g+8oYi z@$1WXzYr^$ofzrH)7JarmDLaJ4}W*RIPK?ERlW1nx=*LS?2lvLELSsa;_rin!FR&{ z)_qW#|6={++dO={x`w46{C*voF}+PS{m_G>UyWZs_;r@;2M@FH4%Nveb&~mp%w^Yu z*;hYa*}U}Ym4mN%&OBIGGpF+3Z^5WPo4#T`;gc=bt|_sHbk3ouQiAx$jwC z%X9WKdqndRq(Iiwd}ar0vo-pi{`Ib&L{T# z+WEA}zxUnYkDHj1+1vSf@2n-CPgiuS=9PnV%!}Q!Wu8^UoP*C(cK)9~_1>cRC&GVA zt7acuxKQ<5t9xqftK>+b=}{NYUwQuQDsOjuoSI>U=3ft4nQL*U?$}DqIJlHqdlt|* z$ql>f{#Zt;CC}euQupOQ<8$K~RuzsQxBp4jDg3cq=25~13ke-Qw(jPGLz8(f{=hE# UH?f-xJwQc~r>mdKI;Vst0G@ehoB#j- literal 1402 zcmdUv`BTyf0L9tb$lR2*3u8hmrghycz|>qt%_}nvODanikIalvL|YM9(2{1WwLFHz z`^Yj+OhnyAGa`?~V@<@PG+{HZ(2(ORNgiu|#{Tf$n|VKd=Kb*Qp2m5b7{iP~AdrdA z3D1D_EM8Z-(S~&g4eN(NpiOQ*o^EI9`SS&0nsV<}PoKW8?rV>P%A=ZHlyk|)%)Z}) z&1o({8}*n&;bo*dn9pA=wk@*LFs9YRd~a^eUChbe#%O86Xyc_*MsAR>d)XaXH#+Xn z>IK@O9j+&e>eoiJ#CfyL4N7p-=l}ft0dn~Ay&Ti zqBAkB6Ibk{>Y2RE_}QD@YbEmOxFYi}OQ~b!A|q+XLais~0L>VzGD; z>1Ye9M)fenxQ)7==oJB*Fj2<$H=#(CPiDcxU6HV{SdUxBH}Y)gqm8;_HNa^GHA>GncBMS1yolbu#EsF`|e@KLs6%?lis zw!=xiGHj+Hj6ua;grMviYyc#XgRvs9tDe|DUfWQPC{al`nlZZh|Ml4c(E;` zY{pKf&N%apNk$tlXD-Dyz_nIPwc@IIFmKCj96!@=llcMyo-R%6y`o|-xzN4pyvZkn zQ}o;B{F$^QYQ$iSii diff --git a/src/gb/audio.c b/src/gb/audio.c index 996fce66d..cf5445e15 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -33,10 +33,10 @@ static void _writeDuty(struct GBAudioEnvelope* envelope, uint8_t value); static bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value, enum GBAudioStyle style); static void _resetSweep(struct GBAudioSweep* sweep); -static bool _resetEnvelope(struct GBAudioEnvelope* sweep); +static bool _resetEnvelope(struct GBAudioEnvelope* sweep, enum GBAudioStyle style); static void _updateEnvelope(struct GBAudioEnvelope* envelope); -static void _updateEnvelopeDead(struct GBAudioEnvelope* envelope); +static void _updateEnvelopeDead(struct GBAudioEnvelope* envelope, enum GBAudioStyle style); static bool _updateSweep(struct GBAudioSquareChannel* sweep, bool initial); static void _updateSquareSample(struct GBAudioSquareChannel* ch); @@ -192,7 +192,7 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) { } } if (GBAudioRegisterControlIsRestart(value << 8)) { - audio->playingCh1 = _resetEnvelope(&audio->ch1.envelope); + audio->playingCh1 = _resetEnvelope(&audio->ch1.envelope, audio->style); audio->ch1.sweep.realFrequency = audio->ch1.control.frequency; _resetSweep(&audio->ch1.sweep); if (audio->playingCh1 && audio->ch1.sweep.shift) { @@ -243,7 +243,7 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) { } } if (GBAudioRegisterControlIsRestart(value << 8)) { - audio->playingCh2 = _resetEnvelope(&audio->ch2.envelope); + audio->playingCh2 = _resetEnvelope(&audio->ch2.envelope, audio->style); if (!audio->ch2.control.length) { audio->ch2.control.length = 64; @@ -383,7 +383,7 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { } } if (GBAudioRegisterNoiseControlIsRestart(value)) { - audio->playingCh4 = _resetEnvelope(&audio->ch4.envelope); + audio->playingCh4 = _resetEnvelope(&audio->ch4.envelope, audio->style); audio->ch4.lfsr = 0; if (!audio->ch4.length) { @@ -877,9 +877,10 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { mTimingSchedule(timing, &audio->sampleEvent, audio->sampleInterval * audio->timingFactor - cyclesLate); } -bool _resetEnvelope(struct GBAudioEnvelope* envelope) { +bool _resetEnvelope(struct GBAudioEnvelope* envelope, enum GBAudioStyle style) { envelope->currentVolume = envelope->initialVolume; - _updateEnvelopeDead(envelope); + envelope->nextStep = envelope->stepTime; + _updateEnvelopeDead(envelope, style); return envelope->initialVolume || envelope->direction; } @@ -932,7 +933,7 @@ bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value, enum GBAudi } envelope->currentVolume &= 0xF; } - _updateEnvelopeDead(envelope); + _updateEnvelopeDead(envelope, style); return envelope->initialVolume || envelope->direction; } @@ -968,16 +969,20 @@ static void _updateEnvelope(struct GBAudioEnvelope* envelope) { } } -static void _updateEnvelopeDead(struct GBAudioEnvelope* envelope) { +static void _updateEnvelopeDead(struct GBAudioEnvelope* envelope, enum GBAudioStyle style) { if (!envelope->stepTime) { envelope->dead = envelope->currentVolume ? 1 : 2; } else if (!envelope->direction && !envelope->currentVolume) { envelope->dead = 2; } else if (envelope->direction && envelope->currentVolume == 0xF) { envelope->dead = 1; - } else { + } else if (envelope->dead) { + // TODO: Figure out if this happens on DMG/CGB or just AGB + // TODO: Figure out the exact circumstances that lead to reloading the step + if (style == GB_AUDIO_GBA) { + envelope->nextStep = envelope->stepTime; + } envelope->dead = 0; - envelope->nextStep = envelope->stepTime; } }