diff --git a/BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs b/BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs index 71e520b738..8337e410e8 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs @@ -1,4 +1,5 @@ using System; +using BizHawk.Emulation.Sound; namespace BizHawk.Emulation.Consoles.TurboGrafx { @@ -13,11 +14,35 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx public ushort adpcm_write_address; public ushort adpcm_length; - public long adpcm_read_timer, adpcm_write_timer; + public int adpcm_read_timer, adpcm_write_timer; public byte adpcm_read_buffer, adpcm_write_buffer; public bool adpcm_read_pending, adpcm_write_pending; - public byte[] ADPCM_RAM; + long LastThink; + float adpcm_playback_timer; + + public byte[] ADPCM_RAM; + + public MetaspuSoundProvider ADPCM_Provider; + + static readonly int[] StepSize = + { + 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 140, 143, + 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, + 494, 544, 598, 658, 724, 796, 876, 963,1060,1166,1282,1411, + 1552 + }; + + static readonly int[] StepFactor = { -1, -1, -1, -1, 2, 4, 6, 8 }; + + int AddClamped(int num1, int num2, int min, int max) + { + int result = num1 + num2; + if (result < min) return min; + if (result > max) return max; + return result; + } public void AdpcmControlWrite(byte value) { @@ -28,58 +53,160 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx adpcm_read_address = 0; adpcm_write_address = 0; adpcm_io_address = 0; + nibble = false; + playingSample = 0; + adpcm_playback_timer = 0; + magnitude = 0; + AdpcmIsPlaying = false; } - else if ((value & 8) != 0) + if ((value & 8) != 0) { adpcm_read_address = adpcm_io_address; if ((value & 4) == 0) adpcm_read_address--; } - else if ((CdIoPorts[0x0D] & 2) == 0 && (value & 2) != 0) + if ((CdIoPorts[0x0D] & 2) == 0 && (value & 2) != 0) { adpcm_write_address = adpcm_io_address; if ((value & 1) == 0) adpcm_write_address--; } + + if ((value & 0x10) != 0) + { + adpcm_length = adpcm_io_address; + Console.WriteLine("SET LENGTH={0:X4}", adpcm_length); + } + + if (AdpcmIsPlaying && (value & 0x20) == 0) + AdpcmIsPlaying = false; // only plays as long as this bit is set + + if (AdpcmIsPlaying == false && (value & 0x20) != 0) + { + Console.WriteLine("Start playing!"); + AdpcmIsPlaying = true; + nibble = false; + playingSample = 0; + adpcm_playback_timer = 0; + magnitude = 0; + } } public void AdpcmDataWrite(byte value) { adpcm_write_buffer = value; - adpcm_write_timer = Cpu.TotalExecutedCycles + 24; + adpcm_write_timer = 24; adpcm_write_pending = true; } public byte AdpcmDataRead() { adpcm_read_pending = true; - adpcm_read_timer = Cpu.TotalExecutedCycles + 24; + adpcm_read_timer = 24; return adpcm_read_buffer; } - public bool AdpcmIsPlaying { get { return false; } } + + public bool AdpcmIsPlaying { get; private set; } public bool AdpcmBusyWriting { get { return AdpcmCdDmaRequested; } } public bool AdpcmBusyReading { get { return adpcm_read_pending; } } + + Random rnd = new Random(); + + int playingSample; + int nextSampleTimer = 0; + bool nibble; + + int magnitude; + + void DecodeAdpcmSample() + { + // get sample. it's one nibble. + byte sample; + if (nibble == false) + { + sample = (byte) (ADPCM_RAM[adpcm_read_address] >> 4); + nibble = true; + } else { + sample = (byte)(ADPCM_RAM[adpcm_read_address] & 0xF); + nibble = false; + adpcm_length--; + adpcm_read_address++; + } + + bool positive = (sample & 8) == 0; + int mag = sample & 7; + int m = StepFactor[mag]; + + magnitude = AddClamped(magnitude, m, 0, 48); + int adjustment = StepSize[magnitude]; + if (positive == false) adjustment *= -1; + playingSample = AddClamped(playingSample, adjustment, 0, 4095); + + adpcm_length--; + } + + void AdpcmEmitSample() + { + if (AdpcmIsPlaying == false) + ADPCM_Provider.buffer.enqueue_sample(0, 0); + else + { + int rate = 16 - (CdIoPorts[0x0E] & 0x0F); + float khz = 32 / rate; + + if (nextSampleTimer == 0) + { + DecodeAdpcmSample(); + nextSampleTimer = 4; + } + nextSampleTimer--; + + if (adpcm_length == 0) + { + AdpcmIsPlaying = false; + } + + short adjustedSample = (short)((playingSample - 2048) << 3); + ADPCM_Provider.buffer.enqueue_sample(adjustedSample, adjustedSample); + } + } public void AdpcmThink() { - if (adpcm_read_pending && Cpu.TotalExecutedCycles >= adpcm_read_timer) + int cycles = (int) (Cpu.TotalExecutedCycles - LastThink); + LastThink = Cpu.TotalExecutedCycles; + + adpcm_playback_timer -= cycles; + if (adpcm_playback_timer < 0) + { + adpcm_playback_timer += 162.81f; // # of CPU cycles that translate to one 44100hz sample. + AdpcmEmitSample(); + } + + if (adpcm_read_timer > 0) adpcm_read_timer -= cycles; + if (adpcm_write_timer > 0) adpcm_write_timer -= cycles; + + if (adpcm_read_pending && adpcm_read_timer <= 0) { adpcm_read_buffer = ADPCM_RAM[adpcm_read_address++]; adpcm_read_pending = false; + if (adpcm_length > ushort.MinValue) + adpcm_length--; } - if (adpcm_write_pending && Cpu.TotalExecutedCycles >= adpcm_write_timer) + if (adpcm_write_pending && adpcm_write_timer <= 0) { ADPCM_RAM[adpcm_write_address++] = adpcm_write_buffer; adpcm_write_pending = false; + if (adpcm_length < ushort.MaxValue) + adpcm_length++; } if (AdpcmCdDmaRequested) { - //Console.WriteLine("CD->ADPCM dma..."); if (SCSI.REQ && SCSI.IO && !SCSI.CD && !SCSI.ACK) { byte dmaByte = SCSI.DataBits; @@ -96,10 +223,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx Console.WriteLine(" ADPCM DMA COMPLETED"); } } - - // Do audio rendering and shit. + + CdIoPorts[0x03] &= 0xF3; + if (AdpcmIsPlaying == false) CdIoPorts[0x03] |= 0x08; + RefreshIRQ2(); } - private bool AdpcmCdDmaRequested { get { return (CdIoPorts[0x0B] & 3) != 0; } } + bool AdpcmCdDmaRequested { get { return (CdIoPorts[0x0B] & 3) != 0; } } } } diff --git a/BizHawk.Emulation/Consoles/PC Engine/Compat.txt b/BizHawk.Emulation/Consoles/PC Engine/Compat.txt index 7bf005b455..039cefe28a 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/Compat.txt +++ b/BizHawk.Emulation/Consoles/PC Engine/Compat.txt @@ -2,15 +2,17 @@ * Turbo CD Issues * ****************************************************** +- Baby Jo, a totally terrible game. - Download 2, eventually has issues. Seems like waiting on ADPCM interrupts or flags. - Similar in Dragon Slayer - Dungeon Explorer II quite desperately need ADPCM audio + and a gross corruption issue at teh end of the intro. and then it freezes. :( -- Dynastic Hero... a CD-command related hard crash :( - Exile II .. seems to reset itself after playing the unskippable intro. :( - Macross 2036.. seems impossible to start/play the game. :( +- rtype, end of level 4 dies with unrecognized scsi command ff +- Startling Odyssey does the reset-at-new-game-screen thats rather odd :( - Super Darius II : at 1st Boss, game freezes waiting for adpcm - Ys 1, start new game, death by adpcm probably @@ -18,8 +20,6 @@ - - ======= TurboGrafx compatibility issues ======= General: @@ -31,8 +31,6 @@ General: Eagan's Rendered Sprite Demo - demonstrates sprites that shouldnt be displayed -Games Express CD Card 1993 - dont forget to treat as a turbocd system card - =================================== Games that need TV Emulation (to varying degrees) =================================== @@ -41,7 +39,7 @@ Greater degrees: Final Blaster - Intro does crazy shit with video modes; not sure what if anything to do about it Griffon - Mid-frame res changes (hax to make playable) -Yo, Bro - Mid-frame res changes (hax to make playable) +Yo, Bro - Mid-frame res changes (hax to make playable) (IF YOU CAN CALL THIS GAME PLAYABLE) Lesser degrees: @@ -55,6 +53,9 @@ Madoo Granzort - Screen ~5 pixels too tall Metal Stoker - Tearing when scrolling vertically at bottom of screen - screen too tall? Side Arms - Screen is like 4 pixels too tall + +Game Express card games don't work yet. + =================================== Stuff I Fixed That's Not In Other Docs: =================================== diff --git a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs index 8dbee29b88..0a94321229 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs @@ -114,8 +114,8 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx Cpu.WriteMemory21 = WriteMemoryCD; Cpu.WriteVDC = VDC1.WriteVDC; CDAudio = new CDAudio(disc, short.MaxValue); - // TODO ADPCM - SoundMixer = new SoundMixer(PSG, CDAudio); + ADPCM_Provider = new MetaspuSoundProvider(ESynchMethod.ESynchMethod_V); + SoundMixer = new SoundMixer(PSG, CDAudio, ADPCM_Provider); SoundSynchronizer = new MetaspuSoundProvider(ESynchMethod.ESynchMethod_V); soundProvider = SoundSynchronizer; Cpu.ThinkAction = () => { SCSI.Think(); AdpcmThink(); }; @@ -456,15 +456,46 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx private void SetupMemoryDomains() { - var domains = new List(1); + var domains = new List(10); var MainMemoryDomain = new MemoryDomain("Main Memory", Ram.Length, Endian.Little, - addr => Ram[addr & 0x7FFF], - (addr, value) => Ram[addr & 0x7FFF] = value); + addr => Ram[addr & 0x1FFF], + (addr, value) => Ram[addr & 0x1FFF] = value); + domains.Add(MainMemoryDomain); + var SystemBusDomain = new MemoryDomain("System Bus", 0x2F0000, Endian.Little, addr => Cpu.ReadMemory21(addr), (addr, value) => Cpu.WriteMemory21(addr, value)); - domains.Add(MainMemoryDomain); domains.Add(SystemBusDomain); + + if (BRAM != null) + { + var BRAMMemoryDomain = new MemoryDomain("Battery RAM", Ram.Length, Endian.Little, + addr => BRAM[addr & 0x7FF], + (addr, value) => BRAM[addr & 0x7FF] = value); + domains.Add(BRAMMemoryDomain); + } + + if (TurboCD) + { + var CDRamMemoryDomain = new MemoryDomain("TurboCD RAM", CDRam.Length, Endian.Little, + addr => CDRam[addr & 0xFFFF], + (addr, value) => CDRam[addr & 0xFFFF] = value); + domains.Add(CDRamMemoryDomain); + + var AdpcmMemoryDomain = new MemoryDomain("ADPCM RAM", ADPCM_RAM.Length, Endian.Little, + addr => ADPCM_RAM[addr & 0xFFFF], + (addr, value) => ADPCM_RAM[addr & 0xFFFF] = value); + domains.Add(AdpcmMemoryDomain); + + if (SuperRam != null) + { + var SuperRamMemoryDomain = new MemoryDomain("Super System Card RAM", SuperRam.Length, Endian.Little, + addr => SuperRam[addr & 0x3FFFF], + (addr, value) => SuperRam[addr & 0x3FFFF] = value); + domains.Add(SuperRamMemoryDomain); + } + } + memoryDomains = domains.AsReadOnly(); } diff --git a/BizHawk.Emulation/Consoles/PC Engine/ScsiCDBus.cs b/BizHawk.Emulation/Consoles/PC Engine/ScsiCDBus.cs index f280df17d8..b71a471128 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/ScsiCDBus.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/ScsiCDBus.cs @@ -457,7 +457,10 @@ throw new Exception("requesting 0 sectors read............................."); case 0x80: // Set end offset in track units byte trackNo = CommandBuffer[2].BCDtoBin(); - audioEndLBA = disc.TOC.Sessions[0].Tracks[trackNo - 1].Indexes[1].aba - 150; + if (trackNo - 1 >= disc.TOC.Sessions[0].Tracks.Count) + audioEndLBA = disc.LBACount; + else + audioEndLBA = disc.TOC.Sessions[0].Tracks[trackNo - 1].Indexes[1].aba - 150; Console.WriteLine("Set End track: {0} lba={1}", trackNo, audioEndLBA); break; } diff --git a/BizHawk.Emulation/Sound/Utilities/Metaspu.cs b/BizHawk.Emulation/Sound/Utilities/Metaspu.cs index a3eca1c2d6..34b7e0654c 100644 --- a/BizHawk.Emulation/Sound/Utilities/Metaspu.cs +++ b/BizHawk.Emulation/Sound/Utilities/Metaspu.cs @@ -564,11 +564,11 @@ namespace BizHawk.Emulation.Sound } } - private Queue buffer; - private Sample[] resampleBuffer; + Queue buffer; + Sample[] resampleBuffer; - private const int SamplesInOneFrame = 735; - private const int MaxExcessSamples = 2048; + const int SamplesInOneFrame = 735; + const int MaxExcessSamples = 2048; public VecnaSynchronizer() { @@ -624,8 +624,8 @@ namespace BizHawk.Emulation.Sound for (int i = 0; i 0; i++) { Sample sample = buffer.Dequeue(); - buf[index++] = sample.left; - buf[index++] = sample.right; + buf[index++] += sample.left; + buf[index++] += sample.right; } } return samples_requested; diff --git a/BizHawk.MultiClient/output/gamedb_pce_cd.txt b/BizHawk.MultiClient/output/gamedb_pce_cd.txt index 632b924ab6..476a3fca8d 100644 --- a/BizHawk.MultiClient/output/gamedb_pce_cd.txt +++ b/BizHawk.MultiClient/output/gamedb_pce_cd.txt @@ -1,27 +1,52 @@ -3E9ED52416C4642096EC78B16AFA3956 Alzadick PCE +C76EF1F635E27216E74EB9C576FCAB69 3 x 3 Eyes - Sanjiyan Hensei PCE NeedSuperSysCard;ArcadeCard +A4821BBB5F1908EA282285D0E46697E3 Advanced Variable Geo PCE NeedSuperSysCard +AA86F346BB6516C50BD78872EE486F47 Ai Chou Aniki PCE NeedSuperSysCard +ADE5602045C6E76D580888E808CAC0BC Alshark PCE NeedSuperSysCard +3E9ED52416C4642096EC78B16AFA3956 Alzadick PCE +B18BFEFDA3B2D5551D6DFADF3EFBB5E6 Angels II - Holy Night [Prototype] PCE NeedSuperSysCard +C0F1830D7867B07125AFB523C3A073D8 Auleria PCE +02D61594738BF9A70FD76F5E1B14DA7A AV Tanjou (GECD) PCE +F6F29A11CFD835A694DC4D921928CC8D Avenger PCE +03B7EBFE37F2B73C56ABC6DF853E6E5B Baby Jo PCE NeedSuperSysCard +AADD9FA50FFB1DE04D8436E3E283F49C Bakuretsu Hunter PCE NeedSuperSysCard +3D69BFBFEC21AA72F5ABB60C8FAE7953 Beyond Shadowgate PCE NeedSuperSysCard +392C7E2094D1B5A6A51AD5F64DE6356F Bikini Girls PCE +F583C57A1AF7164267E927386C89D2F4 Bishoujo Jyanshi Idol Pai (GECD) PCE +BADBE7E4CE0BD917338CAC5DA8451382 Bishoujo Senshi Sailor Moon PCE NeedSuperSysCard 3770A9888388B41A10C28841F9EFD15B Black Hole Assault PCE NeedSuperSysCard 147F46AA1E72C204488035ABB6E8DD37 Blood Gear PCE NeedSuperSysCard 067CB059A300BD731E7620803CAE044E Bomberman '94 Special Version PCE NeedSuperSysCard F4BCF27A1407EDD8AAF51C34E3EAF0C3 Bonk 3 PCE NeedSuperSysCard 491B7FAB01C8A4017221270EFBDBFF37 Brandish PCE NeedSuperSysCard;ArcadeCard +476DAFB769EC3594B12013AABFDBF637 Buster Bros PCE NeedSuperSysCard +4F49DC3E197CA2300AD39E76AA3571C4 Camp California PCE NeedSuperSysCard 5835601EC3879D4E5161DE2BC30BDF44 Cardangels PCE NeedSuperSysCard +F1919F1E3A11764510FB5D982AF8FAF3 Chiki Chiki Boys PCE NeedSuperSysCard +B53303049A7E0DE50EDBD26F6E76472C Chou Aniki PCE NeedSuperSysCard 60AAF2DA21D2AA0BADFCFC0EDE4006D5 Cosmic Fantasy II (U) PCE EDD630721F0719F1648A2E00621AD7B7 Cotton (U) PCE NeedSuperSysCard +EA8C641187C0B1387167D3BE8497905C Crest of the Wolf PCE NeedSuperSysCard +6E4EFC271EF135FEBFCC1E42E9C80AFE Develo Magazine Vol. 1 PCE NeedSuperSysCard 78009190135209BE042D8355B647BE35 Dracula X - Rondo of Blood PCE NeedSuperSysCard +A0C9253B7CD09B0B87DDF91D1E0B4536 Dragon Knight II PCE NeedSuperSysCard +508C7FD84400EBD83FE0C38061BC7EC1 Dragon Slayer - The Legend of Heroes PCE NeedSuperSysCard F6869EBAB1F3F5927B92F59DCF34D512 Double Dragon 2 - The Revenge PCE NeedSuperSysCard DBF82B69AB6AE97E7E16F64FC9267253 Download II PCE 0C260D7C5758E786D80D75ED60E135B8 Dragon Slayer (U) PCE NeedSuperSysCard 00C357F33118BCD033F98952370126A8 Dungeon Explorer II (U) PCE NeedSuperSysCard 65069522E26B5A41F457ADAF97474889 Dungeon Master - Theron's Quest (U) PCE NeedSuperSysCard +5789256071B1FDF2FE919447022EB92D Dynastic Hero PCE NeedSuperSysCard 3CCA1F2CEFC009906EDC19BD5AD30138 Emerald Dragon PCE NeedSuperSysCard E5C69B9D84AEA0641041FB355F66B33A Exile (U) PCE 6DCB244E33963B5F82B0B96B1BA4A4A5 Exile II - Wicked Phenomenon (U) PCE NeedSuperSysCard A067C38F8D5E3AB35FA0EB238C141B81 Fantasy Star Soldeier PCE NeedSuperSysCard +C6014BBE95BD25FA809CC1E08D030E2A Fausseté Amour PCE NeedSuperSysCard 68C794604F210B82D21C5B9DCFAB4596 Final Zone II (U) PCE 71CB34D94D36C19901EA67B6355CDC98 Flash Hiders PCE NeedSuperSysCard 579CFB162AF2B56BB5D178CE32AEC328 Forgotten Worlds (U) PCE NeedSuperSysCard E7C724F744BE836B955D212160F5475E Gain Ground SX PCE NeedSuperSysCard -5D4E8379FDA5160C4400D926ADEA0F92 Gates Of Thunder (U) PCE NeedSuperSysCard +5F13EFF0F9FD89E8AB75540EBE4E58F9 Gates Of Thunder (U) PCE NeedSuperSysCard +; stopped here when I realized old hashes may be wrong 619424C78C17F4D759994810B3253048 God Panic PCE NeedSuperSysCard 5B969960E0B1DA41BCF1A2352724EB63 Golden Axe PCE 7F83141788B5A94A339689FD5F4A0840 Gradius II PCE NeedSuperSysCard diff --git a/BizHawk.MultiClient/output/gamedb_pce_hucards.txt b/BizHawk.MultiClient/output/gamedb_pce_hucards.txt index 9e214d445c..486eddb079 100644 --- a/BizHawk.MultiClient/output/gamedb_pce_hucards.txt +++ b/BizHawk.MultiClient/output/gamedb_pce_hucards.txt @@ -476,10 +476,6 @@ F9F2E2A22B62014E7DD59EBB6E41839B Galaga '90 (Tai Sang Version) (U) PCE FDC1E7D842164C152E2C36A411E56F0E Galaga '90 (U) [h1] PCE 7B8EE897CB1B7A3A6B88AC31D5E2729C Galaga '90 (U) [t1] PCE 94814DB23E163DBFC7D7505170E145C2 Galaga '90 (U) PCE -4492ABEFDBC6759D7BA4A67173C28A2A V Games Express CD Card 1993 (J) [b1] PCE -4E2440576DEE3B9FE25C3A000126A42B Games Express CD Card 1993 (J) [o1] PCE -2E1ACCEC7CDEBEDEE1F699684549507A Games Express CD Card 1993 (J) [o2] PCE -6D2CB14FC3E1F65CEB135633D1694122 Games Express CD Card 1993 (J) PCE FCF8BDC8F67F284A841CADDD82D8B3E6 Ganbare Golf Boys (J) PCE B2ABE3457A7ED21D27FA4DBA930B4AAB Ganbare Golf Boys Sounds PCE 6675160B2A45A08B47A764E005C1A1FF V Gekisha Boy (J) [b1] PCE @@ -1600,3 +1596,8 @@ D3A12A001E22EFB1436EC509D453A10F V Super CD-ROM2 System V3.00 (J) [o4] PCE BRAM 0754F903B52E3B3342202BDAFB13EFA5 I Super CD-ROM2 System V3.00 (U) PCE BRAM;SuperSysCard;BIOS 98D43A097A165B03DF170FD5C2AD2C2F V Super CD-ROM2 System V3.01 (U) [b1] PCE BRAM;SuperSysCard;BIOS +4492ABEFDBC6759D7BA4A67173C28A2A V Games Express CD Card 1993 (J) [b1] PCE BRAM;BIOS +4E2440576DEE3B9FE25C3A000126A42B Games Express CD Card 1993 (J) [o1] PCE BRAM;BIOS +2E1ACCEC7CDEBEDEE1F699684549507A Games Express CD Card 1993 (J) [o2] PCE BRAM;BIOS +6D2CB14FC3E1F65CEB135633D1694122 Games Express CD Card 1993 (J) PCE BRAM;BIOS + diff --git a/DiscoHawk/DiscoHawk.csproj b/DiscoHawk/DiscoHawk.csproj index 1954e157ff..1081b4d426 100644 --- a/DiscoHawk/DiscoHawk.csproj +++ b/DiscoHawk/DiscoHawk.csproj @@ -43,6 +43,7 @@ 4 false AllRules.ruleset + x86 pdbonly