diff -Nru kodi-audiodecoder-gme-2.0.3/appveyor.yml kodi-audiodecoder-gme-19.0.3/appveyor.yml --- kodi-audiodecoder-gme-2.0.3/appveyor.yml 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/appveyor.yml 2013-05-31 22:59:22.000000000 +0000 @@ -16,14 +16,14 @@ CONFIG: Release - GENERATOR: "Visual Studio 15 Win64" CONFIG: Release - WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.16299.0" + WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" - GENERATOR: "Visual Studio 15 ARM" CONFIG: Release - WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.16299.0" + WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" build_script: - cd .. - - git clone --branch Leia --depth=1 https://github.com/xbmc/xbmc.git + - git clone --branch Matrix --depth=1 https://github.com/xbmc/xbmc.git - cd %app_id% - mkdir build - cd build diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/addon.xml.in kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/addon.xml.in --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/addon.xml.in 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/addon.xml.in 2013-05-31 22:59:22.000000000 +0000 @@ -1,7 +1,7 @@ @ADDON_DEPENDS@ @@ -13,24 +13,31 @@ tracks="true" library_@PLATFORM@="@LIBRARY_FILENAME@"/> - Game Music Emu Audio Decoder - Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a "retro" feel to the sound. - -Suppoted Formats: -- AY: ZX Spectrum/Amstrad CPC -- GBS: Nintendo Game Boy -- GYM: Sega Genesis/Mega Drive -- HES: NEC TurboGrafx-16/PC Engine -- KSS: MSX Home Computer/other Z80 systems (no FM sound) -- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound) -- SAP: Atari systems using POKEY sound chip -- SPC: Super Nintendo/Super Famicom -- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro @PLATFORM@ - GPL-2.0 + GPL-2.0-or-later https://github.com/xbmc/audiodecoder.gme icon.png + Game Music Emu lydafkoder + Game Music Emu Audio Decoder + Game Music Emu Audio Decoder + Decodificador de Audio Game Music Emu + Decodificador de audio Game Music Emu + Game Music Emu -äänidekooderi + Game Musik Emu Audio Decoder + Game Music Emu 오디오 디코더 + Аудиодекодер Game Music Emu + 游戏音乐 Emu 音频解码器 + Game Music Emu (GME)-format bruges til at efterligne lydudgangen fra forskellige videospilkonsoller, der var populære i 1980'erne og 1990'erne. Det giver en "retro" fornemmelse af lyden.[CR][CR][B]Bemærk:[/B][CR]Ikke alle filformater giver længde, og i dette tilfælde er den indstillet til 2,5 minutter.[CR][ CR][B]Understøttede formater:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX hjemmecomputer/andre Z80-systemer (ingen FM-lyd)[CR]- NSF/NSFE: Nintendo NES/Famicom (med VRC 6, Namco 106 og FME-7 lyd)[CR]- SAP: Atari-systemer, der bruger POKEY-lydchip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro + Das GME-Format (Game Music Emu) wird verwendet, um die Audioausgabe verschiedener Videospielkonsolen zu emulieren, die in den 1980er und 1990er Jahren beliebt waren. Es gibt dem Sound ein "Retro" -Gefühl.[CR][CR][B]Hinweis:[/B][CR]Nicht alle Dateiformate geben Länge und wird in diesem Fall auf 2,5 Minuten gesetzt.[CR][CR][B]Unterstützte Formate:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro + Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a "retro" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro + El formato Game Music Emu (GME) se usa para emular la salida de audio de varias videoconsolas populares en las decadas de 1980 y 1990. El da un aire "retro" al sonido.[CR][CR][B]Nota:[/B][CR]No todos los formatos tienen en cuenta la duracion y en esos casos se establece a 2.5 minutos.[CR][CR][B]Formatos soportados:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/otros sistemas Z80 (sin sonido FM)[CR]- NSF/NSFE: Nintendo NES/Famicom (con sonido VRC 6, Namco 106 y FME-7)[CR]- SAP: Sistemas Atari que usen el chip de sonido POKEY[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro + El formato Game Music Emu (GME) se usa para emular la salida de audio de varias consolas de videojuegos populares en las décadas de 1980 y 1990. Da un aire "retro" al sonido.[CR][CR][B]Nota:[/B][CR]No todos los formatos establecen la duración, y en esos casos se establece a 2.5 minutos.[CR][CR][B]Formatos soportados:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/otros sistemas Z80 (sin sonido FM)[CR]- NSF/NSFE: Nintendo NES/Famicom (con sonido VRC 6, Namco 106 y FME-7)[CR]- SAP: Sistemas Atari con chip de sonido POKEY[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro + Game Music Emu (GME) -muotoa käytetään emuloitaessa monien 1980- ja 1990-luvun pelikonsoleiden äänilähtöä . Se antaa äänelle "retromaisen" vivahteen.[CR][CR][B]Huomioi:[/B][CR]Kaikki tiedostotyypit eivät ilmoita kestoa ja tällöin se asetetaan 2.5 minuuttiin.[CR][CR][B]Tuetut muodot:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/muu Z80 järjestelmä (ei FM-ääntä)[CR]- NSF/NSFE: Nintendo NES/Famicom (varustettuna VRC 6, Namco 106 ja FME-7 -äänellä)[CR]- SAP: Atari-järjestelmät POKEY-äänipiirillä[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive ja BBC Micro + Format Game Music Emu (GME) digunakan untuk meniru output audio dari berbagai konsol video game yang populer di tahun 1980-an dan 1990-an. Ini memberikan nuansa "retro" pada suara.[CR][CR][B]Catatan:[/B][CR]Tidak semua format file memberikan panjang dan dalam hal ini diatur ke 2,5 menit.[CR][][CR] CR][B]Format yang Didukung:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/sistem Z80 lainnya (tanpa suara FM)[CR]- NSF/NSFE: Nintendo NES/Famicom (dengan suara VRC 6, Namco 106, dan FME-7) [CR]- SAP: Sistem Atari menggunakan chip suara POKEY[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro + GME(Game Music Emu) 형식은 1980년대와 1990년대에 유행했던 다양한 비디오 게임 콘솔의 오디오 출력을 에뮬레이트하는 데 사용됩니다. 사운드에 "복고풍" 느낌을 줍니다.[CR][CR][B]참고:[/B][CR]일부 파일 형식은 길이를 제공하지 않으며 이 경우에는 2.5분으로 설정됩니다.[CR][ CR][B]지원되는 형식:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC 엔진[CR]- KSS: MSX 가정용 컴퓨터/기타 Z80 시스템(FM 사운드 없음)[CR]- NSF/NSFE: Nintendo NES/Famicom(VRC 6, Namco 106 및 FME-7 사운드 포함) [CR]- SAP: POKEY 사운드 칩을 사용하는 Atari 시스템[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro + Формат Game Music Emu (GME) используется для эмуляции аудиовыхода различных игровых приставок, популярных в 1980-х и 1990-х годах. Он придает звуку ощущение "ретро".[CR][CR][B]Примечание:[/B][CR]Не все форматы файлов указывают длину, в данном случае она установлена на 2,5 минуты. [CR][CR][B]Поддерживаемые форматы:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/другие Z80 системы (без FM звука)[CR]- NSF/NSFE: Nintendo NES/Famicom (со звуком VRC 6, Namco 106 и FME-7)[CR]- SAP: Системы Atari, использующие звуковой чип POKEY[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro + 游戏音乐 Emu(GME)格式用于模拟20世纪80年代和90年代流行的各种视频游戏机的音频输出。它给声音一种“复古”的感觉。[CR][CR][B]注:[/B][CR]并非所有文件格式都给出时长,在这种情况下,它被设置为2.5分钟。[CR][CR][B]支持的格式:[/B][CR]- AY:ZX Spectrum/Amstrad CPC[CR]- GBS:任天堂 Game Boy[CR]- GYM:世嘉 Genesis/Mega Drive[CR]- HES:NEC TurboGrafx-16/PC Engine[CR]- KSS:MSX 家用电脑/其他Z80系统(无FM声音)[CR]- NSF/NSFE:任天堂 NES/Famicom(带有VRC 6、Namco 106 和 FME-7 声音)[CR]- SAP:雅达利系统使用 POKEY sound 芯片[CR]- SPC:超级任天堂/Super Famicom[CR]- VGM/VGZ:世嘉 Master System/Mark III、世嘉Genesis/Mega Drive、BBC Micro diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.af_za/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.af_za/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.af_za/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.af_za/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: af_za\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.am_et/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.am_et/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.am_et/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.am_et/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: am_et\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ar_sa/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ar_sa/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ar_sa/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ar_sa/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ar_sa\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ast_es/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ast_es/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ast_es/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ast_es/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ast_es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.az_az/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.az_az/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.az_az/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.az_az/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: az_az\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.be_by/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.be_by/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.be_by/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.be_by/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: be_by\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.bg_bg/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.bg_bg/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.bg_bg/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.bg_bg/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: bg_bg\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.bs_ba/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.bs_ba/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.bs_ba/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.bs_ba/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: bs_ba\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ca_es/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ca_es/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ca_es/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ca_es/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ca_es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.cs_cz/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.cs_cz/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.cs_cz/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.cs_cz/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: cs_cz\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.cy_gb/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.cy_gb/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.cy_gb/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.cy_gb/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: cy_gb\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=(n==0) ? 0 : (n==1) ? 1 : (n==2) ? 2 : (n==3) ? 3 :(n==6) ? 4 : 5;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.da_dk/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.da_dk/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.da_dk/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.da_dk/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,26 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2021-10-21 12:30+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Danish \n" +"Language: da_dk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.8\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "Game Music Emu lydafkoder" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "Game Music Emu (GME)-format bruges til at efterligne lydudgangen fra forskellige videospilkonsoller, der var populære i 1980'erne og 1990'erne. Det giver en \"retro\" fornemmelse af lyden.[CR][CR][B]Bemærk:[/B][CR]Ikke alle filformater giver længde, og i dette tilfælde er den indstillet til 2,5 minutter.[CR][ CR][B]Understøttede formater:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX hjemmecomputer/andre Z80-systemer (ingen FM-lyd)[CR]- NSF/NSFE: Nintendo NES/Famicom (med VRC 6, Namco 106 og FME-7 lyd)[CR]- SAP: Atari-systemer, der bruger POKEY-lydchip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.de_de/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.de_de/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.de_de/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.de_de/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: (https://kodi.weblate.cloud/languages/de_de/)\n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "Game Music Emu Audio Decoder" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "Das GME-Format (Game Music Emu) wird verwendet, um die Audioausgabe verschiedener Videospielkonsolen zu emulieren, die in den 1980er und 1990er Jahren beliebt waren. Es gibt dem Sound ein \"Retro\" -Gefühl.[CR][CR][B]Hinweis:[/B][CR]Nicht alle Dateiformate geben Länge und wird in diesem Fall auf 2,5 Minuten gesetzt.[CR][CR][B]Unterstützte Formate:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.el_gr/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.el_gr/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.el_gr/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.el_gr/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: el_gr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.en_au/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.en_au/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.en_au/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.en_au/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en_au\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.en_gb/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.en_gb/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.en_gb/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.en_gb/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: (https://kodi.weblate.cloud/languages/en_gb/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en_GB\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.en_nz/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.en_nz/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.en_nz/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.en_nz/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en_nz\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.en_us/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.en_us/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.en_us/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.en_us/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en_us\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.eo/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.eo/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.eo/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.eo/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: eo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.es_ar/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.es_ar/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.es_ar/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.es_ar/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: es_ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.es_es/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.es_es/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.es_es/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.es_es/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,26 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2022-01-22 22:13+0000\n" +"Last-Translator: Alfonso Cachero \n" +"Language-Team: Spanish (Spain) \n" +"Language: es_es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.10.1\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "Decodificador de Audio Game Music Emu" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "El formato Game Music Emu (GME) se usa para emular la salida de audio de varias videoconsolas populares en las decadas de 1980 y 1990. El da un aire \"retro\" al sonido.[CR][CR][B]Nota:[/B][CR]No todos los formatos tienen en cuenta la duracion y en esos casos se establece a 2.5 minutos.[CR][CR][B]Formatos soportados:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/otros sistemas Z80 (sin sonido FM)[CR]- NSF/NSFE: Nintendo NES/Famicom (con sonido VRC 6, Namco 106 y FME-7)[CR]- SAP: Sistemas Atari que usen el chip de sonido POKEY[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.es_mx/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.es_mx/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.es_mx/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.es_mx/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,26 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2022-01-22 22:13+0000\n" +"Last-Translator: Edson Armando \n" +"Language-Team: Spanish (Mexico) \n" +"Language: es_mx\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.10.1\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "Decodificador de audio Game Music Emu" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "El formato Game Music Emu (GME) se usa para emular la salida de audio de varias consolas de videojuegos populares en las décadas de 1980 y 1990. Da un aire \"retro\" al sonido.[CR][CR][B]Nota:[/B][CR]No todos los formatos establecen la duración, y en esos casos se establece a 2.5 minutos.[CR][CR][B]Formatos soportados:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/otros sistemas Z80 (sin sonido FM)[CR]- NSF/NSFE: Nintendo NES/Famicom (con sonido VRC 6, Namco 106 y FME-7)[CR]- SAP: Sistemas Atari con chip de sonido POKEY[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.et_ee/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.et_ee/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.et_ee/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.et_ee/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: et_ee\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.eu_es/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.eu_es/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.eu_es/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.eu_es/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: eu_es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fa_af/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fa_af/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fa_af/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fa_af/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fa_af\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fi_fi/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fi_fi/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fi_fi/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fi_fi/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,26 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2022-03-19 06:44+0000\n" +"Last-Translator: Oskari Lavinto \n" +"Language-Team: Finnish \n" +"Language: fi_fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.11.2\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "Game Music Emu -äänidekooderi" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "Game Music Emu (GME) -muotoa käytetään emuloitaessa monien 1980- ja 1990-luvun pelikonsoleiden äänilähtöä . Se antaa äänelle \"retromaisen\" vivahteen.[CR][CR][B]Huomioi:[/B][CR]Kaikki tiedostotyypit eivät ilmoita kestoa ja tällöin se asetetaan 2.5 minuuttiin.[CR][CR][B]Tuetut muodot:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/muu Z80 järjestelmä (ei FM-ääntä)[CR]- NSF/NSFE: Nintendo NES/Famicom (varustettuna VRC 6, Namco 106 ja FME-7 -äänellä)[CR]- SAP: Atari-järjestelmät POKEY-äänipiirillä[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive ja BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fo_fo/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fo_fo/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fo_fo/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fo_fo/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fo_fo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fr_ca/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fr_ca/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fr_ca/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fr_ca/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fr_ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fr_fr/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fr_fr/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.fr_fr/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.fr_fr/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fr_fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.gl_es/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.gl_es/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.gl_es/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.gl_es/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: gl_es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.he_il/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.he_il/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.he_il/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.he_il/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: he_il\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && n % 10 == 0) ? 2 : 3));\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.hi_in/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.hi_in/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.hi_in/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.hi_in/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: hi_in\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.hr_hr/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.hr_hr/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.hr_hr/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.hr_hr/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: hr_hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.hu_hu/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.hu_hu/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.hu_hu/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.hu_hu/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: hu_hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.hy_am/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.hy_am/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.hy_am/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.hy_am/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: hy_am\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.id_id/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.id_id/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.id_id/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.id_id/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,26 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2021-11-18 08:13+0000\n" +"Last-Translator: Nao3Line Prez \n" +"Language-Team: Indonesian \n" +"Language: id_id\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.9\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "Game Musik Emu Audio Decoder" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "Format Game Music Emu (GME) digunakan untuk meniru output audio dari berbagai konsol video game yang populer di tahun 1980-an dan 1990-an. Ini memberikan nuansa \"retro\" pada suara.[CR][CR][B]Catatan:[/B][CR]Tidak semua format file memberikan panjang dan dalam hal ini diatur ke 2,5 menit.[CR][][CR] CR][B]Format yang Didukung:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/sistem Z80 lainnya (tanpa suara FM)[CR]- NSF/NSFE: Nintendo NES/Famicom (dengan suara VRC 6, Namco 106, dan FME-7) [CR]- SAP: Sistem Atari menggunakan chip suara POKEY[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.is_is/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.is_is/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.is_is/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.is_is/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: is_is\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n % 10 != 1 || n % 100 == 11;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.it_it/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.it_it/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.it_it/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.it_it/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it_it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ja_jp/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ja_jp/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ja_jp/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ja_jp/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ja_jp\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.kn_in/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.kn_in/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.kn_in/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.kn_in/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: kn_in\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ko_kr/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ko_kr/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ko_kr/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ko_kr/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,26 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2021-10-03 11:47+0000\n" +"Last-Translator: Minho Park \n" +"Language-Team: Korean \n" +"Language: ko_kr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.8\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "Game Music Emu 오디오 디코더" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "GME(Game Music Emu) 형식은 1980년대와 1990년대에 유행했던 다양한 비디오 게임 콘솔의 오디오 출력을 에뮬레이트하는 데 사용됩니다. 사운드에 \"복고풍\" 느낌을 줍니다.[CR][CR][B]참고:[/B][CR]일부 파일 형식은 길이를 제공하지 않으며 이 경우에는 2.5분으로 설정됩니다.[CR][ CR][B]지원되는 형식:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC 엔진[CR]- KSS: MSX 가정용 컴퓨터/기타 Z80 시스템(FM 사운드 없음)[CR]- NSF/NSFE: Nintendo NES/Famicom(VRC 6, Namco 106 및 FME-7 사운드 포함) [CR]- SAP: POKEY 사운드 칩을 사용하는 Atari 시스템[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.lt_lt/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.lt_lt/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.lt_lt/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.lt_lt/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: lt_lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > 19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? 1 : 2);\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.lv_lv/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.lv_lv/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.lv_lv/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.lv_lv/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: lv_lv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n % 10 == 0 || n % 100 >= 11 && n % 100 <= 19) ? 0 : ((n % 10 == 1 && n % 100 != 11) ? 1 : 2);\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.mi/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.mi/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.mi/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.mi/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: mi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.mk_mk/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.mk_mk/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.mk_mk/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.mk_mk/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: mk_mk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n==1 || n%10==1 ? 0 : 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ml_in/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ml_in/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ml_in/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ml_in/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ml_in\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.mn_mn/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.mn_mn/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.mn_mn/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.mn_mn/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: mn_mn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ms_my/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ms_my/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ms_my/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ms_my/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ms_my\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.mt_mt/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.mt_mt/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.mt_mt/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.mt_mt/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: mt_mt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.my_mm/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.my_mm/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.my_mm/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.my_mm/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: my_mm\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.nb_no/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.nb_no/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.nb_no/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.nb_no/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: nb_no\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.nl_nl/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.nl_nl/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.nl_nl/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.nl_nl/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: nl_nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.oc_fr/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.oc_fr/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.oc_fr/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.oc_fr/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: oc_fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.os_os/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.os_os/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.os_os/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.os_os/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: os_os\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.pl_pl/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.pl_pl/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.pl_pl/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.pl_pl/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: pl_pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.pt_br/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.pt_br/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.pt_br/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.pt_br/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: pt_br\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.pt_pt/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.pt_pt/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.pt_pt/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.pt_pt/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: pt_pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ro_ro/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ro_ro/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ro_ro/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ro_ro/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ro_ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ru_ru/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ru_ru/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ru_ru/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ru_ru/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,26 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2021-10-03 11:47+0000\n" +"Last-Translator: vdkbsd \n" +"Language-Team: Russian \n" +"Language: ru_ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.8\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "Аудиодекодер Game Music Emu" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "Формат Game Music Emu (GME) используется для эмуляции аудиовыхода различных игровых приставок, популярных в 1980-х и 1990-х годах. Он придает звуку ощущение \"ретро\".[CR][CR][B]Примечание:[/B][CR]Не все форматы файлов указывают длину, в данном случае она установлена на 2,5 минуты. [CR][CR][B]Поддерживаемые форматы:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/другие Z80 системы (без FM звука)[CR]- NSF/NSFE: Nintendo NES/Famicom (со звуком VRC 6, Namco 106 и FME-7)[CR]- SAP: Системы Atari, использующие звуковой чип POKEY[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.si_lk/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.si_lk/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.si_lk/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.si_lk/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: si_lk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sk_sk/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sk_sk/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sk_sk/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sk_sk/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: sk_sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sl_si/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sl_si/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sl_si/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sl_si/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: sl_si\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sq_al/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sq_al/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sq_al/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sq_al/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: sq_al\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sr_rs/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sr_rs/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sr_rs/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sr_rs/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: sr_rs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sr_rs@latin/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sr_rs@latin/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sr_rs@latin/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sr_rs@latin/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: sr_Latn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sv_se/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sv_se/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.sv_se/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.sv_se/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: sv_se\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.szl/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.szl/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.szl/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.szl/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: szl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ta_in/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ta_in/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.ta_in/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.ta_in/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ta_in\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.te_in/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.te_in/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.te_in/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.te_in/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: te_in\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.tg_tj/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.tg_tj/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.tg_tj/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.tg_tj/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: tg_tj\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.th_th/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.th_th/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.th_th/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.th_th/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: th_th\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.tr_tr/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.tr_tr/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.tr_tr/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.tr_tr/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: tr_tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.uk_ua/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.uk_ua/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.uk_ua/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.uk_ua/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: uk_ua\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.uz_uz/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.uz_uz/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.uz_uz/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.uz_uz/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: uz_uz\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.vi_vn/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.vi_vn/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.vi_vn/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.vi_vn/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: vi_vn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.zh_cn/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.zh_cn/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.zh_cn/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.zh_cn/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,26 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2021-10-03 11:47+0000\n" +"Last-Translator: taxigps \n" +"Language-Team: Chinese (China) \n" +"Language: zh_cn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.8\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "游戏音乐 Emu 音频解码器" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "游戏音乐 Emu(GME)格式用于模拟20世纪80年代和90年代流行的各种视频游戏机的音频输出。它给声音一种“复古”的感觉。[CR][CR][B]注:[/B][CR]并非所有文件格式都给出时长,在这种情况下,它被设置为2.5分钟。[CR][CR][B]支持的格式:[/B][CR]- AY:ZX Spectrum/Amstrad CPC[CR]- GBS:任天堂 Game Boy[CR]- GYM:世嘉 Genesis/Mega Drive[CR]- HES:NEC TurboGrafx-16/PC Engine[CR]- KSS:MSX 家用电脑/其他Z80系统(无FM声音)[CR]- NSF/NSFE:任天堂 NES/Famicom(带有VRC 6、Namco 106 和 FME-7 声音)[CR]- SAP:雅达利系统使用 POKEY sound 芯片[CR]- SPC:超级任天堂/Super Famicom[CR]- VGM/VGZ:世嘉 Master System/Mark III、世嘉Genesis/Mega Drive、BBC Micro" diff -Nru kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.zh_tw/strings.po kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.zh_tw/strings.po --- kodi-audiodecoder-gme-2.0.3/audiodecoder.gme/resources/language/resource.language.zh_tw/strings.po 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/audiodecoder.gme/resources/language/resource.language.zh_tw/strings.po 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,25 @@ +# Kodi Media Center language file +# Addon Name: GME Audio Decoder +# Addon id: audiodecoder.gme +# Addon Provider: Team Kodi +msgid "" +msgstr "" +"Project-Id-Version: KODI Main\n" +"Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh_tw\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +msgctxt "Addon Summary" +msgid "Game Music Emu Audio Decoder" +msgstr "" + +msgctxt "Addon Description" +msgid "Game Music Emu (GME) format is used to emulate the audio output of various video game consoles popular in the 1980s and 1990s. It gives a \"retro\" feel to the sound.[CR][CR][B]Note:[/B][CR]Not all file formats give length and in this case it is set to 2.5 minutes.[CR][CR][B]Supported Formats:[/B][CR]- AY: ZX Spectrum/Amstrad CPC[CR]- GBS: Nintendo Game Boy[CR]- GYM: Sega Genesis/Mega Drive[CR]- HES: NEC TurboGrafx-16/PC Engine[CR]- KSS: MSX Home Computer/other Z80 systems (no FM sound)[CR]- NSF/NSFE: Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)[CR]- SAP: Atari systems using POKEY sound chip[CR]- SPC: Super Nintendo/Super Famicom[CR]- VGM/VGZ: Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro" +msgstr "" diff -Nru kodi-audiodecoder-gme-2.0.3/azure-pipelines.yml kodi-audiodecoder-gme-19.0.3/azure-pipelines.yml --- kodi-audiodecoder-gme-2.0.3/azure-pipelines.yml 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/azure-pipelines.yml 2013-05-31 22:59:22.000000000 +0000 @@ -4,7 +4,7 @@ trigger: branches: include: - - Leia + - Matrix - releases/* paths: include: @@ -16,25 +16,25 @@ - job: Windows pool: - vmImage: 'VS2017-Win2016' + vmImage: 'windows-2022' strategy: matrix: Win32: - GENERATOR: "Visual Studio 15 2017" + GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: Win32 CONFIGURATION: Release Win64: - GENERATOR: "Visual Studio 15 2017" + GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: x64 CONFIGURATION: Release Win64-UWP: - GENERATOR: "Visual Studio 15 2017" + GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: x64 CONFIGURATION: Release WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" ARM64-UWP: - GENERATOR: "Visual Studio 15 2017" + GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: ARM64 CONFIGURATION: Release WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" @@ -46,7 +46,7 @@ - script: | cd .. - git clone --branch Leia --depth=1 https://github.com/xbmc/xbmc.git kodi + git clone --branch Matrix --depth=1 https://github.com/xbmc/xbmc.git kodi cd $(Build.SourcesDirectory) mkdir build cd build diff -Nru kodi-audiodecoder-gme-2.0.3/.clang-format kodi-audiodecoder-gme-19.0.3/.clang-format --- kodi-audiodecoder-gme-2.0.3/.clang-format 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/.clang-format 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,88 @@ +--- +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: DontAlign +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^<[a-z0-9_]+>$' + Priority: 3 + - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|iso646|limits|locale|math|setjmp|signal|stdalign|stdarg|stdatomic|stdbool|stddef|stdint|stdio|stdlib|stdnoreturn|string|tgmath|threads|time|uchar|wchar|wctype)\.h>$' + Priority: 3 + - Regex: '^<' + Priority: 3 + - Regex: '^["<](kodi|p8-platform)\/.*\.h[">]$' + Priority: 2 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '$' +IndentCaseLabels: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60000 +PointerAlignment: Left +ReflowComments: false +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... diff -Nru kodi-audiodecoder-gme-2.0.3/CMakeLists.txt kodi-audiodecoder-gme-19.0.3/CMakeLists.txt --- kodi-audiodecoder-gme-2.0.3/CMakeLists.txt 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/CMakeLists.txt 2013-05-31 22:59:22.000000000 +0000 @@ -13,6 +13,7 @@ add_subdirectory(lib/Game_Music_Emu) set(GME_SOURCES src/GMECodec.cpp) +set(GME_HEADERS src/GMECodec.h) set(DEPLIBS gme fileex) diff -Nru kodi-audiodecoder-gme-2.0.3/debian/changelog kodi-audiodecoder-gme-19.0.3/debian/changelog --- kodi-audiodecoder-gme-2.0.3/debian/changelog 2013-05-31 22:59:22.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/debian/changelog 2013-05-31 22:59:22.000000000 +0000 @@ -1,4 +1,4 @@ -kodi-audiodecoder-gme (2.0.3-1~focal) focal; urgency=low +kodi-audiodecoder-gme (6:19.0.3-1~focal) focal; urgency=low [ kodi ] * autogenerated dummy changelog diff -Nru kodi-audiodecoder-gme-2.0.3/debian/control kodi-audiodecoder-gme-19.0.3/debian/control --- kodi-audiodecoder-gme-2.0.3/debian/control 2013-05-31 22:59:22.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/debian/control 2013-05-31 22:59:22.000000000 +0000 @@ -4,7 +4,7 @@ Build-Depends: debhelper (>= 9.0.0), cmake, kodi-addon-dev Standards-Version: 4.1.2 Section: libs -Homepage: http://kodi.tv +Homepage: https://kodi.tv Package: kodi-audiodecoder-gme Section: libs diff -Nru kodi-audiodecoder-gme-2.0.3/debian/copyright kodi-audiodecoder-gme-19.0.3/debian/copyright --- kodi-audiodecoder-gme-2.0.3/debian/copyright 2013-05-31 22:59:22.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/debian/copyright 2013-05-31 22:59:22.000000000 +0000 @@ -3,7 +3,7 @@ Source: https://github.com/xbmc/audiodecoder.gme Files: * -Copyright: 2005-2020 Team Kodi +Copyright: 2005-2022 Team Kodi License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff -Nru kodi-audiodecoder-gme-2.0.3/debian/rules kodi-audiodecoder-gme-19.0.3/debian/rules --- kodi-audiodecoder-gme-2.0.3/debian/rules 2013-05-31 22:59:22.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/debian/rules 2013-05-31 22:59:22.000000000 +0000 @@ -10,13 +10,10 @@ #export DH_VERBOSE=1 %: - dh $@ + dh $@ override_dh_auto_configure: - dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 -DUSE_LTO=1 - -override_dh_strip: - dh_strip --dbg-package=kodi-audiodecoder-gme-dbg + dh_auto_configure -- -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=1 -DUSE_LTO=1 override_dh_installdocs: dh_installdocs --link-doc=kodi-audiodecoder-gme diff -Nru kodi-audiodecoder-gme-2.0.3/debian/source/format kodi-audiodecoder-gme-19.0.3/debian/source/format --- kodi-audiodecoder-gme-2.0.3/debian/source/format 2013-05-31 22:59:22.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/debian/source/format 2013-05-31 22:59:22.000000000 +0000 @@ -1 +1 @@ -3.0 (quilt) +3.0 (native) diff -Nru kodi-audiodecoder-gme-2.0.3/.github/workflows/build.yml kodi-audiodecoder-gme-19.0.3/.github/workflows/build.yml --- kodi-audiodecoder-gme-2.0.3/.github/workflows/build.yml 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/.github/workflows/build.yml 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,61 @@ +name: Build and run tests +on: [push, pull_request] +env: + app_id: audiodecoder.gme + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - name: "Debian package test" + os: ubuntu-20.04 + CC: gcc + CXX: g++ + DEBIAN_BUILD: true + #- os: ubuntu-20.04 + #CC: gcc + #CXX: g++ + #- os: ubuntu-20.04 + #CC: clang + #CXX: clang++ + #- os: macos-11 + steps: + - name: Install needed ubuntu depends + env: + DEBIAN_BUILD: ${{ matrix.DEBIAN_BUILD }} + run: | + if [[ $DEBIAN_BUILD == true ]]; then sudo add-apt-repository -y ppa:team-xbmc/ppa; fi + if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get update; fi + if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get install fakeroot; fi + - name: Checkout Kodi repo + uses: actions/checkout@v2 + with: + repository: xbmc/xbmc + ref: Matrix + path: xbmc + - name: Checkout audiodecoder.gme repo + uses: actions/checkout@v2 + with: + path: ${{ env.app_id }} + - name: Configure + env: + CC: ${{ matrix.CC }} + CXX: ${{ matrix.CXX }} + DEBIAN_BUILD: ${{ matrix.DEBIAN_BUILD }} + run: | + if [[ $DEBIAN_BUILD != true ]]; then cd ${app_id} && mkdir -p build && cd build; fi + if [[ $DEBIAN_BUILD != true ]]; then cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=${{ github.workspace }} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/xbmc/addons -DPACKAGE_ZIP=1 ${{ github.workspace }}/xbmc/cmake/addons; fi + if [[ $DEBIAN_BUILD == true ]]; then wget https://raw.githubusercontent.com/xbmc/xbmc/Matrix/xbmc/addons/kodi-dev-kit/tools/debian-addon-package-test.sh && chmod +x ./debian-addon-package-test.sh; fi + if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get build-dep ${{ github.workspace }}/${app_id}; fi + - name: Build + env: + CC: ${{ matrix.CC }} + CXX: ${{ matrix.CXX }} + DEBIAN_BUILD: ${{ matrix.DEBIAN_BUILD }} + run: | + if [[ $DEBIAN_BUILD != true ]]; then cd ${app_id}/build; fi + if [[ $DEBIAN_BUILD != true ]]; then make; fi + if [[ $DEBIAN_BUILD == true ]]; then ./debian-addon-package-test.sh ${{ github.workspace }}/${app_id}; fi diff -Nru kodi-audiodecoder-gme-2.0.3/.github/workflows/sync-addon-metadata-translations.yml kodi-audiodecoder-gme-19.0.3/.github/workflows/sync-addon-metadata-translations.yml --- kodi-audiodecoder-gme-2.0.3/.github/workflows/sync-addon-metadata-translations.yml 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/.github/workflows/sync-addon-metadata-translations.yml 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,46 @@ +name: Sync addon metadata translations + +on: + push: + branches: [ Matrix, Nexus ] + paths: + - '**addon.xml' + - '**resource.language.**strings.po' + +jobs: + default: + if: github.repository == 'xbmc/audiodecoder.gme' + runs-on: ubuntu-latest + + steps: + + - name: Checkout repository + uses: actions/checkout@v2 + with: + path: project + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install git+https://github.com/xbmc/sync_addon_metadata_translations.git + + - name: Run sync-addon-metadata-translations + run: | + sync-addon-metadata-translations + working-directory: ./project + + - name: Create PR for sync-addon-metadata-translations changes + uses: peter-evans/create-pull-request@v3.10.0 + with: + commit-message: Sync of addon metadata translations + title: Sync of addon metadata translations + body: Sync of addon metadata translations triggered by ${{ github.sha }} + branch: amt-sync + delete-branch: true + path: ./project + reviewers: gade01 diff -Nru kodi-audiodecoder-gme-2.0.3/Jenkinsfile kodi-audiodecoder-gme-19.0.3/Jenkinsfile --- kodi-audiodecoder-gme-2.0.3/Jenkinsfile 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/Jenkinsfile 2013-05-31 22:59:22.000000000 +0000 @@ -1 +1 @@ -buildPlugin(version: "Leia") +buildPlugin(version: "Matrix") diff -Nru kodi-audiodecoder-gme-2.0.3/lib/File_Extractor/win32/File_Extractor/.gitignore kodi-audiodecoder-gme-19.0.3/lib/File_Extractor/win32/File_Extractor/.gitignore --- kodi-audiodecoder-gme-2.0.3/lib/File_Extractor/win32/File_Extractor/.gitignore 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/File_Extractor/win32/File_Extractor/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -*.user -Debug -Release \ No newline at end of file diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ay_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ay_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ay_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ay_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,357 +1,357 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Ay_Emu.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2006-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// TODO: probably don't need detailed errors as to why file is corrupt - -int const spectrum_clock = 3546900; // 128K Spectrum -int const spectrum_period = 70908; - -//int const spectrum_clock = 3500000; // 48K Spectrum -//int const spectrum_period = 69888; - -int const cpc_clock = 2000000; - -Ay_Emu::Ay_Emu() -{ - core.set_cpc_callback( enable_cpc_, this ); - set_type( gme_ay_type ); - set_silence_lookahead( 6 ); -} - -Ay_Emu::~Ay_Emu() { } - -// Track info - -// Given pointer to 2-byte offset of data, returns pointer to data, or NULL if -// offset is 0 or there is less than min_size bytes of data available. -static byte const* get_data( Ay_Emu::file_t const& file, byte const ptr [], int min_size ) -{ - int offset = (BOOST::int16_t) get_be16( ptr ); - int pos = ptr - (byte const*) file.header; - int size = file.end - (byte const*) file.header; - assert( (unsigned) pos <= (unsigned) size - 2 ); - int limit = size - min_size; - if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit ) - return NULL; - return ptr + offset; -} - -static blargg_err_t parse_header( byte const in [], int size, Ay_Emu::file_t* out ) -{ - typedef Ay_Emu::header_t header_t; - if ( size < header_t::size ) - return blargg_err_file_type; - - out->header = (header_t const*) in; - out->end = in + size; - header_t const& h = *(header_t const*) in; - if ( memcmp( h.tag, "ZXAYEMUL", 8 ) ) - return blargg_err_file_type; - - out->tracks = get_data( *out, h.track_info, (h.max_track + 1) * 4 ); - if ( !out->tracks ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "missing track data" ); - - return blargg_ok; -} - -static void copy_ay_fields( Ay_Emu::file_t const& file, track_info_t* out, int track ) -{ - Gme_File::copy_field_( out->song, (char const*) get_data( file, file.tracks + track * 4, 1 ) ); - byte const* track_info = get_data( file, file.tracks + track * 4 + 2, 6 ); - if ( track_info ) - out->length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec - - Gme_File::copy_field_( out->author, (char const*) get_data( file, file.header->author, 1 ) ); - Gme_File::copy_field_( out->comment, (char const*) get_data( file, file.header->comment, 1 ) ); -} - -static void hash_ay_file( Ay_Emu::file_t const& file, Gme_Info_::Hash_Function& out ) -{ - out.hash_( &file.header->vers, sizeof(file.header->vers) ); - out.hash_( &file.header->player, sizeof(file.header->player) ); - out.hash_( &file.header->unused[0], sizeof(file.header->unused) ); - out.hash_( &file.header->max_track, sizeof(file.header->max_track) ); - out.hash_( &file.header->first_track, sizeof(file.header->first_track) ); - - for ( unsigned i = 0; i <= file.header->max_track; i++ ) - { - byte const* track_info = get_data( file, file.tracks + i * 4 + 2, 14 ); - if ( track_info ) - { - out.hash_( track_info + 8, 2 ); - byte const* points = get_data( file, track_info + 10, 6 ); - if ( points ) out.hash_( points, 6 ); - - byte const* blocks = get_data( file, track_info + 12, 8 ); - if ( blocks ) - { - int addr = get_be16( blocks ); - - while ( addr ) - { - out.hash_( blocks, 4 ); - - int len = get_be16( blocks + 2 ); - - byte const* block = get_data( file, blocks + 4, len ); - if ( block ) out.hash_( block, len ); - - blocks += 6; - addr = get_be16( blocks ); - } - } - } - } -} - -blargg_err_t Ay_Emu::track_info_( track_info_t* out, int track ) const -{ - copy_ay_fields( file, out, track ); - return blargg_ok; -} - -struct Ay_File : Gme_Info_ -{ - Ay_Emu::file_t file; - - Ay_File() { set_type( gme_ay_type ); } - - blargg_err_t load_mem_( byte const begin [], int size ) - { - RETURN_ERR( parse_header( begin, size, &file ) ); - set_track_count( file.header->max_track + 1 ); - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int track ) const - { - copy_ay_fields( file, out, track ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_ay_file( file, out ); - return blargg_ok; - } -}; - -static Music_Emu* new_ay_emu () -{ - return BLARGG_NEW Ay_Emu; -} - -static Music_Emu* new_ay_file() -{ - return BLARGG_NEW Ay_File; -} - -gme_type_t_ const gme_ay_type [1] = {{ - "ZX Spectrum", - 0, - &new_ay_emu, - &new_ay_file, - "AY", - 1 -}}; - -// Setup - -blargg_err_t Ay_Emu::load_mem_( byte const in [], int size ) -{ - assert( offsetof (header_t,track_info [2]) == header_t::size ); - - RETURN_ERR( parse_header( in, size, &file ) ); - set_track_count( file.header->max_track + 1 ); - - if ( file.header->vers > 2 ) - set_warning( "Unknown file version" ); - - int const osc_count = Ay_Apu::osc_count + 1; // +1 for beeper - - set_voice_count( osc_count ); - core.apu().volume( gain() ); - - static const char* const names [osc_count] = { - "Wave 1", "Wave 2", "Wave 3", "Beeper" - }; - set_voice_names( names ); - - static int const types [osc_count] = { - wave_type+0, wave_type+1, wave_type+2, mixed_type+1 - }; - set_voice_types( types ); - - return setup_buffer( spectrum_clock ); -} - -void Ay_Emu::update_eq( blip_eq_t const& eq ) -{ - core.apu().treble_eq( eq ); -} - -void Ay_Emu::set_voice( int i, Blip_Buffer* center, Blip_Buffer*, Blip_Buffer* ) -{ - if ( i >= Ay_Apu::osc_count ) - core.set_beeper_output( center ); - else - core.apu().set_output( i, center ); -} - -void Ay_Emu::set_tempo_( double t ) -{ - int p = spectrum_period; - if ( clock_rate() != spectrum_clock ) - p = clock_rate() / 50; - - core.set_play_period( blip_time_t (p / t) ); -} - -blargg_err_t Ay_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - byte* const mem = core.mem(); - - memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET - memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 ); - memset( mem + core.ram_addr, 0x00, core.mem_size - core.ram_addr ); - - // locate data blocks - byte const* const data = get_data( file, file.tracks + track * 4 + 2, 14 ); - if ( !data ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); - - byte const* const more_data = get_data( file, data + 10, 6 ); - if ( !more_data ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); - - byte const* blocks = get_data( file, data + 12, 8 ); - if ( !blocks ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); - - // initial addresses - unsigned addr = get_be16( blocks ); - if ( !addr ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); - - unsigned init = get_be16( more_data + 2 ); - if ( !init ) - init = addr; - - // copy blocks into memory - do - { - blocks += 2; - unsigned len = get_be16( blocks ); blocks += 2; - if ( addr + len > core.mem_size ) - { - set_warning( "Bad data block size" ); - len = core.mem_size - addr; - } - check( len ); - byte const* in = get_data( file, blocks, 0 ); blocks += 2; - if ( len > (unsigned) (file.end - in) ) - { - set_warning( "File data missing" ); - len = file.end - in; - } - //dprintf( "addr: $%04X, len: $%04X\n", addr, len ); - if ( addr < core.ram_addr && addr >= 0x400 ) // several tracks use low data - dprintf( "Block addr in ROM\n" ); - memcpy( mem + addr, in, len ); - - if ( file.end - blocks < 8 ) - { - set_warning( "File data missing" ); - break; - } - } - while ( (addr = get_be16( blocks )) != 0 ); - - // copy and configure driver - static byte const passive [] = { - 0xF3, // DI - 0xCD, 0, 0, // CALL init - 0xED, 0x5E, // LOOP: IM 2 - 0xFB, // EI - 0x76, // HALT - 0x18, 0xFA // JR LOOP - }; - static byte const active [] = { - 0xF3, // DI - 0xCD, 0, 0, // CALL init - 0xED, 0x56, // LOOP: IM 1 - 0xFB, // EI - 0x76, // HALT - 0xCD, 0, 0, // CALL play - 0x18, 0xF7 // JR LOOP - }; - memcpy( mem, passive, sizeof passive ); - int const play_addr = get_be16( more_data + 4 ); - if ( play_addr ) - { - memcpy( mem, active, sizeof active ); - mem [ 9] = play_addr; - mem [10] = play_addr >> 8; - } - mem [2] = init; - mem [3] = init >> 8; - - mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET) - - // start at spectrum speed - change_clock_rate( spectrum_clock ); - set_tempo( tempo() ); - - Ay_Core::registers_t r = { }; - r.sp = get_be16( more_data ); - r.b.a = r.b.b = r.b.d = r.b.h = data [8]; - r.b.flags = r.b.c = r.b.e = r.b.l = data [9]; - r.alt.w = r.w; - r.ix = r.iy = r.w.hl; - - core.start_track( r, play_addr ); - - return blargg_ok; -} - -blargg_err_t Ay_Emu::run_clocks( blip_time_t& duration, int ) -{ - core.end_frame( &duration ); - return blargg_ok; -} - -inline void Ay_Emu::enable_cpc() -{ - change_clock_rate( cpc_clock ); - set_tempo( tempo() ); -} - -void Ay_Emu::enable_cpc_( void* data ) -{ - STATIC_CAST(Ay_Emu*,data)->enable_cpc(); -} - -blargg_err_t Ay_Emu::hash_( Hash_Function& out ) const -{ - hash_ay_file( file, out ); - return blargg_ok; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Ay_Emu.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2006-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// TODO: probably don't need detailed errors as to why file is corrupt + +int const spectrum_clock = 3546900; // 128K Spectrum +int const spectrum_period = 70908; + +//int const spectrum_clock = 3500000; // 48K Spectrum +//int const spectrum_period = 69888; + +int const cpc_clock = 2000000; + +Ay_Emu::Ay_Emu() +{ + core.set_cpc_callback( enable_cpc_, this ); + set_type( gme_ay_type ); + set_silence_lookahead( 6 ); +} + +Ay_Emu::~Ay_Emu() { } + +// Track info + +// Given pointer to 2-byte offset of data, returns pointer to data, or NULL if +// offset is 0 or there is less than min_size bytes of data available. +static byte const* get_data( Ay_Emu::file_t const& file, byte const ptr [], int min_size ) +{ + int offset = (BOOST::int16_t) get_be16( ptr ); + int pos = ptr - (byte const*) file.header; + int size = file.end - (byte const*) file.header; + assert( (unsigned) pos <= (unsigned) size - 2 ); + int limit = size - min_size; + if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit ) + return NULL; + return ptr + offset; +} + +static blargg_err_t parse_header( byte const in [], int size, Ay_Emu::file_t* out ) +{ + typedef Ay_Emu::header_t header_t; + if ( size < header_t::size ) + return blargg_err_file_type; + + out->header = (header_t const*) in; + out->end = in + size; + header_t const& h = *(header_t const*) in; + if ( memcmp( h.tag, "ZXAYEMUL", 8 ) ) + return blargg_err_file_type; + + out->tracks = get_data( *out, h.track_info, (h.max_track + 1) * 4 ); + if ( !out->tracks ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "missing track data" ); + + return blargg_ok; +} + +static void copy_ay_fields( Ay_Emu::file_t const& file, track_info_t* out, int track ) +{ + Gme_File::copy_field_( out->song, (char const*) get_data( file, file.tracks + track * 4, 1 ) ); + byte const* track_info = get_data( file, file.tracks + track * 4 + 2, 6 ); + if ( track_info ) + out->length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec + + Gme_File::copy_field_( out->author, (char const*) get_data( file, file.header->author, 1 ) ); + Gme_File::copy_field_( out->comment, (char const*) get_data( file, file.header->comment, 1 ) ); +} + +static void hash_ay_file( Ay_Emu::file_t const& file, Gme_Info_::Hash_Function& out ) +{ + out.hash_( &file.header->vers, sizeof(file.header->vers) ); + out.hash_( &file.header->player, sizeof(file.header->player) ); + out.hash_( &file.header->unused[0], sizeof(file.header->unused) ); + out.hash_( &file.header->max_track, sizeof(file.header->max_track) ); + out.hash_( &file.header->first_track, sizeof(file.header->first_track) ); + + for ( unsigned i = 0; i <= file.header->max_track; i++ ) + { + byte const* track_info = get_data( file, file.tracks + i * 4 + 2, 14 ); + if ( track_info ) + { + out.hash_( track_info + 8, 2 ); + byte const* points = get_data( file, track_info + 10, 6 ); + if ( points ) out.hash_( points, 6 ); + + byte const* blocks = get_data( file, track_info + 12, 8 ); + if ( blocks ) + { + int addr = get_be16( blocks ); + + while ( addr ) + { + out.hash_( blocks, 4 ); + + int len = get_be16( blocks + 2 ); + + byte const* block = get_data( file, blocks + 4, len ); + if ( block ) out.hash_( block, len ); + + blocks += 6; + addr = get_be16( blocks ); + } + } + } + } +} + +blargg_err_t Ay_Emu::track_info_( track_info_t* out, int track ) const +{ + copy_ay_fields( file, out, track ); + return blargg_ok; +} + +struct Ay_File : Gme_Info_ +{ + Ay_Emu::file_t file; + + Ay_File() { set_type( gme_ay_type ); } + + blargg_err_t load_mem_( byte const begin [], int size ) + { + RETURN_ERR( parse_header( begin, size, &file ) ); + set_track_count( file.header->max_track + 1 ); + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int track ) const + { + copy_ay_fields( file, out, track ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_ay_file( file, out ); + return blargg_ok; + } +}; + +static Music_Emu* new_ay_emu () +{ + return BLARGG_NEW Ay_Emu; +} + +static Music_Emu* new_ay_file() +{ + return BLARGG_NEW Ay_File; +} + +gme_type_t_ const gme_ay_type [1] = {{ + "ZX Spectrum", + 0, + &new_ay_emu, + &new_ay_file, + "AY", + 1 +}}; + +// Setup + +blargg_err_t Ay_Emu::load_mem_( byte const in [], int size ) +{ + assert( offsetof (header_t,track_info [2]) == header_t::size ); + + RETURN_ERR( parse_header( in, size, &file ) ); + set_track_count( file.header->max_track + 1 ); + + if ( file.header->vers > 2 ) + set_warning( "Unknown file version" ); + + int const osc_count = Ay_Apu::osc_count + 1; // +1 for beeper + + set_voice_count( osc_count ); + core.apu().volume( gain() ); + + static const char* const names [osc_count] = { + "Wave 1", "Wave 2", "Wave 3", "Beeper" + }; + set_voice_names( names ); + + static int const types [osc_count] = { + wave_type+0, wave_type+1, wave_type+2, mixed_type+1 + }; + set_voice_types( types ); + + return setup_buffer( spectrum_clock ); +} + +void Ay_Emu::update_eq( blip_eq_t const& eq ) +{ + core.apu().treble_eq( eq ); +} + +void Ay_Emu::set_voice( int i, Blip_Buffer* center, Blip_Buffer*, Blip_Buffer* ) +{ + if ( i >= Ay_Apu::osc_count ) + core.set_beeper_output( center ); + else + core.apu().set_output( i, center ); +} + +void Ay_Emu::set_tempo_( double t ) +{ + int p = spectrum_period; + if ( clock_rate() != spectrum_clock ) + p = clock_rate() / 50; + + core.set_play_period( blip_time_t (p / t) ); +} + +blargg_err_t Ay_Emu::start_track_( int track ) +{ + RETURN_ERR( Classic_Emu::start_track_( track ) ); + + byte* const mem = core.mem(); + + memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET + memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 ); + memset( mem + core.ram_addr, 0x00, core.mem_size - core.ram_addr ); + + // locate data blocks + byte const* const data = get_data( file, file.tracks + track * 4 + 2, 14 ); + if ( !data ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); + + byte const* const more_data = get_data( file, data + 10, 6 ); + if ( !more_data ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); + + byte const* blocks = get_data( file, data + 12, 8 ); + if ( !blocks ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); + + // initial addresses + unsigned addr = get_be16( blocks ); + if ( !addr ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); + + unsigned init = get_be16( more_data + 2 ); + if ( !init ) + init = addr; + + // copy blocks into memory + do + { + blocks += 2; + unsigned len = get_be16( blocks ); blocks += 2; + if ( addr + len > core.mem_size ) + { + set_warning( "Bad data block size" ); + len = core.mem_size - addr; + } + check( len ); + byte const* in = get_data( file, blocks, 0 ); blocks += 2; + if ( len > (unsigned) (file.end - in) ) + { + set_warning( "File data missing" ); + len = file.end - in; + } + //dprintf( "addr: $%04X, len: $%04X\n", addr, len ); + if ( addr < core.ram_addr && addr >= 0x400 ) // several tracks use low data + dprintf( "Block addr in ROM\n" ); + memcpy( mem + addr, in, len ); + + if ( file.end - blocks < 8 ) + { + set_warning( "File data missing" ); + break; + } + } + while ( (addr = get_be16( blocks )) != 0 ); + + // copy and configure driver + static byte const passive [] = { + 0xF3, // DI + 0xCD, 0, 0, // CALL init + 0xED, 0x5E, // LOOP: IM 2 + 0xFB, // EI + 0x76, // HALT + 0x18, 0xFA // JR LOOP + }; + static byte const active [] = { + 0xF3, // DI + 0xCD, 0, 0, // CALL init + 0xED, 0x56, // LOOP: IM 1 + 0xFB, // EI + 0x76, // HALT + 0xCD, 0, 0, // CALL play + 0x18, 0xF7 // JR LOOP + }; + memcpy( mem, passive, sizeof passive ); + int const play_addr = get_be16( more_data + 4 ); + if ( play_addr ) + { + memcpy( mem, active, sizeof active ); + mem [ 9] = play_addr; + mem [10] = play_addr >> 8; + } + mem [2] = init; + mem [3] = init >> 8; + + mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET) + + // start at spectrum speed + change_clock_rate( spectrum_clock ); + set_tempo( tempo() ); + + Ay_Core::registers_t r = { }; + r.sp = get_be16( more_data ); + r.b.a = r.b.b = r.b.d = r.b.h = data [8]; + r.b.flags = r.b.c = r.b.e = r.b.l = data [9]; + r.alt.w = r.w; + r.ix = r.iy = r.w.hl; + + core.start_track( r, play_addr ); + + return blargg_ok; +} + +blargg_err_t Ay_Emu::run_clocks( blip_time_t& duration, int ) +{ + core.end_frame( &duration ); + return blargg_ok; +} + +inline void Ay_Emu::enable_cpc() +{ + change_clock_rate( cpc_clock ); + set_tempo( tempo() ); +} + +void Ay_Emu::enable_cpc_( void* data ) +{ + STATIC_CAST(Ay_Emu*,data)->enable_cpc(); +} + +blargg_err_t Ay_Emu::hash_( Hash_Function& out ) const +{ + hash_ay_file( file, out ); + return blargg_ok; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_common.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_common.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_common.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_common.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,58 +1,58 @@ -// $package. http://www.slack.net/~ant/ - -#include "blargg_common.h" - -/* Copyright (C) 2008-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -BLARGG_NAMESPACE_BEGIN - -// defined here to avoid need for blargg_errors.cpp in simple programs -blargg_err_def_t blargg_err_memory = BLARGG_ERR_MEMORY; - -void blargg_vector_::init() -{ - begin_ = NULL; - size_ = 0; -} - -void blargg_vector_::clear() -{ - void* p = begin_; - begin_ = NULL; - size_ = 0; - free( p ); -} - -blargg_err_t blargg_vector_::resize_( size_t n, size_t elem_size ) -{ - if ( n != size_ ) - { - if ( n == 0 ) - { - // Simpler to handle explicitly. Realloc will handle a size of 0, - // but then we have to avoid raising an error for a NULL return. - clear(); - } - else - { - void* p = realloc( begin_, n * elem_size ); - CHECK_ALLOC( p ); - begin_ = p; - size_ = n; - } - } - return blargg_ok; -} - -BLARGG_NAMESPACE_END +// $package. http://www.slack.net/~ant/ + +#include "blargg_common.h" + +/* Copyright (C) 2008-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +BLARGG_NAMESPACE_BEGIN + +// defined here to avoid need for blargg_errors.cpp in simple programs +blargg_err_def_t blargg_err_memory = BLARGG_ERR_MEMORY; + +void blargg_vector_::init() +{ + begin_ = NULL; + size_ = 0; +} + +void blargg_vector_::clear() +{ + void* p = begin_; + begin_ = NULL; + size_ = 0; + free( p ); +} + +blargg_err_t blargg_vector_::resize_( size_t n, size_t elem_size ) +{ + if ( n != size_ ) + { + if ( n == 0 ) + { + // Simpler to handle explicitly. Realloc will handle a size of 0, + // but then we have to avoid raising an error for a NULL return. + clear(); + } + else + { + void* p = realloc( begin_, n * elem_size ); + CHECK_ALLOC( p ); + begin_ = p; + size_ = n; + } + } + return blargg_ok; +} + +BLARGG_NAMESPACE_END diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_common.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_common.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_common.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_common.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,224 +1,224 @@ -// Sets up common environment for Shay Green's libraries. -// To change configuration options, modify blargg_config.h, not this file. - -// $package -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -#include -#include -#include - -typedef const char* blargg_err_t; // 0 on success, otherwise error string - -// Success; no error -blargg_err_t const blargg_ok = 0; - -// BLARGG_RESTRICT: equivalent to C99's restrict, where supported -#if __GNUC__ >= 3 || _MSC_VER >= 1100 - #define BLARGG_RESTRICT __restrict -#else - #define BLARGG_RESTRICT -#endif - -#if __cplusplus >= 199711 - #define BLARGG_MUTABLE mutable -#else - #define BLARGG_MUTABLE -#endif - -/* BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant). -I don't just use 'abcd' because that's implementation-dependent. */ -#define BLARGG_4CHAR( a, b, c, d ) \ - ((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF)) - -/* BLARGG_STATIC_ASSERT( expr ): Generates compile error if expr is 0. -Can be used at file, function, or class scope. */ -#ifdef _MSC_VER - // MSVC6 (_MSC_VER < 1300) __LINE__ fails when /Zl is specified - #define BLARGG_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) -#else - // Others fail when declaring same function multiple times in class, - // so differentiate them by line - #define BLARGG_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) -#endif - -/* Pure virtual functions cause a vtable entry to a "called pure virtual" -error handler, requiring linkage to the C++ runtime library. This macro is -used in place of the "= 0", and simply expands to its argument. During -development, it expands to "= 0", allowing detection of missing overrides. */ -#define BLARGG_PURE( def ) def - -/* My code depends on ASCII anywhere a character or string constant is -compared with data read from a file, and anywhere file data is read and -treated as a string. */ -#if '\n'!=0x0A || ' '!=0x20 || '0'!=0x30 || 'A'!=0x41 || 'a'!=0x61 - #error "ASCII character set required" -#endif - -/* My code depends on int being at least 32 bits. Almost everything these days -uses at least 32-bit ints, so it's hard to even find a system with 16-bit ints -to test with. The issue can't be gotten around by using a suitable blargg_int -everywhere either, because int is often converted to implicitly when doing -arithmetic on smaller types. */ -#if UINT_MAX < 0xFFFFFFFF - #error "int must be at least 32 bits" -#endif - -// In case compiler doesn't support these properly. Used rarely. -#define STATIC_CAST(T,expr) static_cast (expr) -#define CONST_CAST( T,expr) const_cast (expr) - -// User configuration can override the above macros if necessary -#include "blargg_config.h" - -#ifdef BLARGG_NAMESPACE - #define BLARGG_NAMESPACE_BEGIN namespace BLARGG_NAMESPACE { - #define BLARGG_NAMESPACE_END } - - BLARGG_NAMESPACE_BEGIN - BLARGG_NAMESPACE_END - using namespace BLARGG_NAMESPACE; -#else - #define BLARGG_NAMESPACE_BEGIN - #define BLARGG_NAMESPACE_END -#endif - -BLARGG_NAMESPACE_BEGIN - -/* BLARGG_DEPRECATED [_TEXT] for any declarations/text to be removed in a -future version. In GCC, we can let the compiler warn. In other compilers, -we strip it out unless BLARGG_LEGACY is true. */ -#if BLARGG_LEGACY - // Allow old client code to work without warnings - #define BLARGG_DEPRECATED_TEXT( text ) text - #define BLARGG_DEPRECATED( text ) text -#elif __GNUC__ >= 4 - // In GCC, we can mark declarations and let the compiler warn - #define BLARGG_DEPRECATED_TEXT( text ) text - #define BLARGG_DEPRECATED( text ) __attribute__ ((deprecated)) text -#else - // By default, deprecated items are removed, to avoid use in new code - #define BLARGG_DEPRECATED_TEXT( text ) - #define BLARGG_DEPRECATED( text ) -#endif - -/* BOOST::int8_t, BOOST::int32_t, etc. -I used BOOST since I originally was going to allow use of the boost library -for prividing the definitions. If I'm defining them, they must be scoped or -else they could conflict with the standard ones at global scope. Even if -HAVE_STDINT_H isn't defined, I can't assume the typedefs won't exist at -global scope already. */ -#if defined (HAVE_STDINT_H) || \ - UCHAR_MAX != 0xFF || USHRT_MAX != 0xFFFF || UINT_MAX != 0xFFFFFFFF - #include - #define BOOST -#else - struct BOOST - { - typedef signed char int8_t; - typedef unsigned char uint8_t; - typedef short int16_t; - typedef unsigned short uint16_t; - typedef int int32_t; - typedef unsigned int uint32_t; - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; - }; -#endif - -/* My code is not written with exceptions in mind, so either uses new (nothrow) -OR overrides operator new in my classes. The former is best since clients -creating objects will get standard exceptions on failure, but that causes it -to require the standard C++ library. So, when the client is using the C -interface, I override operator new to use malloc. */ - -// BLARGG_DISABLE_NOTHROW is put inside classes -#ifndef BLARGG_DISABLE_NOTHROW - // throw spec mandatory in ISO C++ if NULL can be returned - #if __cplusplus >= 199711 || __GNUC__ >= 3 || _MSC_VER >= 1300 - #define BLARGG_THROWS_NOTHING throw () - #else - #define BLARGG_THROWS_NOTHING - #endif - - #define BLARGG_DISABLE_NOTHROW \ - void* operator new ( size_t s ) BLARGG_THROWS_NOTHING { return malloc( s ); }\ - void operator delete( void* p ) BLARGG_THROWS_NOTHING { free( p ); } - - #define BLARGG_NEW new -#else - // BLARGG_NEW is used in place of new in library code - #include - #define BLARGG_NEW new (std::nothrow) -#endif - - class blargg_vector_ { - protected: - void* begin_; - size_t size_; - void init(); - blargg_err_t resize_( size_t n, size_t elem_size ); - public: - size_t size() const { return size_; } - void clear(); - }; - -// Very lightweight vector for POD types (no constructor/destructor) -template -class blargg_vector : public blargg_vector_ { - union T_must_be_pod { T t; }; // fails if T is not POD -public: - blargg_vector() { init(); } - ~blargg_vector() { clear(); } - - blargg_err_t resize( size_t n ) { return resize_( n, sizeof (T) ); } - - T* begin() { return static_cast (begin_); } - const T* begin() const { return static_cast (begin_); } - - T* end() { return static_cast (begin_) + size_; } - const T* end() const { return static_cast (begin_) + size_; } - - T& operator [] ( size_t n ) - { - assert( n < size_ ); - return static_cast (begin_) [n]; - } - - const T& operator [] ( size_t n ) const - { - assert( n < size_ ); - return static_cast (begin_) [n]; - } -}; - -// Callback function with user data. -// blargg_callback set_callback; // for user, this acts like... -// void set_callback( T func, void* user_data = NULL ); // ...this -// To call function, do set_callback.f( .. set_callback.data ... ); -template -struct blargg_callback -{ - T f; - void* data; - blargg_callback() { f = NULL; } - void operator () ( T callback, void* user_data = NULL ) { f = callback; data = user_data; } -}; - -#ifndef _WIN32 - // Not supported on any other platforms - #undef BLARGG_UTF8_PATHS -#endif - -BLARGG_DEPRECATED( typedef signed int blargg_long; ) -BLARGG_DEPRECATED( typedef unsigned int blargg_ulong; ) -#if BLARGG_LEGACY - #define BOOST_STATIC_ASSERT BLARGG_STATIC_ASSERT -#endif - -BLARGG_NAMESPACE_END - -#endif +// Sets up common environment for Shay Green's libraries. +// To change configuration options, modify blargg_config.h, not this file. + +// $package +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +#include +#include +#include + +typedef const char* blargg_err_t; // 0 on success, otherwise error string + +// Success; no error +blargg_err_t const blargg_ok = 0; + +// BLARGG_RESTRICT: equivalent to C99's restrict, where supported +#if __GNUC__ >= 3 || _MSC_VER >= 1100 + #define BLARGG_RESTRICT __restrict +#else + #define BLARGG_RESTRICT +#endif + +#if __cplusplus >= 199711 + #define BLARGG_MUTABLE mutable +#else + #define BLARGG_MUTABLE +#endif + +/* BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant). +I don't just use 'abcd' because that's implementation-dependent. */ +#define BLARGG_4CHAR( a, b, c, d ) \ + ((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF)) + +/* BLARGG_STATIC_ASSERT( expr ): Generates compile error if expr is 0. +Can be used at file, function, or class scope. */ +#ifdef _MSC_VER + // MSVC6 (_MSC_VER < 1300) __LINE__ fails when /Zl is specified + #define BLARGG_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) +#else + // Others fail when declaring same function multiple times in class, + // so differentiate them by line + #define BLARGG_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) +#endif + +/* Pure virtual functions cause a vtable entry to a "called pure virtual" +error handler, requiring linkage to the C++ runtime library. This macro is +used in place of the "= 0", and simply expands to its argument. During +development, it expands to "= 0", allowing detection of missing overrides. */ +#define BLARGG_PURE( def ) def + +/* My code depends on ASCII anywhere a character or string constant is +compared with data read from a file, and anywhere file data is read and +treated as a string. */ +#if '\n'!=0x0A || ' '!=0x20 || '0'!=0x30 || 'A'!=0x41 || 'a'!=0x61 + #error "ASCII character set required" +#endif + +/* My code depends on int being at least 32 bits. Almost everything these days +uses at least 32-bit ints, so it's hard to even find a system with 16-bit ints +to test with. The issue can't be gotten around by using a suitable blargg_int +everywhere either, because int is often converted to implicitly when doing +arithmetic on smaller types. */ +#if UINT_MAX < 0xFFFFFFFF + #error "int must be at least 32 bits" +#endif + +// In case compiler doesn't support these properly. Used rarely. +#define STATIC_CAST(T,expr) static_cast (expr) +#define CONST_CAST( T,expr) const_cast (expr) + +// User configuration can override the above macros if necessary +#include "blargg_config.h" + +#ifdef BLARGG_NAMESPACE + #define BLARGG_NAMESPACE_BEGIN namespace BLARGG_NAMESPACE { + #define BLARGG_NAMESPACE_END } + + BLARGG_NAMESPACE_BEGIN + BLARGG_NAMESPACE_END + using namespace BLARGG_NAMESPACE; +#else + #define BLARGG_NAMESPACE_BEGIN + #define BLARGG_NAMESPACE_END +#endif + +BLARGG_NAMESPACE_BEGIN + +/* BLARGG_DEPRECATED [_TEXT] for any declarations/text to be removed in a +future version. In GCC, we can let the compiler warn. In other compilers, +we strip it out unless BLARGG_LEGACY is true. */ +#if BLARGG_LEGACY + // Allow old client code to work without warnings + #define BLARGG_DEPRECATED_TEXT( text ) text + #define BLARGG_DEPRECATED( text ) text +#elif __GNUC__ >= 4 + // In GCC, we can mark declarations and let the compiler warn + #define BLARGG_DEPRECATED_TEXT( text ) text + #define BLARGG_DEPRECATED( text ) __attribute__ ((deprecated)) text +#else + // By default, deprecated items are removed, to avoid use in new code + #define BLARGG_DEPRECATED_TEXT( text ) + #define BLARGG_DEPRECATED( text ) +#endif + +/* BOOST::int8_t, BOOST::int32_t, etc. +I used BOOST since I originally was going to allow use of the boost library +for prividing the definitions. If I'm defining them, they must be scoped or +else they could conflict with the standard ones at global scope. Even if +HAVE_STDINT_H isn't defined, I can't assume the typedefs won't exist at +global scope already. */ +#if defined (HAVE_STDINT_H) || \ + UCHAR_MAX != 0xFF || USHRT_MAX != 0xFFFF || UINT_MAX != 0xFFFFFFFF + #include + #define BOOST +#else + struct BOOST + { + typedef signed char int8_t; + typedef unsigned char uint8_t; + typedef short int16_t; + typedef unsigned short uint16_t; + typedef int int32_t; + typedef unsigned int uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + }; +#endif + +/* My code is not written with exceptions in mind, so either uses new (nothrow) +OR overrides operator new in my classes. The former is best since clients +creating objects will get standard exceptions on failure, but that causes it +to require the standard C++ library. So, when the client is using the C +interface, I override operator new to use malloc. */ + +// BLARGG_DISABLE_NOTHROW is put inside classes +#ifndef BLARGG_DISABLE_NOTHROW + // throw spec mandatory in ISO C++ if NULL can be returned + #if __cplusplus >= 199711 || __GNUC__ >= 3 || _MSC_VER >= 1300 + #define BLARGG_THROWS_NOTHING throw () + #else + #define BLARGG_THROWS_NOTHING + #endif + + #define BLARGG_DISABLE_NOTHROW \ + void* operator new ( size_t s ) BLARGG_THROWS_NOTHING { return malloc( s ); }\ + void operator delete( void* p ) BLARGG_THROWS_NOTHING { free( p ); } + + #define BLARGG_NEW new +#else + // BLARGG_NEW is used in place of new in library code + #include + #define BLARGG_NEW new (std::nothrow) +#endif + + class blargg_vector_ { + protected: + void* begin_; + size_t size_; + void init(); + blargg_err_t resize_( size_t n, size_t elem_size ); + public: + size_t size() const { return size_; } + void clear(); + }; + +// Very lightweight vector for POD types (no constructor/destructor) +template +class blargg_vector : public blargg_vector_ { + union T_must_be_pod { T t; }; // fails if T is not POD +public: + blargg_vector() { init(); } + ~blargg_vector() { clear(); } + + blargg_err_t resize( size_t n ) { return resize_( n, sizeof (T) ); } + + T* begin() { return static_cast (begin_); } + const T* begin() const { return static_cast (begin_); } + + T* end() { return static_cast (begin_) + size_; } + const T* end() const { return static_cast (begin_) + size_; } + + T& operator [] ( size_t n ) + { + assert( n < size_ ); + return static_cast (begin_) [n]; + } + + const T& operator [] ( size_t n ) const + { + assert( n < size_ ); + return static_cast (begin_) [n]; + } +}; + +// Callback function with user data. +// blargg_callback set_callback; // for user, this acts like... +// void set_callback( T func, void* user_data = NULL ); // ...this +// To call function, do set_callback.f( .. set_callback.data ... ); +template +struct blargg_callback +{ + T f; + void* data; + blargg_callback() { f = NULL; } + void operator () ( T callback, void* user_data = NULL ) { f = callback; data = user_data; } +}; + +#ifndef _WIN32 + // Not supported on any other platforms + #undef BLARGG_UTF8_PATHS +#endif + +BLARGG_DEPRECATED( typedef signed int blargg_long; ) +BLARGG_DEPRECATED( typedef unsigned int blargg_ulong; ) +#if BLARGG_LEGACY + #define BOOST_STATIC_ASSERT BLARGG_STATIC_ASSERT +#endif + +BLARGG_NAMESPACE_END + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_config.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_config.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_config.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_config.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,56 +1,56 @@ -// Library configuration. Modify this file as necessary. - -// $package -#ifndef BLARGG_CONFIG_H -#define BLARGG_CONFIG_H - -// Uncomment a #define line below to have effect described. - -// Allow static linking with this library and one of my other libraries -// in the same program. -//#define BLARGG_NAMESPACE blargg_gme - -// Use zlib for transparent decompression of gzipped files. -//#define HAVE_ZLIB_H - -// Support only listed music types. Remove a line to disable that type. -/* #define GME_TYPE_LIST \ - gme_ay_type,\ - gme_gbs_type,\ - gme_gym_type,\ - gme_hes_type,\ - gme_kss_type,\ - gme_nsf_type,\ - gme_nsfe_type,\ - gme_sap_type,\ - gme_sfm_type,\ - gme_sgc_type,\ - gme_spc_type,\ - gme_vgm_type,\ - gme_vgz_type -*/ - -// Enable platform-specific optimizations. -//#define BLARGG_NONPORTABLE 1 - -// Use faster sample rate convertor for SPC music. -//#define GME_SPC_FAST_RESAMPLER 1 - -// Use faster sample rate convertor for VGM and GYM music. -//#define GME_VGM_FAST_RESAMPLER 1 - -// Use faster, significantly lower quality sound synthesis for classic emulators. -//#define BLIP_BUFFER_FAST 1 - -// Reduce memory usage of gme.h by disabling gme_set_effects_config(). -//#define GME_DISABLE_EFFECTS 1 - -// Force library to use assume big-endian processor. -//#define BLARGG_BIG_ENDIAN 1 - -// Use standard config.h if present -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#endif +// Library configuration. Modify this file as necessary. + +// $package +#ifndef BLARGG_CONFIG_H +#define BLARGG_CONFIG_H + +// Uncomment a #define line below to have effect described. + +// Allow static linking with this library and one of my other libraries +// in the same program. +//#define BLARGG_NAMESPACE blargg_gme + +// Use zlib for transparent decompression of gzipped files. +//#define HAVE_ZLIB_H + +// Support only listed music types. Remove a line to disable that type. +/* #define GME_TYPE_LIST \ + gme_ay_type,\ + gme_gbs_type,\ + gme_gym_type,\ + gme_hes_type,\ + gme_kss_type,\ + gme_nsf_type,\ + gme_nsfe_type,\ + gme_sap_type,\ + gme_sfm_type,\ + gme_sgc_type,\ + gme_spc_type,\ + gme_vgm_type,\ + gme_vgz_type +*/ + +// Enable platform-specific optimizations. +//#define BLARGG_NONPORTABLE 1 + +// Use faster sample rate convertor for SPC music. +//#define GME_SPC_FAST_RESAMPLER 1 + +// Use faster sample rate convertor for VGM and GYM music. +//#define GME_VGM_FAST_RESAMPLER 1 + +// Use faster, significantly lower quality sound synthesis for classic emulators. +//#define BLIP_BUFFER_FAST 1 + +// Reduce memory usage of gme.h by disabling gme_set_effects_config(). +//#define GME_DISABLE_EFFECTS 1 + +// Force library to use assume big-endian processor. +//#define BLARGG_BIG_ENDIAN 1 + +// Use standard config.h if present +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_endian.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_endian.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_endian.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_endian.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,203 +1,203 @@ -// CPU Byte Order Utilities - -// $package -#ifndef BLARGG_ENDIAN_H -#define BLARGG_ENDIAN_H - -#include "blargg_common.h" - -// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) -#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64) - #define BLARGG_CPU_X86 1 - #define BLARGG_CPU_CISC 1 -#endif - -#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \ - defined (__POWERPC__) || defined (__powerc) - #define BLARGG_CPU_POWERPC 1 - #define BLARGG_CPU_RISC 1 -#endif - -// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only -// one may be #defined to 1. Only needed if something actually depends on byte order. -#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) -#ifdef __GLIBC__ - // GCC handles this for us - #include - #if __BYTE_ORDER == __LITTLE_ENDIAN - #define BLARGG_LITTLE_ENDIAN 1 - #elif __BYTE_ORDER == __BIG_ENDIAN - #define BLARGG_BIG_ENDIAN 1 - #endif -#else - -#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ - (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) - #define BLARGG_LITTLE_ENDIAN 1 -#endif - -#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ - defined (__sparc__) || BLARGG_CPU_POWERPC || \ - (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) - #define BLARGG_BIG_ENDIAN 1 -#elif !defined (__mips__) - // No endian specified; assume little-endian, since it's most common - #define BLARGG_LITTLE_ENDIAN 1 -#endif -#endif -#endif - -#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN - #undef BLARGG_LITTLE_ENDIAN - #undef BLARGG_BIG_ENDIAN -#endif - -BLARGG_NAMESPACE_BEGIN - -inline void blargg_verify_byte_order() -{ - #ifndef NDEBUG - #if BLARGG_BIG_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i == 0 ); - #elif BLARGG_LITTLE_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i != 0 ); - #endif - #endif -} - -inline unsigned get_le16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; -} - -inline unsigned get_be16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [0] << 8 | - (unsigned) ((unsigned char const*) p) [1]; -} - -inline unsigned get_le24( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [2] << 16 | - (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; -} - -inline unsigned get_be24( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [0] << 16 | - (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [2]; -} - -inline unsigned get_le32( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [3] << 24 | - (unsigned) ((unsigned char const*) p) [2] << 16 | - (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; -} - -inline unsigned get_be32( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [0] << 24 | - (unsigned) ((unsigned char const*) p) [1] << 16 | - (unsigned) ((unsigned char const*) p) [2] << 8 | - (unsigned) ((unsigned char const*) p) [3]; -} - -inline void set_le16( void* p, unsigned n ) -{ - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [0] = (unsigned char) n; -} - -inline void set_be16( void* p, unsigned n ) -{ - ((unsigned char*) p) [0] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) n; -} - -inline void set_le32( void* p, unsigned n ) -{ - ((unsigned char*) p) [0] = (unsigned char) n; - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [2] = (unsigned char) (n >> 16); - ((unsigned char*) p) [3] = (unsigned char) (n >> 24); -} - -inline void set_be32( void* p, unsigned n ) -{ - ((unsigned char*) p) [3] = (unsigned char) n; - ((unsigned char*) p) [2] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) (n >> 16); - ((unsigned char*) p) [0] = (unsigned char) (n >> 24); -} - -#if BLARGG_NONPORTABLE - // Optimized implementation if byte order is known - #if BLARGG_LITTLE_ENDIAN - #define GET_LE16( addr ) (*(BOOST::uint16_t const*) (addr)) - #define GET_LE32( addr ) (*(BOOST::uint32_t const*) (addr)) - #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) - #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - #elif BLARGG_BIG_ENDIAN - #define GET_BE16( addr ) (*(BOOST::uint16_t const*) (addr)) - #define GET_BE32( addr ) (*(BOOST::uint32_t const*) (addr)) - #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) - #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - - #if BLARGG_CPU_POWERPC - // PowerPC has special byte-reversed instructions - #if defined (__MWERKS__) - #define GET_LE16( addr ) (__lhbrx( addr, 0 )) - #define GET_LE32( addr ) (__lwbrx( addr, 0 )) - #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) - #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) - #elif defined (__GNUC__) - #define GET_LE16( addr ) ({unsigned short ppc_lhbrx_; __asm__ volatile( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr) : "memory" ); ppc_lhbrx_;}) - #define GET_LE32( addr ) ({unsigned short ppc_lwbrx_; __asm__ volatile( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr) : "memory" ); ppc_lwbrx_;}) - #define SET_LE16( addr, in ) ({__asm__ volatile( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );}) - #define SET_LE32( addr, in ) ({__asm__ volatile( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );}) - #endif - #endif - #endif -#endif - -#ifndef GET_LE16 - #define GET_LE16( addr ) get_le16( addr ) - #define SET_LE16( addr, data ) set_le16( addr, data ) -#endif - -#ifndef GET_LE32 - #define GET_LE32( addr ) get_le32( addr ) - #define SET_LE32( addr, data ) set_le32( addr, data ) -#endif - -#ifndef GET_BE16 - #define GET_BE16( addr ) get_be16( addr ) - #define SET_BE16( addr, data ) set_be16( addr, data ) -#endif - -#ifndef GET_BE32 - #define GET_BE32( addr ) get_be32( addr ) - #define SET_BE32( addr, data ) set_be32( addr, data ) -#endif - -// auto-selecting versions - -inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } -inline void set_le( BOOST::uint32_t* p, unsigned n ) { SET_LE32( p, n ); } -inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } -inline void set_be( BOOST::uint32_t* p, unsigned n ) { SET_BE32( p, n ); } -inline unsigned get_le( BOOST::uint16_t const* p ) { return GET_LE16( p ); } -inline unsigned get_le( BOOST::uint32_t const* p ) { return GET_LE32( p ); } -inline unsigned get_be( BOOST::uint16_t const* p ) { return GET_BE16( p ); } -inline unsigned get_be( BOOST::uint32_t const* p ) { return GET_BE32( p ); } - -BLARGG_NAMESPACE_END - -#endif +// CPU Byte Order Utilities + +// $package +#ifndef BLARGG_ENDIAN_H +#define BLARGG_ENDIAN_H + +#include "blargg_common.h" + +// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) +#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64) + #define BLARGG_CPU_X86 1 + #define BLARGG_CPU_CISC 1 +#endif + +#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \ + defined (__POWERPC__) || defined (__powerc) + #define BLARGG_CPU_POWERPC 1 + #define BLARGG_CPU_RISC 1 +#endif + +// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only +// one may be #defined to 1. Only needed if something actually depends on byte order. +#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) +#ifdef __GLIBC__ + // GCC handles this for us + #include + #if __BYTE_ORDER == __LITTLE_ENDIAN + #define BLARGG_LITTLE_ENDIAN 1 + #elif __BYTE_ORDER == __BIG_ENDIAN + #define BLARGG_BIG_ENDIAN 1 + #endif +#else + +#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ + (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) + #define BLARGG_LITTLE_ENDIAN 1 +#endif + +#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ + defined (__sparc__) || BLARGG_CPU_POWERPC || \ + (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) + #define BLARGG_BIG_ENDIAN 1 +#elif !defined (__mips__) + // No endian specified; assume little-endian, since it's most common + #define BLARGG_LITTLE_ENDIAN 1 +#endif +#endif +#endif + +#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN + #undef BLARGG_LITTLE_ENDIAN + #undef BLARGG_BIG_ENDIAN +#endif + +BLARGG_NAMESPACE_BEGIN + +inline void blargg_verify_byte_order() +{ + #ifndef NDEBUG + #if BLARGG_BIG_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i == 0 ); + #elif BLARGG_LITTLE_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i != 0 ); + #endif + #endif +} + +inline unsigned get_le16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 8 | + (unsigned) ((unsigned char const*) p) [1]; +} + +inline unsigned get_le24( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [2] << 16 | + (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be24( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 16 | + (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [2]; +} + +inline unsigned get_le32( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [3] << 24 | + (unsigned) ((unsigned char const*) p) [2] << 16 | + (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be32( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 24 | + (unsigned) ((unsigned char const*) p) [1] << 16 | + (unsigned) ((unsigned char const*) p) [2] << 8 | + (unsigned) ((unsigned char const*) p) [3]; +} + +inline void set_le16( void* p, unsigned n ) +{ + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [0] = (unsigned char) n; +} + +inline void set_be16( void* p, unsigned n ) +{ + ((unsigned char*) p) [0] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) n; +} + +inline void set_le32( void* p, unsigned n ) +{ + ((unsigned char*) p) [0] = (unsigned char) n; + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [2] = (unsigned char) (n >> 16); + ((unsigned char*) p) [3] = (unsigned char) (n >> 24); +} + +inline void set_be32( void* p, unsigned n ) +{ + ((unsigned char*) p) [3] = (unsigned char) n; + ((unsigned char*) p) [2] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) (n >> 16); + ((unsigned char*) p) [0] = (unsigned char) (n >> 24); +} + +#if BLARGG_NONPORTABLE + // Optimized implementation if byte order is known + #if BLARGG_LITTLE_ENDIAN + #define GET_LE16( addr ) (*(BOOST::uint16_t const*) (addr)) + #define GET_LE32( addr ) (*(BOOST::uint32_t const*) (addr)) + #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + #elif BLARGG_BIG_ENDIAN + #define GET_BE16( addr ) (*(BOOST::uint16_t const*) (addr)) + #define GET_BE32( addr ) (*(BOOST::uint32_t const*) (addr)) + #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + + #if BLARGG_CPU_POWERPC + // PowerPC has special byte-reversed instructions + #if defined (__MWERKS__) + #define GET_LE16( addr ) (__lhbrx( addr, 0 )) + #define GET_LE32( addr ) (__lwbrx( addr, 0 )) + #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) + #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) + #elif defined (__GNUC__) + #define GET_LE16( addr ) ({unsigned short ppc_lhbrx_; __asm__ volatile( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr) : "memory" ); ppc_lhbrx_;}) + #define GET_LE32( addr ) ({unsigned short ppc_lwbrx_; __asm__ volatile( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr) : "memory" ); ppc_lwbrx_;}) + #define SET_LE16( addr, in ) ({__asm__ volatile( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );}) + #define SET_LE32( addr, in ) ({__asm__ volatile( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );}) + #endif + #endif + #endif +#endif + +#ifndef GET_LE16 + #define GET_LE16( addr ) get_le16( addr ) + #define SET_LE16( addr, data ) set_le16( addr, data ) +#endif + +#ifndef GET_LE32 + #define GET_LE32( addr ) get_le32( addr ) + #define SET_LE32( addr, data ) set_le32( addr, data ) +#endif + +#ifndef GET_BE16 + #define GET_BE16( addr ) get_be16( addr ) + #define SET_BE16( addr, data ) set_be16( addr, data ) +#endif + +#ifndef GET_BE32 + #define GET_BE32( addr ) get_be32( addr ) + #define SET_BE32( addr, data ) set_be32( addr, data ) +#endif + +// auto-selecting versions + +inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } +inline void set_le( BOOST::uint32_t* p, unsigned n ) { SET_LE32( p, n ); } +inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } +inline void set_be( BOOST::uint32_t* p, unsigned n ) { SET_BE32( p, n ); } +inline unsigned get_le( BOOST::uint16_t const* p ) { return GET_LE16( p ); } +inline unsigned get_le( BOOST::uint32_t const* p ) { return GET_LE32( p ); } +inline unsigned get_be( BOOST::uint16_t const* p ) { return GET_BE16( p ); } +inline unsigned get_be( BOOST::uint32_t const* p ) { return GET_BE32( p ); } + +BLARGG_NAMESPACE_END + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_errors.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_errors.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_errors.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_errors.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,117 +1,117 @@ -// $package. http://www.slack.net/~ant/ - -#include "blargg_errors.h" - -/* Copyright (C) 2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -BLARGG_NAMESPACE_BEGIN - -blargg_err_def_t blargg_err_generic = BLARGG_ERR_GENERIC; -// blargg_err_memory is defined in blargg_common.cpp -blargg_err_def_t blargg_err_caller = BLARGG_ERR_CALLER; -blargg_err_def_t blargg_err_internal = BLARGG_ERR_INTERNAL; -blargg_err_def_t blargg_err_limitation = BLARGG_ERR_LIMITATION; - -blargg_err_def_t blargg_err_file_missing = BLARGG_ERR_FILE_MISSING; -blargg_err_def_t blargg_err_file_read = BLARGG_ERR_FILE_READ; -blargg_err_def_t blargg_err_file_write = BLARGG_ERR_FILE_WRITE; -blargg_err_def_t blargg_err_file_io = BLARGG_ERR_FILE_IO; -blargg_err_def_t blargg_err_file_full = BLARGG_ERR_FILE_FULL; -blargg_err_def_t blargg_err_file_eof = BLARGG_ERR_FILE_EOF; - -blargg_err_def_t blargg_err_file_type = BLARGG_ERR_FILE_TYPE; -blargg_err_def_t blargg_err_file_feature = BLARGG_ERR_FILE_FEATURE; -blargg_err_def_t blargg_err_file_corrupt = BLARGG_ERR_FILE_CORRUPT; - -const char* blargg_err_str( blargg_err_t err ) -{ - if ( !err ) - return ""; - - if ( *err == BLARGG_ERR_TYPE("")[0] ) - return err + 1; - - return err; -} - -bool blargg_is_err_type( blargg_err_t err, const char type [] ) -{ - if ( err ) - { - // True if first strlen(type) characters of err match type - char const* p = err; - while ( *type && *type == *p ) - { - type++; - p++; - } - - if ( !*type ) - return true; - } - - return false; -} - -const char* blargg_err_details( blargg_err_t err ) -{ - const char* p = err; - if ( !p ) - { - p = ""; - } - else if ( *p == BLARGG_ERR_TYPE("")[0] ) - { - while ( *p && *p != ';' ) - p++; - - // Skip ; and space after it - if ( *p ) - { - p++; - - check( *p == ' ' ); - if ( *p ) - p++; - } - } - return p; -} - -int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const codes [] ) -{ - if ( !err ) - return 0; - - while ( codes->str && !blargg_is_err_type( err, codes->str ) ) - codes++; - - return codes->code; -} - -blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const codes [] ) -{ - if ( !code ) - return blargg_ok; - - while ( codes->str && codes->code != code ) - codes++; - - if ( !codes->str ) - return blargg_err_generic; - - return codes->str; -} - -BLARGG_NAMESPACE_END +// $package. http://www.slack.net/~ant/ + +#include "blargg_errors.h" + +/* Copyright (C) 2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +BLARGG_NAMESPACE_BEGIN + +blargg_err_def_t blargg_err_generic = BLARGG_ERR_GENERIC; +// blargg_err_memory is defined in blargg_common.cpp +blargg_err_def_t blargg_err_caller = BLARGG_ERR_CALLER; +blargg_err_def_t blargg_err_internal = BLARGG_ERR_INTERNAL; +blargg_err_def_t blargg_err_limitation = BLARGG_ERR_LIMITATION; + +blargg_err_def_t blargg_err_file_missing = BLARGG_ERR_FILE_MISSING; +blargg_err_def_t blargg_err_file_read = BLARGG_ERR_FILE_READ; +blargg_err_def_t blargg_err_file_write = BLARGG_ERR_FILE_WRITE; +blargg_err_def_t blargg_err_file_io = BLARGG_ERR_FILE_IO; +blargg_err_def_t blargg_err_file_full = BLARGG_ERR_FILE_FULL; +blargg_err_def_t blargg_err_file_eof = BLARGG_ERR_FILE_EOF; + +blargg_err_def_t blargg_err_file_type = BLARGG_ERR_FILE_TYPE; +blargg_err_def_t blargg_err_file_feature = BLARGG_ERR_FILE_FEATURE; +blargg_err_def_t blargg_err_file_corrupt = BLARGG_ERR_FILE_CORRUPT; + +const char* blargg_err_str( blargg_err_t err ) +{ + if ( !err ) + return ""; + + if ( *err == BLARGG_ERR_TYPE("")[0] ) + return err + 1; + + return err; +} + +bool blargg_is_err_type( blargg_err_t err, const char type [] ) +{ + if ( err ) + { + // True if first strlen(type) characters of err match type + char const* p = err; + while ( *type && *type == *p ) + { + type++; + p++; + } + + if ( !*type ) + return true; + } + + return false; +} + +const char* blargg_err_details( blargg_err_t err ) +{ + const char* p = err; + if ( !p ) + { + p = ""; + } + else if ( *p == BLARGG_ERR_TYPE("")[0] ) + { + while ( *p && *p != ';' ) + p++; + + // Skip ; and space after it + if ( *p ) + { + p++; + + check( *p == ' ' ); + if ( *p ) + p++; + } + } + return p; +} + +int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const codes [] ) +{ + if ( !err ) + return 0; + + while ( codes->str && !blargg_is_err_type( err, codes->str ) ) + codes++; + + return codes->code; +} + +blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const codes [] ) +{ + if ( !code ) + return blargg_ok; + + while ( codes->str && codes->code != code ) + codes++; + + if ( !codes->str ) + return blargg_err_generic; + + return codes->str; +} + +BLARGG_NAMESPACE_END diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_errors.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_errors.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_errors.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_errors.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,84 +1,84 @@ -// Error strings and conversion functions - -// $package -#ifndef BLARGG_ERRORS_H -#define BLARGG_ERRORS_H - -#ifndef BLARGG_COMMON_H - #include "blargg_common.h" -#endif - -BLARGG_NAMESPACE_BEGIN - -typedef const char blargg_err_def_t []; - -// Basic errors -extern blargg_err_def_t blargg_err_generic; -extern blargg_err_def_t blargg_err_memory; -extern blargg_err_def_t blargg_err_caller; -extern blargg_err_def_t blargg_err_internal; -extern blargg_err_def_t blargg_err_limitation; - -// File low-level -extern blargg_err_def_t blargg_err_file_missing; // not found -extern blargg_err_def_t blargg_err_file_read; -extern blargg_err_def_t blargg_err_file_write; -extern blargg_err_def_t blargg_err_file_io; -extern blargg_err_def_t blargg_err_file_full; -extern blargg_err_def_t blargg_err_file_eof; - -// File high-level -extern blargg_err_def_t blargg_err_file_type; // wrong file type -extern blargg_err_def_t blargg_err_file_feature; -extern blargg_err_def_t blargg_err_file_corrupt; - -// C string describing error, or "" if err == NULL -const char* blargg_err_str( blargg_err_t err ); - -// True iff error is of given type, or false if err == NULL -bool blargg_is_err_type( blargg_err_t, const char type [] ); - -// Details of error without describing main cause, or "" if err == NULL -const char* blargg_err_details( blargg_err_t err ); - -// Converts error string to integer code using mapping table. Calls blargg_is_err_type() -// for each str and returns code on first match. Returns 0 if err == NULL. -struct blargg_err_to_code_t { - const char* str; - int code; -}; -int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const [] ); - -// Converts error code back to string. If code == 0, returns NULL. If not in table, -// returns blargg_err_generic. -blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const [] ); - -// Generates error string literal with details of cause -#define BLARGG_ERR( type, str ) (type "; " str) - -// Extra space to make it clear when blargg_err_str() isn't called to get -// printable version of error. At some point, I might prefix error strings -// with a code, to speed conversion to a code. -#define BLARGG_ERR_TYPE( str ) " " str - -// Error types to pass to BLARGG_ERR macro -#define BLARGG_ERR_GENERIC BLARGG_ERR_TYPE( "operation failed" ) -#define BLARGG_ERR_MEMORY BLARGG_ERR_TYPE( "out of memory" ) -#define BLARGG_ERR_CALLER BLARGG_ERR_TYPE( "internal usage bug" ) -#define BLARGG_ERR_INTERNAL BLARGG_ERR_TYPE( "internal bug" ) -#define BLARGG_ERR_LIMITATION BLARGG_ERR_TYPE( "exceeded limitation" ) - -#define BLARGG_ERR_FILE_MISSING BLARGG_ERR_TYPE( "file not found" ) -#define BLARGG_ERR_FILE_READ BLARGG_ERR_TYPE( "couldn't open file" ) -#define BLARGG_ERR_FILE_WRITE BLARGG_ERR_TYPE( "couldn't modify file" ) -#define BLARGG_ERR_FILE_IO BLARGG_ERR_TYPE( "read/write error" ) -#define BLARGG_ERR_FILE_FULL BLARGG_ERR_TYPE( "disk full" ) -#define BLARGG_ERR_FILE_EOF BLARGG_ERR_TYPE( "truncated file" ) - -#define BLARGG_ERR_FILE_TYPE BLARGG_ERR_TYPE( "wrong file type" ) -#define BLARGG_ERR_FILE_FEATURE BLARGG_ERR_TYPE( "unsupported file feature" ) -#define BLARGG_ERR_FILE_CORRUPT BLARGG_ERR_TYPE( "corrupt file" ) - -BLARGG_NAMESPACE_END - -#endif +// Error strings and conversion functions + +// $package +#ifndef BLARGG_ERRORS_H +#define BLARGG_ERRORS_H + +#ifndef BLARGG_COMMON_H + #include "blargg_common.h" +#endif + +BLARGG_NAMESPACE_BEGIN + +typedef const char blargg_err_def_t []; + +// Basic errors +extern blargg_err_def_t blargg_err_generic; +extern blargg_err_def_t blargg_err_memory; +extern blargg_err_def_t blargg_err_caller; +extern blargg_err_def_t blargg_err_internal; +extern blargg_err_def_t blargg_err_limitation; + +// File low-level +extern blargg_err_def_t blargg_err_file_missing; // not found +extern blargg_err_def_t blargg_err_file_read; +extern blargg_err_def_t blargg_err_file_write; +extern blargg_err_def_t blargg_err_file_io; +extern blargg_err_def_t blargg_err_file_full; +extern blargg_err_def_t blargg_err_file_eof; + +// File high-level +extern blargg_err_def_t blargg_err_file_type; // wrong file type +extern blargg_err_def_t blargg_err_file_feature; +extern blargg_err_def_t blargg_err_file_corrupt; + +// C string describing error, or "" if err == NULL +const char* blargg_err_str( blargg_err_t err ); + +// True iff error is of given type, or false if err == NULL +bool blargg_is_err_type( blargg_err_t, const char type [] ); + +// Details of error without describing main cause, or "" if err == NULL +const char* blargg_err_details( blargg_err_t err ); + +// Converts error string to integer code using mapping table. Calls blargg_is_err_type() +// for each str and returns code on first match. Returns 0 if err == NULL. +struct blargg_err_to_code_t { + const char* str; + int code; +}; +int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const [] ); + +// Converts error code back to string. If code == 0, returns NULL. If not in table, +// returns blargg_err_generic. +blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const [] ); + +// Generates error string literal with details of cause +#define BLARGG_ERR( type, str ) (type "; " str) + +// Extra space to make it clear when blargg_err_str() isn't called to get +// printable version of error. At some point, I might prefix error strings +// with a code, to speed conversion to a code. +#define BLARGG_ERR_TYPE( str ) " " str + +// Error types to pass to BLARGG_ERR macro +#define BLARGG_ERR_GENERIC BLARGG_ERR_TYPE( "operation failed" ) +#define BLARGG_ERR_MEMORY BLARGG_ERR_TYPE( "out of memory" ) +#define BLARGG_ERR_CALLER BLARGG_ERR_TYPE( "internal usage bug" ) +#define BLARGG_ERR_INTERNAL BLARGG_ERR_TYPE( "internal bug" ) +#define BLARGG_ERR_LIMITATION BLARGG_ERR_TYPE( "exceeded limitation" ) + +#define BLARGG_ERR_FILE_MISSING BLARGG_ERR_TYPE( "file not found" ) +#define BLARGG_ERR_FILE_READ BLARGG_ERR_TYPE( "couldn't open file" ) +#define BLARGG_ERR_FILE_WRITE BLARGG_ERR_TYPE( "couldn't modify file" ) +#define BLARGG_ERR_FILE_IO BLARGG_ERR_TYPE( "read/write error" ) +#define BLARGG_ERR_FILE_FULL BLARGG_ERR_TYPE( "disk full" ) +#define BLARGG_ERR_FILE_EOF BLARGG_ERR_TYPE( "truncated file" ) + +#define BLARGG_ERR_FILE_TYPE BLARGG_ERR_TYPE( "wrong file type" ) +#define BLARGG_ERR_FILE_FEATURE BLARGG_ERR_TYPE( "unsupported file feature" ) +#define BLARGG_ERR_FILE_CORRUPT BLARGG_ERR_TYPE( "corrupt file" ) + +BLARGG_NAMESPACE_END + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_source.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_source.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/blargg_source.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/blargg_source.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,175 +1,175 @@ -/* Included at the beginning of library source files, AFTER all other #include -lines. Sets up helpful macros and services used in my source code. Since this -is only "active" in my source code, I don't have to worry about polluting the -global namespace with unprefixed names. */ - -// $package -#ifndef BLARGG_SOURCE_H -#define BLARGG_SOURCE_H - -#ifndef BLARGG_COMMON_H // optimization only - #include "blargg_common.h" -#endif -#include "blargg_errors.h" -#include "gme_custom_dprintf.h" - -#include /* memcpy(), memset(), memmove() */ -#include /* offsetof() */ - -/* The following four macros are for debugging only. Some or all might be -defined to do nothing, depending on the circumstances. Described is what -happens when a particular macro is defined to do something. When defined to -do nothing, the macros do NOT evaluate their argument(s). */ - -/* If expr is false, prints file and line number, then aborts program. Meant -for checking internal state and consistency. A failed assertion indicates a bug -in MY code. - -void assert( bool expr ); */ -#include - -/* If expr is false, prints file and line number, then aborts program. Meant -for checking caller-supplied parameters and operations that are outside the -control of the module. A failed requirement probably indicates a bug in YOUR -code. - -void require( bool expr ); */ -#undef require -#define require( expr ) assert( expr ) - -/* Like printf() except output goes to debugging console/file. - -void dprintf( const char format [], ... ); */ - -#ifdef CUSTOM_DPRINTF_FUNCTION - -static inline void dprintf( const char * fmt, ... ) -{ - if (gme_custom_dprintf) - { - va_list vl; - va_start(vl, fmt); - gme_custom_dprintf(fmt, vl); - va_end(vl); - } -} - -#else - -#ifdef NDEBUG -static inline void blargg_dprintf_( const char [], ... ) { } -#undef dprintf -#define dprintf (1) ? (void) 0 : blargg_dprintf_ -#else -#include -#include -#undef dprintf -#define dprintf (1) ? (void) 0 : blargg_dprintf_ -#ifndef _WIN32 -#include -static inline void blargg_dprintf_( const char * fmt, ... ) -{ - char error[512]; - va_list vl; - va_start(vl, fmt); - vsnprintf( error, 511, fmt, vl ); - va_end(vl); - fputs( error, stderr ); -} -#else -#include -static inline void blargg_dprintf_( const char * fmt, ... ) -{ - char error[512]; - va_list vl; - va_start(vl, fmt); - vsnprintf_s( error, 511, 511, fmt, vl ); - va_end(vl); - OutputDebugStringA( error ); -} -#endif -#endif - -#endif - -/* If expr is false, prints file and line number to debug console/log, then -continues execution normally. Meant for flagging potential problems or things -that should be looked into, but that aren't serious problems. - -void check( bool expr ); */ -#undef check -#define check( expr ) ((void) 0) - -/* If expr yields non-NULL error string, returns it from current function, -otherwise continues normally. */ -#undef RETURN_ERR -#define RETURN_ERR( expr ) \ - do {\ - blargg_err_t blargg_return_err_ = (expr);\ - if ( blargg_return_err_ )\ - return blargg_return_err_;\ - } while ( 0 ) - -/* If ptr is NULL, returns out-of-memory error, otherwise continues normally. */ -#undef CHECK_ALLOC -#define CHECK_ALLOC( ptr ) \ - do {\ - if ( !(ptr) )\ - return blargg_err_memory;\ - } while ( 0 ) - -/* The usual min/max functions for built-in types. - -template T min( T x, T y ) { return x < y ? x : y; } -template T max( T x, T y ) { return x > y ? x : y; } */ -#define BLARGG_DEF_MIN_MAX( type ) \ - static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\ - static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; } - -BLARGG_DEF_MIN_MAX( int ) -BLARGG_DEF_MIN_MAX( unsigned ) -BLARGG_DEF_MIN_MAX( long ) -BLARGG_DEF_MIN_MAX( unsigned long ) -BLARGG_DEF_MIN_MAX( unsigned long long ) -BLARGG_DEF_MIN_MAX( float ) -BLARGG_DEF_MIN_MAX( double ) - -#undef min -#define min blargg_min - -#undef max -#define max blargg_max - -// typedef unsigned char byte; -typedef unsigned char blargg_byte; -#undef byte -#define byte blargg_byte - -#ifndef BLARGG_EXPORT - #if defined (_WIN32) && BLARGG_BUILD_DLL - #define BLARGG_EXPORT __declspec(dllexport) - #elif defined (__GNUC__) - // can always set visibility, even when not building DLL - #define BLARGG_EXPORT __attribute__ ((visibility ("default"))) - #else - #define BLARGG_EXPORT - #endif -#endif - -#if BLARGG_LEGACY - #define BLARGG_CHECK_ALLOC CHECK_ALLOC - #define BLARGG_RETURN_ERR RETURN_ERR -#endif - -// Called after failed operation when overall operation may still complete OK. -// Only used by unit testing framework. -#undef ACK_FAILURE -#define ACK_FAILURE() ((void)0) - -/* BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf etc. -and check */ -#ifdef BLARGG_SOURCE_BEGIN - #include BLARGG_SOURCE_BEGIN -#endif - -#endif +/* Included at the beginning of library source files, AFTER all other #include +lines. Sets up helpful macros and services used in my source code. Since this +is only "active" in my source code, I don't have to worry about polluting the +global namespace with unprefixed names. */ + +// $package +#ifndef BLARGG_SOURCE_H +#define BLARGG_SOURCE_H + +#ifndef BLARGG_COMMON_H // optimization only + #include "blargg_common.h" +#endif +#include "blargg_errors.h" +#include "gme_custom_dprintf.h" + +#include /* memcpy(), memset(), memmove() */ +#include /* offsetof() */ + +/* The following four macros are for debugging only. Some or all might be +defined to do nothing, depending on the circumstances. Described is what +happens when a particular macro is defined to do something. When defined to +do nothing, the macros do NOT evaluate their argument(s). */ + +/* If expr is false, prints file and line number, then aborts program. Meant +for checking internal state and consistency. A failed assertion indicates a bug +in MY code. + +void assert( bool expr ); */ +#include + +/* If expr is false, prints file and line number, then aborts program. Meant +for checking caller-supplied parameters and operations that are outside the +control of the module. A failed requirement probably indicates a bug in YOUR +code. + +void require( bool expr ); */ +#undef require +#define require( expr ) assert( expr ) + +/* Like printf() except output goes to debugging console/file. + +void dprintf( const char format [], ... ); */ + +#ifdef CUSTOM_DPRINTF_FUNCTION + +static inline void dprintf( const char * fmt, ... ) +{ + if (gme_custom_dprintf) + { + va_list vl; + va_start(vl, fmt); + gme_custom_dprintf(fmt, vl); + va_end(vl); + } +} + +#else + +#ifdef NDEBUG +static inline void blargg_dprintf_( const char [], ... ) { } +#undef dprintf +#define dprintf (1) ? (void) 0 : blargg_dprintf_ +#else +#include +#include +#undef dprintf +#define dprintf (1) ? (void) 0 : blargg_dprintf_ +#ifndef _WIN32 +#include +static inline void blargg_dprintf_( const char * fmt, ... ) +{ + char error[512]; + va_list vl; + va_start(vl, fmt); + vsnprintf( error, 511, fmt, vl ); + va_end(vl); + fputs( error, stderr ); +} +#else +#include +static inline void blargg_dprintf_( const char * fmt, ... ) +{ + char error[512]; + va_list vl; + va_start(vl, fmt); + vsnprintf_s( error, 511, 511, fmt, vl ); + va_end(vl); + OutputDebugStringA( error ); +} +#endif +#endif + +#endif + +/* If expr is false, prints file and line number to debug console/log, then +continues execution normally. Meant for flagging potential problems or things +that should be looked into, but that aren't serious problems. + +void check( bool expr ); */ +#undef check +#define check( expr ) ((void) 0) + +/* If expr yields non-NULL error string, returns it from current function, +otherwise continues normally. */ +#undef RETURN_ERR +#define RETURN_ERR( expr ) \ + do {\ + blargg_err_t blargg_return_err_ = (expr);\ + if ( blargg_return_err_ )\ + return blargg_return_err_;\ + } while ( 0 ) + +/* If ptr is NULL, returns out-of-memory error, otherwise continues normally. */ +#undef CHECK_ALLOC +#define CHECK_ALLOC( ptr ) \ + do {\ + if ( !(ptr) )\ + return blargg_err_memory;\ + } while ( 0 ) + +/* The usual min/max functions for built-in types. + +template T min( T x, T y ) { return x < y ? x : y; } +template T max( T x, T y ) { return x > y ? x : y; } */ +#define BLARGG_DEF_MIN_MAX( type ) \ + static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\ + static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; } + +BLARGG_DEF_MIN_MAX( int ) +BLARGG_DEF_MIN_MAX( unsigned ) +BLARGG_DEF_MIN_MAX( long ) +BLARGG_DEF_MIN_MAX( unsigned long ) +BLARGG_DEF_MIN_MAX( unsigned long long ) +BLARGG_DEF_MIN_MAX( float ) +BLARGG_DEF_MIN_MAX( double ) + +#undef min +#define min blargg_min + +#undef max +#define max blargg_max + +// typedef unsigned char byte; +typedef unsigned char blargg_byte; +#undef byte +#define byte blargg_byte + +#ifndef BLARGG_EXPORT + #if defined (_WIN32) && BLARGG_BUILD_DLL + #define BLARGG_EXPORT __declspec(dllexport) + #elif defined (__GNUC__) + // can always set visibility, even when not building DLL + #define BLARGG_EXPORT __attribute__ ((visibility ("default"))) + #else + #define BLARGG_EXPORT + #endif +#endif + +#if BLARGG_LEGACY + #define BLARGG_CHECK_ALLOC CHECK_ALLOC + #define BLARGG_RETURN_ERR RETURN_ERR +#endif + +// Called after failed operation when overall operation may still complete OK. +// Only used by unit testing framework. +#undef ACK_FAILURE +#define ACK_FAILURE() ((void)0) + +/* BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf etc. +and check */ +#ifdef BLARGG_SOURCE_BEGIN + #include BLARGG_SOURCE_BEGIN +#endif + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Blip_Buffer.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Blip_Buffer.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Blip_Buffer.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Blip_Buffer.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,509 +1,509 @@ -// Blip_Buffer $vers. http://www.slack.net/~ant/ - -#include "Blip_Buffer.h" - -#include - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -//// Blip_Buffer - -Blip_Buffer::Blip_Buffer() -{ - factor_ = UINT_MAX/2 + 1; - buffer_ = NULL; - buffer_center_ = NULL; - buffer_size_ = 0; - sample_rate_ = 0; - bass_shift_ = 0; - clock_rate_ = 0; - bass_freq_ = 16; - length_ = 0; - - // assumptions code makes about implementation-defined features - #ifndef NDEBUG - // right shift of negative value preserves sign - int i = -0x7FFFFFFE; - assert( (i >> 1) == -0x3FFFFFFF ); - - // casting truncates and sign-extends - i = 0x18000; - assert( (BOOST::int16_t) i == -0x8000 ); - #endif - - clear(); -} - -Blip_Buffer::~Blip_Buffer() -{ - free( buffer_ ); -} - -void Blip_Buffer::clear() -{ - bool const entire_buffer = true; - - offset_ = 0; - reader_accum_ = 0; - modified_ = false; - - if ( buffer_ ) - { - int count = (entire_buffer ? buffer_size_ : samples_avail()); - memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (delta_t) ); - } -} - -blargg_err_t Blip_Buffer::set_sample_rate( int new_rate, int msec ) -{ - // Limit to maximum size that resampled time can represent - int max_size = (((blip_resampled_time_t) -1) >> BLIP_BUFFER_ACCURACY) - - blip_buffer_extra_ - 64; // TODO: -64 isn't needed - int new_size = (new_rate * (msec + 1) + 999) / 1000; - if ( new_size > max_size ) - new_size = max_size; - - // Resize buffer - if ( buffer_size_ != new_size ) - { - //dprintf( "%d \n", (new_size + blip_buffer_extra_) * sizeof *buffer_ ); - void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ ); - CHECK_ALLOC( p ); - buffer_ = (delta_t*) p; - buffer_center_ = buffer_ + BLIP_MAX_QUALITY/2; - buffer_size_ = new_size; - } - - // Update sample_rate and things that depend on it - sample_rate_ = new_rate; - length_ = new_size * 1000 / new_rate - 1; - if ( clock_rate_ ) - clock_rate( clock_rate_ ); - bass_freq( bass_freq_ ); - - clear(); - - return blargg_ok; -} - -blip_resampled_time_t Blip_Buffer::clock_rate_factor( int rate ) const -{ - double ratio = (double) sample_rate_ / rate; - int factor = (int) floor( ratio * (1 << BLIP_BUFFER_ACCURACY) + 0.5 ); - assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large - return (blip_resampled_time_t) factor; -} - -void Blip_Buffer::bass_freq( int freq ) -{ - bass_freq_ = freq; - int shift = 31; - if ( freq > 0 && sample_rate_ ) - { - shift = 13; - int f = (freq << 16) / sample_rate_; - while ( (f >>= 1) != 0 && --shift ) { } - } - bass_shift_ = shift; -} - -void Blip_Buffer::end_frame( blip_time_t t ) -{ - offset_ += t * factor_; - assert( samples_avail() <= (int) buffer_size_ ); // fails if time is past end of buffer -} - -int Blip_Buffer::count_samples( blip_time_t t ) const -{ - blip_resampled_time_t last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY; - blip_resampled_time_t first_sample = offset_ >> BLIP_BUFFER_ACCURACY; - return (int) (last_sample - first_sample); -} - -blip_time_t Blip_Buffer::count_clocks( int count ) const -{ - if ( count > buffer_size_ ) - count = buffer_size_; - blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; - return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_); -} - -void Blip_Buffer::remove_samples( int count ) -{ - if ( count ) - { - remove_silence( count ); - - // copy remaining samples to beginning and clear old samples - int remain = samples_avail() + blip_buffer_extra_; - memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ ); - memset( buffer_ + remain, 0, count * sizeof *buffer_ ); - } -} - -int Blip_Buffer::read_samples( blip_sample_t out_ [], int max_samples, bool stereo ) -{ - int count = samples_avail(); - if ( count > max_samples ) - count = max_samples; - - if ( count ) - { - int const bass = highpass_shift(); - delta_t const* reader = read_pos() + count; - int reader_sum = integrator(); - - blip_sample_t* BLARGG_RESTRICT out = out_ + count; - if ( stereo ) - out += count; - int offset = -count; - - if ( !stereo ) - { - do - { - int s = reader_sum >> delta_bits; - - reader_sum -= reader_sum >> bass; - reader_sum += reader [offset]; - - BLIP_CLAMP( s, s ); - out [offset] = (blip_sample_t) s; - } - while ( ++offset ); - } - else - { - do - { - int s = reader_sum >> delta_bits; - - reader_sum -= reader_sum >> bass; - reader_sum += reader [offset]; - - BLIP_CLAMP( s, s ); - out [offset * 2] = (blip_sample_t) s; - } - while ( ++offset ); - } - - set_integrator( reader_sum ); - - remove_samples( count ); - } - return count; -} - -void Blip_Buffer::mix_samples( blip_sample_t const in [], int count ) -{ - delta_t* out = buffer_center_ + (offset_ >> BLIP_BUFFER_ACCURACY); - - int const sample_shift = blip_sample_bits - 16; - int prev = 0; - while ( --count >= 0 ) - { - int s = *in++ << sample_shift; - *out += s - prev; - prev = s; - ++out; - } - *out -= prev; -} - -void Blip_Buffer::save_state( blip_buffer_state_t* out ) -{ - assert( samples_avail() == 0 ); - out->offset_ = offset_; - out->reader_accum_ = reader_accum_; - memcpy( out->buf, &buffer_ [offset_ >> BLIP_BUFFER_ACCURACY], sizeof out->buf ); -} - -void Blip_Buffer::load_state( blip_buffer_state_t const& in ) -{ - clear(); - - offset_ = in.offset_; - reader_accum_ = in.reader_accum_; - memcpy( buffer_, in.buf, sizeof in.buf ); -} - - -//// Blip_Synth_ - -Blip_Synth_Fast_::Blip_Synth_Fast_() -{ - buf = NULL; - last_amp = 0; - delta_factor = 0; -} - -void Blip_Synth_Fast_::volume_unit( double new_unit ) -{ - delta_factor = int (new_unit * (1 << blip_sample_bits) + 0.5); -} - -#if BLIP_BUFFER_FAST - -void blip_eq_t::generate( float* out, int count ) const { } - -#else - -Blip_Synth_::Blip_Synth_( short p [], int w ) : - phases( p ), - width( w ) -{ - volume_unit_ = 0.0; - kernel_unit = 0; - buf = NULL; - last_amp = 0; - delta_factor = 0; -} - -#undef PI -#define PI 3.1415926535897932384626433832795029 - -// Generates right half of sinc kernel (including center point) with cutoff at -// sample rate / 2 / oversample. Frequency response at cutoff frequency is -// treble dB (-6=0.5,-12=0.25). Mid controls frequency that rolloff begins at, -// cut * sample rate / 2. -static void gen_sinc( float out [], int out_size, double oversample, - double treble, double mid ) -{ - if ( mid > 0.9999 ) mid = 0.9999; - if ( treble < -300.0 ) treble = -300.0; - if ( treble > 5.0 ) treble = 5.0; - - double const maxh = 4096.0; - double rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - mid) ); - double const pow_a_n = pow( rolloff, maxh - maxh * mid ); - double const to_angle = PI / maxh / oversample; - for ( int i = 1; i < out_size; i++ ) - { - double angle = i * to_angle; - double c = rolloff * cos( angle * maxh - angle ) - - cos( angle * maxh ); - double cos_nc_angle = cos( angle * maxh * mid ); - double cos_nc1_angle = cos( angle * maxh * mid - angle ); - double cos_angle = cos( angle ); - - c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle; - double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle); - double b = 2.0 - cos_angle - cos_angle; - double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle; - - out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d - } - - // Approximate center by looking at two points to right. Much simpler - // and more reliable than trying to calculate it properly. - out [0] = out [1] + 0.5 * (out [1] - out [2]); -} - -// Gain is 1-2800 for beta of 0-10, instead of 1.0 as it should be, but -// this is corrected by normalization in treble_eq(). -static void kaiser_window( float io [], int count, float beta ) -{ - int const accuracy = 10; - - float const beta2 = beta * beta; - float const step = (float) 0.5 / count; - float pos = (float) 0.5; - for ( float* const end = io + count; io < end; ++io ) - { - float x = (pos - pos*pos) * beta2; - float u = x; - float k = 1; - float n = 2; - - // Keep refining until adjustment becomes small - do - { - u *= x / (n * n); - n += 1; - k += u; - } - while ( k <= u * (1 << accuracy) ); - - pos += step; - *io *= k; - } -} - -void blip_eq_t::generate( float out [], int count ) const -{ - // lower cutoff freq for narrow kernels with their wider transition band - // (8 points->1.49, 16 points->1.15) - double cutoff_adj = blip_res * 2.25 / count + 0.85; - if ( cutoff_adj < 1.02 ) - cutoff_adj = 1.02; - double half_rate = sample_rate * 0.5; - if ( cutoff_freq ) - cutoff_adj = half_rate / cutoff_freq; - double cutoff = rolloff_freq * cutoff_adj / half_rate; - - gen_sinc( out, count, oversample * cutoff_adj, treble, cutoff ); - - kaiser_window( out, count, kaiser ); -} - -void Blip_Synth_::treble_eq( blip_eq_t const& eq ) -{ - // Generate right half of kernel - int const half_size = blip_eq_t::calc_count( width ); - float fimpulse [blip_res / 2 * (BLIP_MAX_QUALITY - 1) + 1]; - eq.generate( fimpulse, half_size ); - - int i; - - // Find rescale factor. Summing from small to large (right to left) - // reduces error. - double total = 0.0; - for ( i = half_size; --i > 0; ) - total += fimpulse [i]; - total = total * 2.0 + fimpulse [0]; - - //double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB - //double const base_unit = 37888.0; // allows treble to +5 dB - double const base_unit = 32768.0; // necessary for blip_unscaled to work - double rescale = base_unit / total; - kernel_unit = (int) base_unit; - - // Integrate, first difference, rescale, convert to int - double sum = 0; - double next = 0; - int const size = impulses_size(); - for ( i = 0; i < size; i++ ) - { - int j = (half_size - 1) - i; - - if ( i >= blip_res ) - sum += fimpulse [j + blip_res]; - - // goes slightly past center, so it needs a little mirroring - next += fimpulse [j < 0 ? -j : j]; - - // calculate unintereleved index - int x = (~i & (blip_res - 1)) * (width >> 1) + (i >> BLIP_PHASE_BITS); - assert( (unsigned) x < (unsigned) size ); - - // flooring separately virtually eliminates error - phases [x] = (short) (int) - (floor( sum * rescale + 0.5 ) - floor( next * rescale + 0.5 )); - //phases [x] = (short) (int) - // floor( sum * rescale - next * rescale + 0.5 ); - } - - adjust_impulse(); - - // volume might require rescaling - double vol = volume_unit_; - if ( vol ) - { - volume_unit_ = 0.0; - volume_unit( vol ); - } -} - -void Blip_Synth_::adjust_impulse() -{ - int const size = impulses_size(); - int const half_width = width / 2; - - // Sum each phase as would be done when synthesizing, and correct - // any that don't add up to exactly kernel_half. - for ( int phase = blip_res / 2; --phase >= 0; ) - { - int const fwd = phase * half_width; - int const rev = size - half_width - fwd; - - int error = kernel_unit; - for ( int i = half_width; --i >= 0; ) - { - error += phases [fwd + i]; - error += phases [rev + i]; - } - phases [fwd + half_width - 1] -= (short) error; - - // Error shouldn't occur now with improved calculation - //if ( error ) printf( "error: %ld\n", error ); - } - - #if 0 - for ( int i = 0; i < blip_res; i++, printf( "\n" ) ) - for ( int j = 0; j < width / 2; j++ ) - printf( "%5d,", (int) -phases [j + width/2 * i] ); - #endif -} - -void Blip_Synth_::rescale_kernel( int shift ) -{ - // Keep values positive to avoid round-towards-zero of sign-preserving - // right shift for negative values. - int const keep_positive = 0x8000 + (1 << (shift - 1)); - - int const half_width = width / 2; - for ( int phase = blip_res; --phase >= 0; ) - { - int const fwd = phase * half_width; - - // Integrate, rescale, then differentiate again. - // If differences are rescaled directly, more error results. - int sum = keep_positive; - for ( int i = 0; i < half_width; i++ ) - { - int prev = sum; - sum += phases [fwd + i]; - phases [fwd + i] = (sum >> shift) - (prev >> shift); - } - } - - adjust_impulse(); -} - -void Blip_Synth_::volume_unit( double new_unit ) -{ - if ( volume_unit_ != new_unit ) - { - // use default eq if it hasn't been set yet - if ( !kernel_unit ) - treble_eq( -8.0 ); - - // Factor that kernel must be multiplied by - volume_unit_ = new_unit; - double factor = new_unit * (1 << blip_sample_bits) / kernel_unit; - - if ( factor > 0.0 ) - { - // If factor is low, reduce amplitude of kernel itself - int shift = 0; - while ( factor < 2.0 ) - { - shift++; - factor *= 2.0; - } - - if ( shift ) - { - kernel_unit >>= shift; - assert( kernel_unit > 0 ); // fails if volume unit is too low - - rescale_kernel( shift ); - } - } - - delta_factor = -(int) floor( factor + 0.5 ); - //printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit ); - } -} -#endif +// Blip_Buffer $vers. http://www.slack.net/~ant/ + +#include "Blip_Buffer.h" + +#include + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +//// Blip_Buffer + +Blip_Buffer::Blip_Buffer() +{ + factor_ = UINT_MAX/2 + 1; + buffer_ = NULL; + buffer_center_ = NULL; + buffer_size_ = 0; + sample_rate_ = 0; + bass_shift_ = 0; + clock_rate_ = 0; + bass_freq_ = 16; + length_ = 0; + + // assumptions code makes about implementation-defined features + #ifndef NDEBUG + // right shift of negative value preserves sign + int i = -0x7FFFFFFE; + assert( (i >> 1) == -0x3FFFFFFF ); + + // casting truncates and sign-extends + i = 0x18000; + assert( (BOOST::int16_t) i == -0x8000 ); + #endif + + clear(); +} + +Blip_Buffer::~Blip_Buffer() +{ + free( buffer_ ); +} + +void Blip_Buffer::clear() +{ + bool const entire_buffer = true; + + offset_ = 0; + reader_accum_ = 0; + modified_ = false; + + if ( buffer_ ) + { + int count = (entire_buffer ? buffer_size_ : samples_avail()); + memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (delta_t) ); + } +} + +blargg_err_t Blip_Buffer::set_sample_rate( int new_rate, int msec ) +{ + // Limit to maximum size that resampled time can represent + int max_size = (((blip_resampled_time_t) -1) >> BLIP_BUFFER_ACCURACY) - + blip_buffer_extra_ - 64; // TODO: -64 isn't needed + int new_size = (new_rate * (msec + 1) + 999) / 1000; + if ( new_size > max_size ) + new_size = max_size; + + // Resize buffer + if ( buffer_size_ != new_size ) + { + //dprintf( "%d \n", (new_size + blip_buffer_extra_) * sizeof *buffer_ ); + void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ ); + CHECK_ALLOC( p ); + buffer_ = (delta_t*) p; + buffer_center_ = buffer_ + BLIP_MAX_QUALITY/2; + buffer_size_ = new_size; + } + + // Update sample_rate and things that depend on it + sample_rate_ = new_rate; + length_ = new_size * 1000 / new_rate - 1; + if ( clock_rate_ ) + clock_rate( clock_rate_ ); + bass_freq( bass_freq_ ); + + clear(); + + return blargg_ok; +} + +blip_resampled_time_t Blip_Buffer::clock_rate_factor( int rate ) const +{ + double ratio = (double) sample_rate_ / rate; + int factor = (int) floor( ratio * (1 << BLIP_BUFFER_ACCURACY) + 0.5 ); + assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large + return (blip_resampled_time_t) factor; +} + +void Blip_Buffer::bass_freq( int freq ) +{ + bass_freq_ = freq; + int shift = 31; + if ( freq > 0 && sample_rate_ ) + { + shift = 13; + int f = (freq << 16) / sample_rate_; + while ( (f >>= 1) != 0 && --shift ) { } + } + bass_shift_ = shift; +} + +void Blip_Buffer::end_frame( blip_time_t t ) +{ + offset_ += t * factor_; + assert( samples_avail() <= (int) buffer_size_ ); // fails if time is past end of buffer +} + +int Blip_Buffer::count_samples( blip_time_t t ) const +{ + blip_resampled_time_t last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY; + blip_resampled_time_t first_sample = offset_ >> BLIP_BUFFER_ACCURACY; + return (int) (last_sample - first_sample); +} + +blip_time_t Blip_Buffer::count_clocks( int count ) const +{ + if ( count > buffer_size_ ) + count = buffer_size_; + blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; + return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_); +} + +void Blip_Buffer::remove_samples( int count ) +{ + if ( count ) + { + remove_silence( count ); + + // copy remaining samples to beginning and clear old samples + int remain = samples_avail() + blip_buffer_extra_; + memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ ); + memset( buffer_ + remain, 0, count * sizeof *buffer_ ); + } +} + +int Blip_Buffer::read_samples( blip_sample_t out_ [], int max_samples, bool stereo ) +{ + int count = samples_avail(); + if ( count > max_samples ) + count = max_samples; + + if ( count ) + { + int const bass = highpass_shift(); + delta_t const* reader = read_pos() + count; + int reader_sum = integrator(); + + blip_sample_t* BLARGG_RESTRICT out = out_ + count; + if ( stereo ) + out += count; + int offset = -count; + + if ( !stereo ) + { + do + { + int s = reader_sum >> delta_bits; + + reader_sum -= reader_sum >> bass; + reader_sum += reader [offset]; + + BLIP_CLAMP( s, s ); + out [offset] = (blip_sample_t) s; + } + while ( ++offset ); + } + else + { + do + { + int s = reader_sum >> delta_bits; + + reader_sum -= reader_sum >> bass; + reader_sum += reader [offset]; + + BLIP_CLAMP( s, s ); + out [offset * 2] = (blip_sample_t) s; + } + while ( ++offset ); + } + + set_integrator( reader_sum ); + + remove_samples( count ); + } + return count; +} + +void Blip_Buffer::mix_samples( blip_sample_t const in [], int count ) +{ + delta_t* out = buffer_center_ + (offset_ >> BLIP_BUFFER_ACCURACY); + + int const sample_shift = blip_sample_bits - 16; + int prev = 0; + while ( --count >= 0 ) + { + int s = *in++ << sample_shift; + *out += s - prev; + prev = s; + ++out; + } + *out -= prev; +} + +void Blip_Buffer::save_state( blip_buffer_state_t* out ) +{ + assert( samples_avail() == 0 ); + out->offset_ = offset_; + out->reader_accum_ = reader_accum_; + memcpy( out->buf, &buffer_ [offset_ >> BLIP_BUFFER_ACCURACY], sizeof out->buf ); +} + +void Blip_Buffer::load_state( blip_buffer_state_t const& in ) +{ + clear(); + + offset_ = in.offset_; + reader_accum_ = in.reader_accum_; + memcpy( buffer_, in.buf, sizeof in.buf ); +} + + +//// Blip_Synth_ + +Blip_Synth_Fast_::Blip_Synth_Fast_() +{ + buf = NULL; + last_amp = 0; + delta_factor = 0; +} + +void Blip_Synth_Fast_::volume_unit( double new_unit ) +{ + delta_factor = int (new_unit * (1 << blip_sample_bits) + 0.5); +} + +#if BLIP_BUFFER_FAST + +void blip_eq_t::generate( float* out, int count ) const { } + +#else + +Blip_Synth_::Blip_Synth_( short p [], int w ) : + phases( p ), + width( w ) +{ + volume_unit_ = 0.0; + kernel_unit = 0; + buf = NULL; + last_amp = 0; + delta_factor = 0; +} + +#undef PI +#define PI 3.1415926535897932384626433832795029 + +// Generates right half of sinc kernel (including center point) with cutoff at +// sample rate / 2 / oversample. Frequency response at cutoff frequency is +// treble dB (-6=0.5,-12=0.25). Mid controls frequency that rolloff begins at, +// cut * sample rate / 2. +static void gen_sinc( float out [], int out_size, double oversample, + double treble, double mid ) +{ + if ( mid > 0.9999 ) mid = 0.9999; + if ( treble < -300.0 ) treble = -300.0; + if ( treble > 5.0 ) treble = 5.0; + + double const maxh = 4096.0; + double rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - mid) ); + double const pow_a_n = pow( rolloff, maxh - maxh * mid ); + double const to_angle = PI / maxh / oversample; + for ( int i = 1; i < out_size; i++ ) + { + double angle = i * to_angle; + double c = rolloff * cos( angle * maxh - angle ) - + cos( angle * maxh ); + double cos_nc_angle = cos( angle * maxh * mid ); + double cos_nc1_angle = cos( angle * maxh * mid - angle ); + double cos_angle = cos( angle ); + + c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle; + double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle); + double b = 2.0 - cos_angle - cos_angle; + double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle; + + out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d + } + + // Approximate center by looking at two points to right. Much simpler + // and more reliable than trying to calculate it properly. + out [0] = out [1] + 0.5 * (out [1] - out [2]); +} + +// Gain is 1-2800 for beta of 0-10, instead of 1.0 as it should be, but +// this is corrected by normalization in treble_eq(). +static void kaiser_window( float io [], int count, float beta ) +{ + int const accuracy = 10; + + float const beta2 = beta * beta; + float const step = (float) 0.5 / count; + float pos = (float) 0.5; + for ( float* const end = io + count; io < end; ++io ) + { + float x = (pos - pos*pos) * beta2; + float u = x; + float k = 1; + float n = 2; + + // Keep refining until adjustment becomes small + do + { + u *= x / (n * n); + n += 1; + k += u; + } + while ( k <= u * (1 << accuracy) ); + + pos += step; + *io *= k; + } +} + +void blip_eq_t::generate( float out [], int count ) const +{ + // lower cutoff freq for narrow kernels with their wider transition band + // (8 points->1.49, 16 points->1.15) + double cutoff_adj = blip_res * 2.25 / count + 0.85; + if ( cutoff_adj < 1.02 ) + cutoff_adj = 1.02; + double half_rate = sample_rate * 0.5; + if ( cutoff_freq ) + cutoff_adj = half_rate / cutoff_freq; + double cutoff = rolloff_freq * cutoff_adj / half_rate; + + gen_sinc( out, count, oversample * cutoff_adj, treble, cutoff ); + + kaiser_window( out, count, kaiser ); +} + +void Blip_Synth_::treble_eq( blip_eq_t const& eq ) +{ + // Generate right half of kernel + int const half_size = blip_eq_t::calc_count( width ); + float fimpulse [blip_res / 2 * (BLIP_MAX_QUALITY - 1) + 1]; + eq.generate( fimpulse, half_size ); + + int i; + + // Find rescale factor. Summing from small to large (right to left) + // reduces error. + double total = 0.0; + for ( i = half_size; --i > 0; ) + total += fimpulse [i]; + total = total * 2.0 + fimpulse [0]; + + //double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB + //double const base_unit = 37888.0; // allows treble to +5 dB + double const base_unit = 32768.0; // necessary for blip_unscaled to work + double rescale = base_unit / total; + kernel_unit = (int) base_unit; + + // Integrate, first difference, rescale, convert to int + double sum = 0; + double next = 0; + int const size = impulses_size(); + for ( i = 0; i < size; i++ ) + { + int j = (half_size - 1) - i; + + if ( i >= blip_res ) + sum += fimpulse [j + blip_res]; + + // goes slightly past center, so it needs a little mirroring + next += fimpulse [j < 0 ? -j : j]; + + // calculate unintereleved index + int x = (~i & (blip_res - 1)) * (width >> 1) + (i >> BLIP_PHASE_BITS); + assert( (unsigned) x < (unsigned) size ); + + // flooring separately virtually eliminates error + phases [x] = (short) (int) + (floor( sum * rescale + 0.5 ) - floor( next * rescale + 0.5 )); + //phases [x] = (short) (int) + // floor( sum * rescale - next * rescale + 0.5 ); + } + + adjust_impulse(); + + // volume might require rescaling + double vol = volume_unit_; + if ( vol ) + { + volume_unit_ = 0.0; + volume_unit( vol ); + } +} + +void Blip_Synth_::adjust_impulse() +{ + int const size = impulses_size(); + int const half_width = width / 2; + + // Sum each phase as would be done when synthesizing, and correct + // any that don't add up to exactly kernel_half. + for ( int phase = blip_res / 2; --phase >= 0; ) + { + int const fwd = phase * half_width; + int const rev = size - half_width - fwd; + + int error = kernel_unit; + for ( int i = half_width; --i >= 0; ) + { + error += phases [fwd + i]; + error += phases [rev + i]; + } + phases [fwd + half_width - 1] -= (short) error; + + // Error shouldn't occur now with improved calculation + //if ( error ) printf( "error: %ld\n", error ); + } + + #if 0 + for ( int i = 0; i < blip_res; i++, printf( "\n" ) ) + for ( int j = 0; j < width / 2; j++ ) + printf( "%5d,", (int) -phases [j + width/2 * i] ); + #endif +} + +void Blip_Synth_::rescale_kernel( int shift ) +{ + // Keep values positive to avoid round-towards-zero of sign-preserving + // right shift for negative values. + int const keep_positive = 0x8000 + (1 << (shift - 1)); + + int const half_width = width / 2; + for ( int phase = blip_res; --phase >= 0; ) + { + int const fwd = phase * half_width; + + // Integrate, rescale, then differentiate again. + // If differences are rescaled directly, more error results. + int sum = keep_positive; + for ( int i = 0; i < half_width; i++ ) + { + int prev = sum; + sum += phases [fwd + i]; + phases [fwd + i] = (sum >> shift) - (prev >> shift); + } + } + + adjust_impulse(); +} + +void Blip_Synth_::volume_unit( double new_unit ) +{ + if ( volume_unit_ != new_unit ) + { + // use default eq if it hasn't been set yet + if ( !kernel_unit ) + treble_eq( -8.0 ); + + // Factor that kernel must be multiplied by + volume_unit_ = new_unit; + double factor = new_unit * (1 << blip_sample_bits) / kernel_unit; + + if ( factor > 0.0 ) + { + // If factor is low, reduce amplitude of kernel itself + int shift = 0; + while ( factor < 2.0 ) + { + shift++; + factor *= 2.0; + } + + if ( shift ) + { + kernel_unit >>= shift; + assert( kernel_unit > 0 ); // fails if volume unit is too low + + rescale_kernel( shift ); + } + } + + delta_factor = -(int) floor( factor + 0.5 ); + //printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit ); + } +} +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Blip_Buffer.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Blip_Buffer.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Blip_Buffer.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Blip_Buffer.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,198 +1,198 @@ -// Band-limited sound synthesis buffer - -// Blip_Buffer $vers -#ifndef BLIP_BUFFER_H -#define BLIP_BUFFER_H - -#include "blargg_common.h" -#include "Blip_Buffer_impl.h" - -typedef int blip_time_t; // Source clocks in current time frame -typedef BOOST::int16_t blip_sample_t; // 16-bit signed output sample -int const blip_default_length = 1000 / 4; // Default Blip_Buffer length (1/4 second) - - -//// Sample buffer for band-limited synthesis - -class Blip_Buffer : public Blip_Buffer_ { -public: - - // Sets output sample rate and resizes and clears sample buffer - blargg_err_t set_sample_rate( int samples_per_sec, int msec_length = blip_default_length ); - - // Sets number of source time units per second - void clock_rate( int clocks_per_sec ); - - // Clears buffer and removes all samples - void clear(); - - // Use Blip_Synth to add waveform to buffer - - // Resamples to time t, then subtracts t from current time. Appends result of resampling - // to buffer for reading. - void end_frame( blip_time_t t ); - - // Number of samples available for reading with read_samples() - int samples_avail() const; - - // Reads at most n samples to out [0 to n-1] and returns number actually read. If stereo - // is true, writes to out [0], out [2], out [4] etc. instead. - int read_samples( blip_sample_t out [], int n, bool stereo = false ); - -// More features - - // Sets flag that tells some Multi_Buffer types that sound was added to buffer, - // so they know that it needs to be mixed in. Only needs to be called once - // per time frame that sound was added. Not needed if not using Multi_Buffer. - void set_modified() { modified_ = true; } - - // Sets high-pass filter frequency, from 0 to 20000 Hz, where higher values reduce bass more - void bass_freq( int frequency ); - - int length() const; // Length of buffer in milliseconds - int sample_rate() const; // Current output sample rate - int clock_rate() const; // Number of source time units per second - int output_latency() const; // Number of samples delay from offset() to read_samples() - -// Low-level features - - // Removes the first n samples - void remove_samples( int n ); - - // Returns number of clocks needed until n samples will be available. - // If buffer cannot even hold n samples, returns number of clocks - // until buffer becomes full. - blip_time_t count_clocks( int n ) const; - - // Number of samples that should be mixed before calling end_frame( t ) - int count_samples( blip_time_t t ) const; - - // Mixes n samples into buffer - void mix_samples( const blip_sample_t in [], int n ); - -// Resampled time (sorry, poor documentation right now) - - // Resampled time is fixed-point, in terms of output samples. - - // Converts clock count to resampled time - blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; } - - // Converts clock time since beginning of current time frame to resampled time - blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; } - - // Returns factor that converts clock rate to resampled time - blip_resampled_time_t clock_rate_factor( int clock_rate ) const; - -// State save/load - - // Saves state, including high-pass filter and tails of last deltas. - // All samples must have been read from buffer before calling this - // (that is, samples_avail() must return 0). - void save_state( blip_buffer_state_t* out ); - - // Loads state. State must have been saved from Blip_Buffer with same - // settings during same run of program; states can NOT be stored on disk. - // Clears buffer before loading state. - void load_state( const blip_buffer_state_t& in ); - -private: - // noncopyable - Blip_Buffer( const Blip_Buffer& ); - Blip_Buffer& operator = ( const Blip_Buffer& ); - -// Implementation -public: - BLARGG_DISABLE_NOTHROW - Blip_Buffer(); - ~Blip_Buffer(); - void remove_silence( int n ); -}; - - -//// Adds amplitude changes to Blip_Buffer - -template class Blip_Synth; - -typedef Blip_Synth<8, 1> Blip_Synth_Fast; // faster, but less equalizer control -typedef Blip_Synth<12,1> Blip_Synth_Norm; // good for most things -typedef Blip_Synth<16,1> Blip_Synth_Good; // sharper filter cutoff - -template -class Blip_Synth { -public: - - // Sets volume of amplitude delta unit - void volume( double v ) { impl.volume_unit( 1.0 / range * v ); } - - // Configures low-pass filter - void treble_eq( const blip_eq_t& eq ) { impl.treble_eq( eq ); } - - // Gets/sets default Blip_Buffer - Blip_Buffer* output() const { return impl.buf; } - void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; } - - // Extends waveform to time t at current amplitude, then changes its amplitude to a - // Using this requires a separate Blip_Synth for each waveform. - void update( blip_time_t t, int a ); - -// Low-level interface - - // If no Blip_Buffer* is specified, uses one set by output() above - - // Adds amplitude transition at time t. Delta can be positive or negative. - // The actual change in amplitude is delta * volume. - void offset( blip_time_t t, int delta, Blip_Buffer* ) const; - void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); } - - // Same as offset(), except code is inlined for higher performance - void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const { offset_resampled( buf->to_fixed( t ), delta, buf ); } - void offset_inline( blip_time_t t, int delta ) const { offset_resampled( impl.buf->to_fixed( t ), delta, impl.buf ); } - - // Works directly in terms of fractional output samples. Use resampled time functions in Blip_Buffer - // to convert clock counts to resampled time. - void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const; - -// Implementation -public: - BLARGG_DISABLE_NOTHROW - -private: -#if BLIP_BUFFER_FAST - Blip_Synth_Fast_ impl; - typedef char coeff_t; -#else - Blip_Synth_ impl; - typedef short coeff_t; - // Left halves of first difference of step response for each possible phase - coeff_t phases [quality / 2 * blip_res]; -public: - Blip_Synth() : impl( phases, quality ) { } -#endif -}; - - -//// Low-pass equalization parameters - -class blip_eq_t { - double treble, kaiser; - int rolloff_freq, sample_rate, cutoff_freq; -public: - // Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce - // treble, small positive values (0 to 5.0) increase treble. - blip_eq_t( double treble_db = 0 ); - - // See blip_buffer.txt - blip_eq_t( double treble, int rolloff_freq, int sample_rate, int cutoff_freq = 0, - double kaiser = 5.2 ); - - // Generate center point and right half of impulse response - virtual void generate( float out [], int count ) const; - virtual ~blip_eq_t() { } - - enum { oversample = blip_res }; - static int calc_count( int quality ) { return (quality - 1) * (oversample / 2) + 1; } -}; - -#include "Blip_Buffer_impl2.h" - -#endif +// Band-limited sound synthesis buffer + +// Blip_Buffer $vers +#ifndef BLIP_BUFFER_H +#define BLIP_BUFFER_H + +#include "blargg_common.h" +#include "Blip_Buffer_impl.h" + +typedef int blip_time_t; // Source clocks in current time frame +typedef BOOST::int16_t blip_sample_t; // 16-bit signed output sample +int const blip_default_length = 1000 / 4; // Default Blip_Buffer length (1/4 second) + + +//// Sample buffer for band-limited synthesis + +class Blip_Buffer : public Blip_Buffer_ { +public: + + // Sets output sample rate and resizes and clears sample buffer + blargg_err_t set_sample_rate( int samples_per_sec, int msec_length = blip_default_length ); + + // Sets number of source time units per second + void clock_rate( int clocks_per_sec ); + + // Clears buffer and removes all samples + void clear(); + + // Use Blip_Synth to add waveform to buffer + + // Resamples to time t, then subtracts t from current time. Appends result of resampling + // to buffer for reading. + void end_frame( blip_time_t t ); + + // Number of samples available for reading with read_samples() + int samples_avail() const; + + // Reads at most n samples to out [0 to n-1] and returns number actually read. If stereo + // is true, writes to out [0], out [2], out [4] etc. instead. + int read_samples( blip_sample_t out [], int n, bool stereo = false ); + +// More features + + // Sets flag that tells some Multi_Buffer types that sound was added to buffer, + // so they know that it needs to be mixed in. Only needs to be called once + // per time frame that sound was added. Not needed if not using Multi_Buffer. + void set_modified() { modified_ = true; } + + // Sets high-pass filter frequency, from 0 to 20000 Hz, where higher values reduce bass more + void bass_freq( int frequency ); + + int length() const; // Length of buffer in milliseconds + int sample_rate() const; // Current output sample rate + int clock_rate() const; // Number of source time units per second + int output_latency() const; // Number of samples delay from offset() to read_samples() + +// Low-level features + + // Removes the first n samples + void remove_samples( int n ); + + // Returns number of clocks needed until n samples will be available. + // If buffer cannot even hold n samples, returns number of clocks + // until buffer becomes full. + blip_time_t count_clocks( int n ) const; + + // Number of samples that should be mixed before calling end_frame( t ) + int count_samples( blip_time_t t ) const; + + // Mixes n samples into buffer + void mix_samples( const blip_sample_t in [], int n ); + +// Resampled time (sorry, poor documentation right now) + + // Resampled time is fixed-point, in terms of output samples. + + // Converts clock count to resampled time + blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; } + + // Converts clock time since beginning of current time frame to resampled time + blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; } + + // Returns factor that converts clock rate to resampled time + blip_resampled_time_t clock_rate_factor( int clock_rate ) const; + +// State save/load + + // Saves state, including high-pass filter and tails of last deltas. + // All samples must have been read from buffer before calling this + // (that is, samples_avail() must return 0). + void save_state( blip_buffer_state_t* out ); + + // Loads state. State must have been saved from Blip_Buffer with same + // settings during same run of program; states can NOT be stored on disk. + // Clears buffer before loading state. + void load_state( const blip_buffer_state_t& in ); + +private: + // noncopyable + Blip_Buffer( const Blip_Buffer& ); + Blip_Buffer& operator = ( const Blip_Buffer& ); + +// Implementation +public: + BLARGG_DISABLE_NOTHROW + Blip_Buffer(); + ~Blip_Buffer(); + void remove_silence( int n ); +}; + + +//// Adds amplitude changes to Blip_Buffer + +template class Blip_Synth; + +typedef Blip_Synth<8, 1> Blip_Synth_Fast; // faster, but less equalizer control +typedef Blip_Synth<12,1> Blip_Synth_Norm; // good for most things +typedef Blip_Synth<16,1> Blip_Synth_Good; // sharper filter cutoff + +template +class Blip_Synth { +public: + + // Sets volume of amplitude delta unit + void volume( double v ) { impl.volume_unit( 1.0 / range * v ); } + + // Configures low-pass filter + void treble_eq( const blip_eq_t& eq ) { impl.treble_eq( eq ); } + + // Gets/sets default Blip_Buffer + Blip_Buffer* output() const { return impl.buf; } + void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; } + + // Extends waveform to time t at current amplitude, then changes its amplitude to a + // Using this requires a separate Blip_Synth for each waveform. + void update( blip_time_t t, int a ); + +// Low-level interface + + // If no Blip_Buffer* is specified, uses one set by output() above + + // Adds amplitude transition at time t. Delta can be positive or negative. + // The actual change in amplitude is delta * volume. + void offset( blip_time_t t, int delta, Blip_Buffer* ) const; + void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); } + + // Same as offset(), except code is inlined for higher performance + void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const { offset_resampled( buf->to_fixed( t ), delta, buf ); } + void offset_inline( blip_time_t t, int delta ) const { offset_resampled( impl.buf->to_fixed( t ), delta, impl.buf ); } + + // Works directly in terms of fractional output samples. Use resampled time functions in Blip_Buffer + // to convert clock counts to resampled time. + void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const; + +// Implementation +public: + BLARGG_DISABLE_NOTHROW + +private: +#if BLIP_BUFFER_FAST + Blip_Synth_Fast_ impl; + typedef char coeff_t; +#else + Blip_Synth_ impl; + typedef short coeff_t; + // Left halves of first difference of step response for each possible phase + coeff_t phases [quality / 2 * blip_res]; +public: + Blip_Synth() : impl( phases, quality ) { } +#endif +}; + + +//// Low-pass equalization parameters + +class blip_eq_t { + double treble, kaiser; + int rolloff_freq, sample_rate, cutoff_freq; +public: + // Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce + // treble, small positive values (0 to 5.0) increase treble. + blip_eq_t( double treble_db = 0 ); + + // See blip_buffer.txt + blip_eq_t( double treble, int rolloff_freq, int sample_rate, int cutoff_freq = 0, + double kaiser = 5.2 ); + + // Generate center point and right half of impulse response + virtual void generate( float out [], int count ) const; + virtual ~blip_eq_t() { } + + enum { oversample = blip_res }; + static int calc_count( int quality ) { return (quality - 1) * (oversample / 2) + 1; } +}; + +#include "Blip_Buffer_impl2.h" + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Blip_Buffer_impl2.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Blip_Buffer_impl2.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Blip_Buffer_impl2.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Blip_Buffer_impl2.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,282 +1,282 @@ -// Internal stuff here to keep public header uncluttered - -// Blip_Buffer $vers -#ifndef BLIP_BUFFER_IMPL2_H -#define BLIP_BUFFER_IMPL2_H - -//// Compatibility - -BLARGG_DEPRECATED( int const blip_low_quality = 8; ) -BLARGG_DEPRECATED( int const blip_med_quality = 8; ) -BLARGG_DEPRECATED( int const blip_good_quality = 12; ) -BLARGG_DEPRECATED( int const blip_high_quality = 16; ) - -BLARGG_DEPRECATED( int const blip_sample_max = 32767; ) - -// Number of bits in raw sample that covers normal output range. Less than 32 bits to give -// extra amplitude range. That is, -// +1 << (blip_sample_bits-1) = +1.0 -// -1 << (blip_sample_bits-1) = -1.0 -int const blip_sample_bits = 30; - -//// BLIP_READER_ - -//// Optimized reading from Blip_Buffer, for use in custom sample buffer or mixer - -// Begins reading from buffer. Name should be unique to the current {} block. -#define BLIP_READER_BEGIN( name, blip_buffer ) \ - const Blip_Buffer::delta_t* BLARGG_RESTRICT name##_reader_buf = (blip_buffer).read_pos();\ - int name##_reader_accum = (blip_buffer).integrator() - -// Gets value to pass to BLIP_READER_NEXT() -#define BLIP_READER_BASS( blip_buffer ) (blip_buffer).highpass_shift() - -// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal -// code at the cost of having no bass_freq() functionality -int const blip_reader_default_bass = 9; - -// Current sample as 16-bit signed value -#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16)) - -// Current raw sample in full internal resolution -#define BLIP_READER_READ_RAW( name ) (name##_reader_accum) - -// Advances to next sample -#define BLIP_READER_NEXT( name, bass ) \ - (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass))) - -// Ends reading samples from buffer. The number of samples read must now be removed -// using Blip_Buffer::remove_samples(). -#define BLIP_READER_END( name, blip_buffer ) \ - (void) ((blip_buffer).set_integrator( name##_reader_accum )) - -#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset) - -int const blip_reader_idx_factor = sizeof (Blip_Buffer::delta_t); - -#define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\ - name##_reader_accum -= name##_reader_accum >> (bass);\ - name##_reader_accum += name##_reader_buf [(idx)];\ -} - -#define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\ - name##_reader_accum -= name##_reader_accum >> (bass);\ - name##_reader_accum +=\ - *(Blip_Buffer::delta_t const*) ((char const*) name##_reader_buf + (idx));\ -} - -//// BLIP_CLAMP - -#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ - defined (__x86_64__) || defined (__ia64__) || defined (__i386__) - #define BLIP_X86 1 - #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in -#else - #define BLIP_CLAMP_( in ) (blip_sample_t) in != in -#endif - -// Clamp sample to blip_sample_t range -#define BLIP_CLAMP( sample, out )\ - { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 31) ^ 0x7FFF; } - - -//// Blip_Synth - -// (in >> sh & mask) * mul -#define BLIP_SH_AND_MUL( in, sh, mask, mul ) \ -((int) (in) / ((1U << (sh)) / (mul)) & (unsigned) ((mask) * (mul))) - -// (T*) ptr + (off >> sh) -#define BLIP_PTR_OFF_SH( T, ptr, off, sh ) \ - ((T*) (BLIP_SH_AND_MUL( off, sh, -1, sizeof (T) ) + (char*) (ptr))) - -template -inline void Blip_Synth::offset_resampled( blip_resampled_time_t time, - int delta, Blip_Buffer* blip_buf ) const -{ -#if BLIP_BUFFER_FAST - int const half_width = 1; -#else - int const half_width = quality / 2; -#endif - - Blip_Buffer::delta_t* BLARGG_RESTRICT buf = blip_buf->delta_at( time ); - - delta *= impl.delta_factor; - - int const phase_shift = BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS; - int const phase = (half_width & (half_width - 1)) ? - (int) BLIP_SH_AND_MUL( time, phase_shift, blip_res - 1, sizeof (coeff_t) ) * half_width : - (int) BLIP_SH_AND_MUL( time, phase_shift, blip_res - 1, sizeof (coeff_t) * half_width ); - -#if BLIP_BUFFER_FAST - int left = buf [0] + delta; - - // Kind of crappy, but doing shift after multiply results in overflow. - // Alternate way of delaying multiply by delta_factor results in worse - // sub-sample resolution. - int right = (delta >> BLIP_PHASE_BITS) * phase; - #if BLIP_BUFFER_NOINTERP - // TODO: remove? (just a hack to see how it sounds) - right = 0; - #endif - left -= right; - right += buf [1]; - - buf [0] = left; - buf [1] = right; -#else - - int const fwd = -quality / 2; - int const rev = fwd + quality - 2; - - coeff_t const* BLARGG_RESTRICT imp = (coeff_t const*) ((char const*) phases + phase); - int const phase2 = phase + phase - (blip_res - 1) * half_width * sizeof (coeff_t); - - #define BLIP_MID_IMP imp = (coeff_t const*) ((char const*) imp - phase2); - - #if BLIP_MAX_QUALITY > 16 - // General version for any quality - if ( quality != 8 && quality != 12 && quality != 16 ) - { - buf += fwd; - - // left half - for ( int n = half_width / 2; --n >= 0; ) - { - buf [0] += imp [0] * delta; - buf [1] += imp [1] * delta; - imp += 2; - buf += 2; - } - - // mirrored right half - BLIP_MID_IMP - for ( int n = half_width / 2; --n >= 0; ) - { - buf [0] += imp [-1] * delta; - buf [1] += *(imp -= 2) * delta; - buf += 2; - } - - return; - } - #endif - - // Unrolled versions for qualities 8, 12, and 16 - - #if BLIP_X86 - // This gives better code for x86 - #define BLIP_ADD( out, in ) \ - buf [out] += imp [in] * delta - - #define BLIP_FWD( i ) {\ - BLIP_ADD( fwd + i, i );\ - BLIP_ADD( fwd + 1 + i, i + 1 );\ - } - - #define BLIP_REV( r ) {\ - BLIP_ADD( rev - r, r + 1 );\ - BLIP_ADD( rev + 1 - r, r );\ - } - - BLIP_FWD( 0 ) - BLIP_FWD( 2 ) - if ( quality > 8 ) BLIP_FWD( 4 ) - if ( quality > 12 ) BLIP_FWD( 6 ) - BLIP_MID_IMP - if ( quality > 12 ) BLIP_REV( 6 ) - if ( quality > 8 ) BLIP_REV( 4 ) - BLIP_REV( 2 ) - BLIP_REV( 0 ) - - #else - // Help RISC processors and simplistic compilers by reading ahead of writes - #define BLIP_FWD( i ) {\ - int t0 = i0 * delta + buf [fwd + i];\ - int t1 = imp [i + 1] * delta + buf [fwd + 1 + i];\ - i0 = imp [i + 2];\ - buf [fwd + i] = t0;\ - buf [fwd + 1 + i] = t1;\ - } - - #define BLIP_REV( r ) {\ - int t0 = i0 * delta + buf [rev - r];\ - int t1 = imp [r] * delta + buf [rev + 1 - r];\ - i0 = imp [r - 1];\ - buf [rev - r] = t0;\ - buf [rev + 1 - r] = t1;\ - } - - int i0 = *imp; - BLIP_FWD( 0 ) - if ( quality > 8 ) BLIP_FWD( 2 ) - if ( quality > 12 ) BLIP_FWD( 4 ) - { - int const mid = half_width - 1; - int t0 = i0 * delta + buf [fwd + mid - 1]; - int t1 = imp [mid] * delta + buf [fwd + mid ]; - BLIP_MID_IMP - i0 = imp [mid]; - buf [fwd + mid - 1] = t0; - buf [fwd + mid ] = t1; - } - if ( quality > 12 ) BLIP_REV( 6 ) - if ( quality > 8 ) BLIP_REV( 4 ) - BLIP_REV( 2 ) - - int t0 = i0 * delta + buf [rev ]; - int t1 = *imp * delta + buf [rev + 1]; - buf [rev ] = t0; - buf [rev + 1] = t1; - #endif - -#endif -} - -template -#if BLIP_BUFFER_FAST - inline -#endif -void Blip_Synth::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const -{ - offset_resampled( buf->to_fixed( t ), delta, buf ); -} - -template -#if BLIP_BUFFER_FAST - inline -#endif -void Blip_Synth::update( blip_time_t t, int amp ) -{ - int delta = amp - impl.last_amp; - impl.last_amp = amp; - offset_resampled( impl.buf->to_fixed( t ), delta, impl.buf ); -} - - -//// blip_eq_t - -inline blip_eq_t::blip_eq_t( double t ) : - treble( t ), kaiser( 5.2 ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { } -inline blip_eq_t::blip_eq_t( double t, int rf, int sr, int cf, double k ) : - treble( t ), kaiser( k ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { } - - -//// Blip_Buffer - -inline int Blip_Buffer::length() const { return length_; } -inline int Blip_Buffer::samples_avail() const { return (int) (offset_ >> BLIP_BUFFER_ACCURACY); } -inline int Blip_Buffer::sample_rate() const { return sample_rate_; } -inline int Blip_Buffer::output_latency() const { return BLIP_MAX_QUALITY / 2; } -inline int Blip_Buffer::clock_rate() const { return clock_rate_; } -inline void Blip_Buffer::clock_rate( int cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); } - -inline void Blip_Buffer::remove_silence( int count ) -{ - // fails if you try to remove more samples than available - assert( count <= samples_avail() ); - offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; -} - -#endif +// Internal stuff here to keep public header uncluttered + +// Blip_Buffer $vers +#ifndef BLIP_BUFFER_IMPL2_H +#define BLIP_BUFFER_IMPL2_H + +//// Compatibility + +BLARGG_DEPRECATED( int const blip_low_quality = 8; ) +BLARGG_DEPRECATED( int const blip_med_quality = 8; ) +BLARGG_DEPRECATED( int const blip_good_quality = 12; ) +BLARGG_DEPRECATED( int const blip_high_quality = 16; ) + +BLARGG_DEPRECATED( int const blip_sample_max = 32767; ) + +// Number of bits in raw sample that covers normal output range. Less than 32 bits to give +// extra amplitude range. That is, +// +1 << (blip_sample_bits-1) = +1.0 +// -1 << (blip_sample_bits-1) = -1.0 +int const blip_sample_bits = 30; + +//// BLIP_READER_ + +//// Optimized reading from Blip_Buffer, for use in custom sample buffer or mixer + +// Begins reading from buffer. Name should be unique to the current {} block. +#define BLIP_READER_BEGIN( name, blip_buffer ) \ + const Blip_Buffer::delta_t* BLARGG_RESTRICT name##_reader_buf = (blip_buffer).read_pos();\ + int name##_reader_accum = (blip_buffer).integrator() + +// Gets value to pass to BLIP_READER_NEXT() +#define BLIP_READER_BASS( blip_buffer ) (blip_buffer).highpass_shift() + +// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal +// code at the cost of having no bass_freq() functionality +int const blip_reader_default_bass = 9; + +// Current sample as 16-bit signed value +#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16)) + +// Current raw sample in full internal resolution +#define BLIP_READER_READ_RAW( name ) (name##_reader_accum) + +// Advances to next sample +#define BLIP_READER_NEXT( name, bass ) \ + (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass))) + +// Ends reading samples from buffer. The number of samples read must now be removed +// using Blip_Buffer::remove_samples(). +#define BLIP_READER_END( name, blip_buffer ) \ + (void) ((blip_buffer).set_integrator( name##_reader_accum )) + +#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset) + +int const blip_reader_idx_factor = sizeof (Blip_Buffer::delta_t); + +#define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\ + name##_reader_accum -= name##_reader_accum >> (bass);\ + name##_reader_accum += name##_reader_buf [(idx)];\ +} + +#define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\ + name##_reader_accum -= name##_reader_accum >> (bass);\ + name##_reader_accum +=\ + *(Blip_Buffer::delta_t const*) ((char const*) name##_reader_buf + (idx));\ +} + +//// BLIP_CLAMP + +#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ + defined (__x86_64__) || defined (__ia64__) || defined (__i386__) + #define BLIP_X86 1 + #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in +#else + #define BLIP_CLAMP_( in ) (blip_sample_t) in != in +#endif + +// Clamp sample to blip_sample_t range +#define BLIP_CLAMP( sample, out )\ + { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 31) ^ 0x7FFF; } + + +//// Blip_Synth + +// (in >> sh & mask) * mul +#define BLIP_SH_AND_MUL( in, sh, mask, mul ) \ +((int) (in) / ((1U << (sh)) / (mul)) & (unsigned) ((mask) * (mul))) + +// (T*) ptr + (off >> sh) +#define BLIP_PTR_OFF_SH( T, ptr, off, sh ) \ + ((T*) (BLIP_SH_AND_MUL( off, sh, -1, sizeof (T) ) + (char*) (ptr))) + +template +inline void Blip_Synth::offset_resampled( blip_resampled_time_t time, + int delta, Blip_Buffer* blip_buf ) const +{ +#if BLIP_BUFFER_FAST + int const half_width = 1; +#else + int const half_width = quality / 2; +#endif + + Blip_Buffer::delta_t* BLARGG_RESTRICT buf = blip_buf->delta_at( time ); + + delta *= impl.delta_factor; + + int const phase_shift = BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS; + int const phase = (half_width & (half_width - 1)) ? + (int) BLIP_SH_AND_MUL( time, phase_shift, blip_res - 1, sizeof (coeff_t) ) * half_width : + (int) BLIP_SH_AND_MUL( time, phase_shift, blip_res - 1, sizeof (coeff_t) * half_width ); + +#if BLIP_BUFFER_FAST + int left = buf [0] + delta; + + // Kind of crappy, but doing shift after multiply results in overflow. + // Alternate way of delaying multiply by delta_factor results in worse + // sub-sample resolution. + int right = (delta >> BLIP_PHASE_BITS) * phase; + #if BLIP_BUFFER_NOINTERP + // TODO: remove? (just a hack to see how it sounds) + right = 0; + #endif + left -= right; + right += buf [1]; + + buf [0] = left; + buf [1] = right; +#else + + int const fwd = -quality / 2; + int const rev = fwd + quality - 2; + + coeff_t const* BLARGG_RESTRICT imp = (coeff_t const*) ((char const*) phases + phase); + int const phase2 = phase + phase - (blip_res - 1) * half_width * sizeof (coeff_t); + + #define BLIP_MID_IMP imp = (coeff_t const*) ((char const*) imp - phase2); + + #if BLIP_MAX_QUALITY > 16 + // General version for any quality + if ( quality != 8 && quality != 12 && quality != 16 ) + { + buf += fwd; + + // left half + for ( int n = half_width / 2; --n >= 0; ) + { + buf [0] += imp [0] * delta; + buf [1] += imp [1] * delta; + imp += 2; + buf += 2; + } + + // mirrored right half + BLIP_MID_IMP + for ( int n = half_width / 2; --n >= 0; ) + { + buf [0] += imp [-1] * delta; + buf [1] += *(imp -= 2) * delta; + buf += 2; + } + + return; + } + #endif + + // Unrolled versions for qualities 8, 12, and 16 + + #if BLIP_X86 + // This gives better code for x86 + #define BLIP_ADD( out, in ) \ + buf [out] += imp [in] * delta + + #define BLIP_FWD( i ) {\ + BLIP_ADD( fwd + i, i );\ + BLIP_ADD( fwd + 1 + i, i + 1 );\ + } + + #define BLIP_REV( r ) {\ + BLIP_ADD( rev - r, r + 1 );\ + BLIP_ADD( rev + 1 - r, r );\ + } + + BLIP_FWD( 0 ) + BLIP_FWD( 2 ) + if ( quality > 8 ) BLIP_FWD( 4 ) + if ( quality > 12 ) BLIP_FWD( 6 ) + BLIP_MID_IMP + if ( quality > 12 ) BLIP_REV( 6 ) + if ( quality > 8 ) BLIP_REV( 4 ) + BLIP_REV( 2 ) + BLIP_REV( 0 ) + + #else + // Help RISC processors and simplistic compilers by reading ahead of writes + #define BLIP_FWD( i ) {\ + int t0 = i0 * delta + buf [fwd + i];\ + int t1 = imp [i + 1] * delta + buf [fwd + 1 + i];\ + i0 = imp [i + 2];\ + buf [fwd + i] = t0;\ + buf [fwd + 1 + i] = t1;\ + } + + #define BLIP_REV( r ) {\ + int t0 = i0 * delta + buf [rev - r];\ + int t1 = imp [r] * delta + buf [rev + 1 - r];\ + i0 = imp [r - 1];\ + buf [rev - r] = t0;\ + buf [rev + 1 - r] = t1;\ + } + + int i0 = *imp; + BLIP_FWD( 0 ) + if ( quality > 8 ) BLIP_FWD( 2 ) + if ( quality > 12 ) BLIP_FWD( 4 ) + { + int const mid = half_width - 1; + int t0 = i0 * delta + buf [fwd + mid - 1]; + int t1 = imp [mid] * delta + buf [fwd + mid ]; + BLIP_MID_IMP + i0 = imp [mid]; + buf [fwd + mid - 1] = t0; + buf [fwd + mid ] = t1; + } + if ( quality > 12 ) BLIP_REV( 6 ) + if ( quality > 8 ) BLIP_REV( 4 ) + BLIP_REV( 2 ) + + int t0 = i0 * delta + buf [rev ]; + int t1 = *imp * delta + buf [rev + 1]; + buf [rev ] = t0; + buf [rev + 1] = t1; + #endif + +#endif +} + +template +#if BLIP_BUFFER_FAST + inline +#endif +void Blip_Synth::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const +{ + offset_resampled( buf->to_fixed( t ), delta, buf ); +} + +template +#if BLIP_BUFFER_FAST + inline +#endif +void Blip_Synth::update( blip_time_t t, int amp ) +{ + int delta = amp - impl.last_amp; + impl.last_amp = amp; + offset_resampled( impl.buf->to_fixed( t ), delta, impl.buf ); +} + + +//// blip_eq_t + +inline blip_eq_t::blip_eq_t( double t ) : + treble( t ), kaiser( 5.2 ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { } +inline blip_eq_t::blip_eq_t( double t, int rf, int sr, int cf, double k ) : + treble( t ), kaiser( k ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { } + + +//// Blip_Buffer + +inline int Blip_Buffer::length() const { return length_; } +inline int Blip_Buffer::samples_avail() const { return (int) (offset_ >> BLIP_BUFFER_ACCURACY); } +inline int Blip_Buffer::sample_rate() const { return sample_rate_; } +inline int Blip_Buffer::output_latency() const { return BLIP_MAX_QUALITY / 2; } +inline int Blip_Buffer::clock_rate() const { return clock_rate_; } +inline void Blip_Buffer::clock_rate( int cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); } + +inline void Blip_Buffer::remove_silence( int count ) +{ + // fails if you try to remove more samples than available + assert( count <= samples_avail() ); + offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; +} + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Blip_Buffer_impl.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Blip_Buffer_impl.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Blip_Buffer_impl.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Blip_Buffer_impl.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,135 +1,135 @@ -// Internal stuff here to keep public header uncluttered - -// Blip_Buffer $vers -#ifndef BLIP_BUFFER_IMPL_H -#define BLIP_BUFFER_IMPL_H - -typedef unsigned blip_resampled_time_t; - -#ifndef BLIP_MAX_QUALITY - #define BLIP_MAX_QUALITY 32 -#endif - -#ifndef BLIP_BUFFER_ACCURACY - #define BLIP_BUFFER_ACCURACY 16 -#endif - -#ifndef BLIP_PHASE_BITS - #define BLIP_PHASE_BITS 6 -#endif - -class blip_eq_t; -class Blip_Buffer; - -#if BLIP_BUFFER_FAST - // linear interpolation needs 8 bits - #undef BLIP_PHASE_BITS - #define BLIP_PHASE_BITS 8 - - #undef BLIP_MAX_QUALITY - #define BLIP_MAX_QUALITY 2 -#endif - -int const blip_res = 1 << BLIP_PHASE_BITS; -int const blip_buffer_extra_ = BLIP_MAX_QUALITY + 2; - -class Blip_Buffer_ { -public: -// Writer - - typedef int clocks_t; - - // Properties of fixed-point sample position - typedef unsigned fixed_t; // unsigned for more range, optimized shifts - enum { fixed_bits = BLIP_BUFFER_ACCURACY }; // bits in fraction - enum { fixed_unit = 1 << fixed_bits }; // 1.0 samples - - // Converts clock count to fixed-point sample position - fixed_t to_fixed( clocks_t t ) const { return t * factor_ + offset_; } - - // Deltas in buffer are fixed-point with this many fraction bits. - // Less than 16 for extra range. - enum { delta_bits = 14 }; - - // Pointer to first committed delta sample - typedef int delta_t; - - // Pointer to delta corresponding to fixed-point sample position - delta_t* delta_at( fixed_t ); - -// Reader - - delta_t* read_pos() { return buffer_; } - - void clear_modified() { modified_ = false; } - int highpass_shift() const { return bass_shift_; } - int integrator() const { return reader_accum_; } - void set_integrator( int n ) { reader_accum_ = n; } - -public: //friend class Tracked_Blip_Buffer; private: - bool modified() const { return modified_; } - void remove_silence( int count ); - -private: - unsigned factor_; - fixed_t offset_; - delta_t* buffer_center_; - int buffer_size_; - int reader_accum_; - int bass_shift_; - delta_t* buffer_; - int sample_rate_; - int clock_rate_; - int bass_freq_; - int length_; - bool modified_; - - friend class Blip_Buffer; -}; - -class Blip_Synth_Fast_ { -public: - int delta_factor; - int last_amp; - Blip_Buffer* buf; - - void volume_unit( double ); - void treble_eq( blip_eq_t const& ) { } - Blip_Synth_Fast_(); -}; - -class Blip_Synth_ { -public: - int delta_factor; - int last_amp; - Blip_Buffer* buf; - - void volume_unit( double ); - void treble_eq( blip_eq_t const& ); - Blip_Synth_( short phases [], int width ); -private: - double volume_unit_; - short* const phases; - int const width; - int kernel_unit; - - void adjust_impulse(); - void rescale_kernel( int shift ); - int impulses_size() const { return blip_res / 2 * width; } -}; - -class blip_buffer_state_t -{ - blip_resampled_time_t offset_; - int reader_accum_; - int buf [blip_buffer_extra_]; - friend class Blip_Buffer; -}; - -inline Blip_Buffer_::delta_t* Blip_Buffer_::delta_at( fixed_t f ) -{ - assert( (f >> fixed_bits) < (unsigned) buffer_size_ ); - return buffer_center_ + (f >> fixed_bits); -} - -#endif +// Internal stuff here to keep public header uncluttered + +// Blip_Buffer $vers +#ifndef BLIP_BUFFER_IMPL_H +#define BLIP_BUFFER_IMPL_H + +typedef unsigned blip_resampled_time_t; + +#ifndef BLIP_MAX_QUALITY + #define BLIP_MAX_QUALITY 32 +#endif + +#ifndef BLIP_BUFFER_ACCURACY + #define BLIP_BUFFER_ACCURACY 16 +#endif + +#ifndef BLIP_PHASE_BITS + #define BLIP_PHASE_BITS 6 +#endif + +class blip_eq_t; +class Blip_Buffer; + +#if BLIP_BUFFER_FAST + // linear interpolation needs 8 bits + #undef BLIP_PHASE_BITS + #define BLIP_PHASE_BITS 8 + + #undef BLIP_MAX_QUALITY + #define BLIP_MAX_QUALITY 2 +#endif + +int const blip_res = 1 << BLIP_PHASE_BITS; +int const blip_buffer_extra_ = BLIP_MAX_QUALITY + 2; + +class Blip_Buffer_ { +public: +// Writer + + typedef int clocks_t; + + // Properties of fixed-point sample position + typedef unsigned fixed_t; // unsigned for more range, optimized shifts + enum { fixed_bits = BLIP_BUFFER_ACCURACY }; // bits in fraction + enum { fixed_unit = 1 << fixed_bits }; // 1.0 samples + + // Converts clock count to fixed-point sample position + fixed_t to_fixed( clocks_t t ) const { return t * factor_ + offset_; } + + // Deltas in buffer are fixed-point with this many fraction bits. + // Less than 16 for extra range. + enum { delta_bits = 14 }; + + // Pointer to first committed delta sample + typedef int delta_t; + + // Pointer to delta corresponding to fixed-point sample position + delta_t* delta_at( fixed_t ); + +// Reader + + delta_t* read_pos() { return buffer_; } + + void clear_modified() { modified_ = false; } + int highpass_shift() const { return bass_shift_; } + int integrator() const { return reader_accum_; } + void set_integrator( int n ) { reader_accum_ = n; } + +public: //friend class Tracked_Blip_Buffer; private: + bool modified() const { return modified_; } + void remove_silence( int count ); + +private: + unsigned factor_; + fixed_t offset_; + delta_t* buffer_center_; + int buffer_size_; + int reader_accum_; + int bass_shift_; + delta_t* buffer_; + int sample_rate_; + int clock_rate_; + int bass_freq_; + int length_; + bool modified_; + + friend class Blip_Buffer; +}; + +class Blip_Synth_Fast_ { +public: + int delta_factor; + int last_amp; + Blip_Buffer* buf; + + void volume_unit( double ); + void treble_eq( blip_eq_t const& ) { } + Blip_Synth_Fast_(); +}; + +class Blip_Synth_ { +public: + int delta_factor; + int last_amp; + Blip_Buffer* buf; + + void volume_unit( double ); + void treble_eq( blip_eq_t const& ); + Blip_Synth_( short phases [], int width ); +private: + double volume_unit_; + short* const phases; + int const width; + int kernel_unit; + + void adjust_impulse(); + void rescale_kernel( int shift ); + int impulses_size() const { return blip_res / 2 * width; } +}; + +class blip_buffer_state_t +{ + blip_resampled_time_t offset_; + int reader_accum_; + int buf [blip_buffer_extra_]; + friend class Blip_Buffer; +}; + +inline Blip_Buffer_::delta_t* Blip_Buffer_::delta_at( fixed_t f ) +{ + assert( (f >> fixed_bits) < (unsigned) buffer_size_ ); + return buffer_center_ + (f >> fixed_bits); +} + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Bml_Parser.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Bml_Parser.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Bml_Parser.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Bml_Parser.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,357 +1,357 @@ -#include -#include -#include - -#include "Bml_Parser.h" - -const char * strchr_limited( const char * in, const char * end, char c ) -{ - while ( in < end && *in != c ) ++in; - if ( in < end ) return in; - else return 0; -} - -Bml_Node Bml_Node::emptyNode; - -Bml_Node::Bml_Node() -{ - name = 0; - value = 0; -} - -Bml_Node::Bml_Node(char const* name, size_t max_length) -{ - size_t length = 0; - char const* ptr = name; - while (*ptr && length < max_length) ++ptr, ++length; - this->name = new char[ length + 1 ]; - memcpy( this->name, name, length ); - this->name[ length ] = '\0'; - value = 0; -} - -Bml_Node::Bml_Node(const Bml_Node &in) -{ - size_t length; - name = 0; - if (in.name) - { - length = strlen(in.name); - name = new char[length + 1]; - memcpy(name, in.name, length + 1); - } - value = 0; - if (in.value) - { - length = strlen(in.value); - value = new char[length + 1]; - memcpy(value, in.value, length + 1); - } - children = in.children; -} - -Bml_Node::~Bml_Node() -{ - delete [] name; - delete [] value; -} - -void Bml_Node::clear() -{ - delete [] name; - delete [] value; - - name = 0; - value = 0; - children.resize( 0 ); -} - -void Bml_Node::setLine(const char *line, size_t max_length) -{ - delete [] name; - delete [] value; - - name = 0; - value = 0; - - size_t length = 0; - const char * end = line; - while (*end && length < max_length) ++end; - - const char * line_end = strchr_limited(line, end, '\n'); - if ( !line_end ) line_end = end; - - const char * first_letter = line; - while ( first_letter < line_end && *first_letter <= 0x20 ) first_letter++; - - const char * colon = strchr_limited(first_letter, line_end, ':'); - const char * last_letter = line_end - 1; - - if (colon) - { - const char * first_value_letter = colon + 1; - while (first_value_letter < line_end && *first_value_letter <= 0x20) first_value_letter++; - last_letter = line_end - 1; - while (last_letter > first_value_letter && *last_letter <= 0x20) last_letter--; - - value = new char[last_letter - first_value_letter + 2]; - memcpy(value, first_value_letter, last_letter - first_value_letter + 1); - value[last_letter - first_value_letter + 1] = '\0'; - - last_letter = colon - 1; - } - - while (last_letter > first_letter && *last_letter <= 0x20) last_letter--; - - name = new char[last_letter - first_letter + 2]; - memcpy(name, first_letter, last_letter - first_letter + 1); - name[last_letter - first_letter + 1] = '\0'; -} - -Bml_Node& Bml_Node::addChild(const Bml_Node &child) -{ - children.push_back(child); - return *(children.end() - 1); -} - -const char * Bml_Node::getName() const -{ - return name; -} - -const char * Bml_Node::getValue() const -{ - return value; -} - -void Bml_Node::setValue(char const* value) -{ - delete [] this->value; - size_t length = strlen( value ) + 1; - this->value = new char[ length ]; - memcpy( this->value, value, length ); -} - -size_t Bml_Node::getChildCount() const -{ - return children.size(); -} - -Bml_Node const& Bml_Node::getChild(size_t index) const -{ - return children[index]; -} - -Bml_Node & Bml_Node::walkToNode(const char *path, bool use_indexes) -{ - Bml_Node * next_node = nullptr; - Bml_Node * node = this; - while ( *path ) - { - bool item_found = false; - size_t array_index = 0; - const char * array_index_start = strchr( path, '[' ); - const char * next_separator = strchr( path, ':' ); - if ( !next_separator ) next_separator = path + strlen(path); - if ( use_indexes && array_index_start && array_index_start < next_separator ) - { - char * temp; - array_index = strtoul( array_index_start + 1, &temp, 10 ); - } - else - { - array_index_start = next_separator; - } - if ( use_indexes ) - { - for ( std::vector::iterator it = node->children.begin(); it != node->children.end(); ++it ) - { - if ( array_index_start - path == strlen(it->name) && - strncmp( it->name, path, array_index_start - path ) == 0 ) - { - next_node = &(*it); - item_found = true; - if ( array_index == 0 ) break; - --array_index; - } - if (array_index) - item_found = false; - } - } - else - { - for ( std::vector::iterator it = node->children.end(); it != node->children.begin(); ) - { - --it; - if ( next_separator - path == strlen(it->name) && - strncmp( it->name, path, next_separator - path ) == 0 ) - { - next_node = &(*it); - item_found = true; - break; - } - } - } - if ( !item_found ) - { - Bml_Node child( path, next_separator - path ); - node = &(node->addChild( child )); - } - else - node = next_node; - if ( *next_separator ) - { - path = next_separator + 1; - } - else break; - } - return *node; -} - -Bml_Node const& Bml_Node::walkToNode(const char *path) const -{ - Bml_Node const* next_node = nullptr; - Bml_Node const* node = this; - while ( *path ) - { - bool item_found = false; - size_t array_index = ~0; - const char * array_index_start = strchr( path, '[' ); - const char * next_separator = strchr( path, ':' ); - if ( !next_separator ) next_separator = path + strlen(path); - if ( array_index_start && array_index_start < next_separator ) - { - char * temp; - array_index = strtoul( array_index_start + 1, &temp, 10 ); - } - else - { - array_index_start = next_separator; - } - for ( std::vector::const_iterator it = node->children.begin(), ite = node->children.end(); it != ite; ++it ) - { - if ( array_index_start - path == strlen(it->name) && - strncmp( it->name, path, array_index_start - path ) == 0 ) - { - next_node = &(*it); - item_found = true; - if ( array_index == 0 ) break; - --array_index; - } - } - if ( !item_found ) return emptyNode; - node = next_node; - if ( *next_separator ) - { - path = next_separator + 1; - } - else break; - } - return *node; -} - -void Bml_Parser::parseDocument( const char * source, size_t max_length ) -{ - std::vector indents; - std::string last_name; - std::string current_path; - - document.clear(); - - size_t last_indent = ~0; - - Bml_Node node; - - size_t length = 0; - const char * end = source; - while ( *end && length < max_length ) ++end, ++length; - - while ( source < end ) - { - const char * line_end = strchr_limited( source, end, '\n' ); - if ( !line_end ) line_end = end; - - if ( node.getName() ) last_name = node.getName(); - - node.setLine( source, line_end - source ); - - size_t indent = 0; - while ( source < line_end && *source <= 0x20 ) - { - source++; - indent++; - } - - if ( last_indent == ~0 ) last_indent = indent; - - if ( indent > last_indent ) - { - indents.push_back( last_indent ); - last_indent = indent; - if ( current_path.length() ) current_path += ":"; - current_path += last_name; - } - else if ( indent < last_indent ) - { - while ( last_indent > indent && indents.size() ) - { - last_indent = *(indents.end() - 1); - indents.pop_back(); - size_t colon = current_path.find_last_of( ':' ); - if ( colon != std::string::npos ) current_path.resize( colon ); - else current_path.resize( 0 ); - } - last_indent = indent; - } - - document.walkToNode( current_path.c_str() ).addChild( node ); - - source = line_end; - while ( *source && *source == '\n' ) source++; - } -} - -const char * Bml_Parser::enumValue(std::string const& path) const -{ - return document.walkToNode(path.c_str()).getValue(); -} - -void Bml_Parser::setValue(std::string const& path, const char *value) -{ - document.walkToNode(path.c_str(), true).setValue(value); -} - -void Bml_Parser::setValue(std::string const& path, long value) -{ - std::ostringstream str; - str << value; - setValue( path, str.str().c_str() ); -} - -void Bml_Parser::serialize(std::string & out) const -{ - std::ostringstream strOut; - serialize(strOut, &document, 0); - out = strOut.str(); -} - -void Bml_Parser::serialize(std::ostringstream & out, Bml_Node const* node, unsigned int indent) const -{ - for (unsigned i = 1; i < indent; ++i) out << " "; - - if ( indent ) - { - out << node->getName(); - if (node->getValue() && strlen(node->getValue())) out << ":" << node->getValue(); - out << std::endl; - } - - for (unsigned i = 0, j = node->getChildCount(); i < j; ++i) - { - Bml_Node const& child = node->getChild(i); - if ( (!child.getValue() || !strlen(child.getValue())) && !child.getChildCount() ) - continue; - serialize( out, &child, indent + 1 ); - if ( indent == 0 ) out << std::endl; - } -} +#include +#include +#include + +#include "Bml_Parser.h" + +const char * strchr_limited( const char * in, const char * end, char c ) +{ + while ( in < end && *in != c ) ++in; + if ( in < end ) return in; + else return 0; +} + +Bml_Node Bml_Node::emptyNode; + +Bml_Node::Bml_Node() +{ + name = 0; + value = 0; +} + +Bml_Node::Bml_Node(char const* name, size_t max_length) +{ + size_t length = 0; + char const* ptr = name; + while (*ptr && length < max_length) ++ptr, ++length; + this->name = new char[ length + 1 ]; + memcpy( this->name, name, length ); + this->name[ length ] = '\0'; + value = 0; +} + +Bml_Node::Bml_Node(const Bml_Node &in) +{ + size_t length; + name = 0; + if (in.name) + { + length = strlen(in.name); + name = new char[length + 1]; + memcpy(name, in.name, length + 1); + } + value = 0; + if (in.value) + { + length = strlen(in.value); + value = new char[length + 1]; + memcpy(value, in.value, length + 1); + } + children = in.children; +} + +Bml_Node::~Bml_Node() +{ + delete [] name; + delete [] value; +} + +void Bml_Node::clear() +{ + delete [] name; + delete [] value; + + name = 0; + value = 0; + children.resize( 0 ); +} + +void Bml_Node::setLine(const char *line, size_t max_length) +{ + delete [] name; + delete [] value; + + name = 0; + value = 0; + + size_t length = 0; + const char * end = line; + while (*end && length < max_length) ++end; + + const char * line_end = strchr_limited(line, end, '\n'); + if ( !line_end ) line_end = end; + + const char * first_letter = line; + while ( first_letter < line_end && *first_letter <= 0x20 ) first_letter++; + + const char * colon = strchr_limited(first_letter, line_end, ':'); + const char * last_letter = line_end - 1; + + if (colon) + { + const char * first_value_letter = colon + 1; + while (first_value_letter < line_end && *first_value_letter <= 0x20) first_value_letter++; + last_letter = line_end - 1; + while (last_letter > first_value_letter && *last_letter <= 0x20) last_letter--; + + value = new char[last_letter - first_value_letter + 2]; + memcpy(value, first_value_letter, last_letter - first_value_letter + 1); + value[last_letter - first_value_letter + 1] = '\0'; + + last_letter = colon - 1; + } + + while (last_letter > first_letter && *last_letter <= 0x20) last_letter--; + + name = new char[last_letter - first_letter + 2]; + memcpy(name, first_letter, last_letter - first_letter + 1); + name[last_letter - first_letter + 1] = '\0'; +} + +Bml_Node& Bml_Node::addChild(const Bml_Node &child) +{ + children.push_back(child); + return *(children.end() - 1); +} + +const char * Bml_Node::getName() const +{ + return name; +} + +const char * Bml_Node::getValue() const +{ + return value; +} + +void Bml_Node::setValue(char const* value) +{ + delete [] this->value; + size_t length = strlen( value ) + 1; + this->value = new char[ length ]; + memcpy( this->value, value, length ); +} + +size_t Bml_Node::getChildCount() const +{ + return children.size(); +} + +Bml_Node const& Bml_Node::getChild(size_t index) const +{ + return children[index]; +} + +Bml_Node & Bml_Node::walkToNode(const char *path, bool use_indexes) +{ + Bml_Node * next_node = nullptr; + Bml_Node * node = this; + while ( *path ) + { + bool item_found = false; + size_t array_index = 0; + const char * array_index_start = strchr( path, '[' ); + const char * next_separator = strchr( path, ':' ); + if ( !next_separator ) next_separator = path + strlen(path); + if ( use_indexes && array_index_start && array_index_start < next_separator ) + { + char * temp; + array_index = strtoul( array_index_start + 1, &temp, 10 ); + } + else + { + array_index_start = next_separator; + } + if ( use_indexes ) + { + for ( std::vector::iterator it = node->children.begin(); it != node->children.end(); ++it ) + { + if ( array_index_start - path == strlen(it->name) && + strncmp( it->name, path, array_index_start - path ) == 0 ) + { + next_node = &(*it); + item_found = true; + if ( array_index == 0 ) break; + --array_index; + } + if (array_index) + item_found = false; + } + } + else + { + for ( std::vector::iterator it = node->children.end(); it != node->children.begin(); ) + { + --it; + if ( next_separator - path == strlen(it->name) && + strncmp( it->name, path, next_separator - path ) == 0 ) + { + next_node = &(*it); + item_found = true; + break; + } + } + } + if ( !item_found ) + { + Bml_Node child( path, next_separator - path ); + node = &(node->addChild( child )); + } + else + node = next_node; + if ( *next_separator ) + { + path = next_separator + 1; + } + else break; + } + return *node; +} + +Bml_Node const& Bml_Node::walkToNode(const char *path) const +{ + Bml_Node const* next_node = nullptr; + Bml_Node const* node = this; + while ( *path ) + { + bool item_found = false; + size_t array_index = ~0; + const char * array_index_start = strchr( path, '[' ); + const char * next_separator = strchr( path, ':' ); + if ( !next_separator ) next_separator = path + strlen(path); + if ( array_index_start && array_index_start < next_separator ) + { + char * temp; + array_index = strtoul( array_index_start + 1, &temp, 10 ); + } + else + { + array_index_start = next_separator; + } + for ( std::vector::const_iterator it = node->children.begin(), ite = node->children.end(); it != ite; ++it ) + { + if ( array_index_start - path == strlen(it->name) && + strncmp( it->name, path, array_index_start - path ) == 0 ) + { + next_node = &(*it); + item_found = true; + if ( array_index == 0 ) break; + --array_index; + } + } + if ( !item_found ) return emptyNode; + node = next_node; + if ( *next_separator ) + { + path = next_separator + 1; + } + else break; + } + return *node; +} + +void Bml_Parser::parseDocument( const char * source, size_t max_length ) +{ + std::vector indents; + std::string last_name; + std::string current_path; + + document.clear(); + + size_t last_indent = ~0; + + Bml_Node node; + + size_t length = 0; + const char * end = source; + while ( *end && length < max_length ) ++end, ++length; + + while ( source < end ) + { + const char * line_end = strchr_limited( source, end, '\n' ); + if ( !line_end ) line_end = end; + + if ( node.getName() ) last_name = node.getName(); + + node.setLine( source, line_end - source ); + + size_t indent = 0; + while ( source < line_end && *source <= 0x20 ) + { + source++; + indent++; + } + + if ( last_indent == ~0 ) last_indent = indent; + + if ( indent > last_indent ) + { + indents.push_back( last_indent ); + last_indent = indent; + if ( current_path.length() ) current_path += ":"; + current_path += last_name; + } + else if ( indent < last_indent ) + { + while ( last_indent > indent && indents.size() ) + { + last_indent = *(indents.end() - 1); + indents.pop_back(); + size_t colon = current_path.find_last_of( ':' ); + if ( colon != std::string::npos ) current_path.resize( colon ); + else current_path.resize( 0 ); + } + last_indent = indent; + } + + document.walkToNode( current_path.c_str() ).addChild( node ); + + source = line_end; + while ( *source && *source == '\n' ) source++; + } +} + +const char * Bml_Parser::enumValue(std::string const& path) const +{ + return document.walkToNode(path.c_str()).getValue(); +} + +void Bml_Parser::setValue(std::string const& path, const char *value) +{ + document.walkToNode(path.c_str(), true).setValue(value); +} + +void Bml_Parser::setValue(std::string const& path, long value) +{ + std::ostringstream str; + str << value; + setValue( path, str.str().c_str() ); +} + +void Bml_Parser::serialize(std::string & out) const +{ + std::ostringstream strOut; + serialize(strOut, &document, 0); + out = strOut.str(); +} + +void Bml_Parser::serialize(std::ostringstream & out, Bml_Node const* node, unsigned int indent) const +{ + for (unsigned i = 1; i < indent; ++i) out << " "; + + if ( indent ) + { + out << node->getName(); + if (node->getValue() && strlen(node->getValue())) out << ":" << node->getValue(); + out << std::endl; + } + + for (unsigned i = 0, j = node->getChildCount(); i < j; ++i) + { + Bml_Node const& child = node->getChild(i); + if ( (!child.getValue() || !strlen(child.getValue())) && !child.getChildCount() ) + continue; + serialize( out, &child, indent + 1 ); + if ( indent == 0 ) out << std::endl; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Bml_Parser.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Bml_Parser.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Bml_Parser.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Bml_Parser.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,61 +1,61 @@ -#ifndef BML_PARSER_H -#define BML_PARSER_H - -#include -#include -#include - -class Bml_Node -{ - char * name; - char * value; - - std::vector children; - - static Bml_Node emptyNode; - -public: - Bml_Node(); - Bml_Node(char const* name, size_t max_length = ~0UL); - Bml_Node(Bml_Node const& in); - - ~Bml_Node(); - - void clear(); - - void setLine(const char * line, size_t max_length = ~0UL); - Bml_Node& addChild(Bml_Node const& child); - - const char * getName() const; - const char * getValue() const; - - void setValue(char const* value); - - size_t getChildCount() const; - Bml_Node const& getChild(size_t index) const; - - Bml_Node & walkToNode( const char * path, bool use_indexes = false ); - Bml_Node const& walkToNode( const char * path ) const; -}; - -class Bml_Parser -{ - Bml_Node document; - -public: - Bml_Parser() { } - - void parseDocument(const char * document, size_t max_length = ~0UL); - - const char * enumValue(std::string const& path) const; - - void setValue(std::string const& path, long value); - void setValue(std::string const& path, const char * value); - - void serialize(std::string & out) const; - -private: - void serialize(std::ostringstream & out, Bml_Node const* node, unsigned int indent) const; -}; - -#endif // BML_PARSER_H +#ifndef BML_PARSER_H +#define BML_PARSER_H + +#include +#include +#include + +class Bml_Node +{ + char * name; + char * value; + + std::vector children; + + static Bml_Node emptyNode; + +public: + Bml_Node(); + Bml_Node(char const* name, size_t max_length = ~0UL); + Bml_Node(Bml_Node const& in); + + ~Bml_Node(); + + void clear(); + + void setLine(const char * line, size_t max_length = ~0UL); + Bml_Node& addChild(Bml_Node const& child); + + const char * getName() const; + const char * getValue() const; + + void setValue(char const* value); + + size_t getChildCount() const; + Bml_Node const& getChild(size_t index) const; + + Bml_Node & walkToNode( const char * path, bool use_indexes = false ); + Bml_Node const& walkToNode( const char * path ) const; +}; + +class Bml_Parser +{ + Bml_Node document; + +public: + Bml_Parser() { } + + void parseDocument(const char * document, size_t max_length = ~0UL); + + const char * enumValue(std::string const& path) const; + + void setValue(std::string const& path, long value); + void setValue(std::string const& path, const char * value); + + void serialize(std::string & out) const; + +private: + void serialize(std::ostringstream & out, Bml_Node const* node, unsigned int indent) const; +}; + +#endif // BML_PARSER_H diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/c140.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/c140.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/c140.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/c140.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,621 +1,621 @@ -/* -C140.c - -Simulator based on AMUSE sources. -The C140 sound chip is used by Namco System 2 and System 21 -The 219 ASIC (which incorporates a modified C140) is used by Namco NA-1 and NA-2 -This chip controls 24 channels (C140) or 16 (219) of PCM. -16 bytes are associated with each channel. -Channels can be 8 bit signed PCM, or 12 bit signed PCM. - -Timer behavior is not yet handled. - -Unmapped registers: - 0x1f8:timer interval? (Nx0.1 ms) - 0x1fa:irq ack? timer restart? - 0x1fe:timer switch?(0:off 1:on) - --------------- - - ASIC "219" notes - - On the 219 ASIC used on NA-1 and NA-2, the high registers have the following - meaning instead: - 0x1f7: bank for voices 0-3 - 0x1f1: bank for voices 4-7 - 0x1f3: bank for voices 8-11 - 0x1f5: bank for voices 12-15 - - Some games (bkrtmaq, xday2) write to 0x1fd for voices 12-15 instead. Probably the bank registers - mirror at 1f8, in which case 1ff is also 0-3, 1f9 is also 4-7, 1fb is also 8-11, and 1fd is also 12-15. - - Each bank is 0x20000 (128k), and the voice addresses on the 219 are all multiplied by 2. - Additionally, the 219's base pitch is the same as the C352's (42667). But these changes - are IMO not sufficient to make this a separate file - all the other registers are - fully compatible. - - Finally, the 219 only has 16 voices. -*/ -/* - 2000.06.26 CAB fixed compressed pcm playback - 2002.07.20 R.Belmont added support for multiple banking types - 2006.01.08 R.Belmont added support for NA-1/2 "219" derivative -*/ - - -//#include "emu.h" -#include -#include -#include "c140.h" - -#undef NULL -#define NULL ((void *)0) - -#define MAX_VOICE 24 - -struct voice_registers -{ - UINT8 volume_right; - UINT8 volume_left; - UINT8 frequency_msb; - UINT8 frequency_lsb; - UINT8 bank; - UINT8 mode; - UINT8 start_msb; - UINT8 start_lsb; - UINT8 end_msb; - UINT8 end_lsb; - UINT8 loop_msb; - UINT8 loop_lsb; - UINT8 reserved[4]; -}; - -typedef struct -{ - long ptoffset; - long pos; - long key; - //--work - long lastdt; - long prevdt; - long dltdt; - //--reg - long rvol; - long lvol; - long frequency; - long bank; - long mode; - - long sample_start; - long sample_end; - long sample_loop; - UINT8 Muted; -} VOICE; - -typedef struct _c140_state c140_state; -struct _c140_state -{ - int sample_rate; - //sound_stream *stream; - int banking_type; - /* internal buffers */ - INT16 *mixer_buffer_left; - INT16 *mixer_buffer_right; - - int baserate; - UINT32 pRomSize; - void *pRom; - UINT8 REG[0x200]; - - INT16 pcmtbl[8]; //2000.06.26 CAB - - VOICE voi[MAX_VOICE]; -}; - -/*INLINE c140_state *get_safe_token(device_t *device) -{ - assert(device != NULL); - assert(device->type() == C140); - return (c140_state *)downcast(device)->token(); -}*/ - - -static void init_voice( VOICE *v ) -{ - v->key=0; - v->ptoffset=0; - v->rvol=0; - v->lvol=0; - v->frequency=0; - v->bank=0; - v->mode=0; - v->sample_start=0; - v->sample_end=0; - v->sample_loop=0; -} -//READ8_DEVICE_HANDLER( c140_r ) -UINT8 c140_r(void *chip, offs_t offset) -{ - //c140_state *info = get_safe_token(device); - c140_state *info = (c140_state *) chip; - offset&=0x1ff; - return info->REG[offset]; -} - -/* - find_sample: compute the actual address of a sample given it's - address and banking registers, as well as the board type. - - I suspect in "real life" this works like the Sega MultiPCM where the banking - is done by a small PAL or GAL external to the sound chip, which can be switched - per-game or at least per-PCB revision as addressing range needs grow. - */ -static long find_sample(c140_state *info, long adrs, long bank, int voice) -{ - long newadr = 0; - - static const INT16 asic219banks[4] = { 0x1f7, 0x1f1, 0x1f3, 0x1f5 }; - - adrs=(bank<<16)+adrs; - - switch (info->banking_type) - { - case C140_TYPE_SYSTEM2: - // System 2 banking - newadr = ((adrs&0x200000)>>2)|(adrs&0x7ffff); - break; - - case C140_TYPE_SYSTEM21_A: - // System 21 type A (simple) banking. - // similar to System 2's. - newadr = ((adrs&0x300000)>>1)+(adrs&0x7ffff); - break; - - case C140_TYPE_SYSTEM21_B: - // System 21 type B (chip select) banking - - // get base address of sample inside the bank - newadr = ((adrs&0x100000)>>2) + (adrs&0x3ffff); - - // now add the starting bank offsets based on the 2 - // chip select bits. - // 0x40000 picks individual 512k ROMs - if (adrs & 0x40000) - { - newadr += 0x80000; - } - - // and 0x200000 which group of chips... - if (adrs & 0x200000) - { - newadr += 0x100000; - } - break; - - case C140_TYPE_ASIC219: - // ASIC219's banking is fairly simple - newadr = ((info->REG[asic219banks[voice/4]]&0x3) * 0x20000) + adrs; - break; - } - - return (newadr); -} -//WRITE8_DEVICE_HANDLER( c140_w ) -void c140_w(void *chip, offs_t offset, UINT8 data) -{ - //c140_state *info = get_safe_token(device); - c140_state *info = (c140_state *) chip; - //info->stream->update(); - - offset&=0x1ff; - - // mirror the bank registers on the 219, fixes bkrtmaq (and probably xday2 based on notes in the HLE) - if ((offset >= 0x1f8) && (info->banking_type == C140_TYPE_ASIC219)) - { - offset -= 8; - } - - info->REG[offset]=data; - if( offset<0x180 ) - { - VOICE *v = &info->voi[offset>>4]; - - if( (offset&0xf)==0x5 ) - { - if( data&0x80 ) - { - const struct voice_registers *vreg = (struct voice_registers *) &info->REG[offset&0x1f0]; - v->key=1; - v->ptoffset=0; - v->pos=0; - v->lastdt=0; - v->prevdt=0; - v->dltdt=0; - v->bank = vreg->bank; - v->mode = data; - - // on the 219 asic, addresses are in words - if (info->banking_type == C140_TYPE_ASIC219) - { - v->sample_loop = (vreg->loop_msb*256 + vreg->loop_lsb)*2; - v->sample_start = (vreg->start_msb*256 + vreg->start_lsb)*2; - v->sample_end = (vreg->end_msb*256 + vreg->end_lsb)*2; - - #if 0 - logerror("219: play v %d mode %02x start %x loop %x end %x\n", - offset>>4, v->mode, - find_sample(info, v->sample_start, v->bank, offset>>4), - find_sample(info, v->sample_loop, v->bank, offset>>4), - find_sample(info, v->sample_end, v->bank, offset>>4)); - #endif - } - else - { - v->sample_loop = vreg->loop_msb*256 + vreg->loop_lsb; - v->sample_start = vreg->start_msb*256 + vreg->start_lsb; - v->sample_end = vreg->end_msb*256 + vreg->end_lsb; - } - } - else - { - v->key=0; - } - } - } -} - -//void c140_set_base(device_t *device, void *base) -void c140_set_base(void *chip, void *base) -{ - //c140_state *info = get_safe_token(device); - c140_state *info = (c140_state *) chip; - info->pRom = base; -} - -/*INLINE int limit(INT32 in) -{ - if(in>0x7fff) return 0x7fff; - else if(in<-0x8000) return -0x8000; - return in; -}*/ - -//static STREAM_UPDATE( update_stereo ) -void c140_update(void *chip, stream_sample_t **outputs, int samples) -{ - //c140_state *info = (c140_state *)param; - c140_state *info = (c140_state *) chip; - int i,j; - - INT32 rvol,lvol; - INT32 dt; - INT32 sdt; - INT32 st,ed,sz; - - INT8 *pSampleData; - INT32 frequency,delta,offset,pos; - INT32 cnt, voicecnt; - INT32 lastdt,prevdt,dltdt; - float pbase=(float)info->baserate*2.0f / (float)info->sample_rate; - - INT16 *lmix, *rmix; - - if(samples>info->sample_rate) samples=info->sample_rate; - - /* zap the contents of the mixer buffer */ - memset(info->mixer_buffer_left, 0, samples * sizeof(INT16)); - memset(info->mixer_buffer_right, 0, samples * sizeof(INT16)); - if (info->pRom == NULL) - return; - - /* get the number of voices to update */ - voicecnt = (info->banking_type == C140_TYPE_ASIC219) ? 16 : 24; - - //--- audio update - for( i=0;ivoi[i]; - const struct voice_registers *vreg = (struct voice_registers *)&info->REG[i*16]; - - if( v->key && ! v->Muted) - { - frequency= vreg->frequency_msb*256 + vreg->frequency_lsb; - - /* Abort voice if no frequency value set */ - if(frequency==0) continue; - - /* Delta = frequency * ((8MHz/374)*2 / sample rate) */ - delta=(long)((float)frequency * pbase); - - /* Calculate left/right channel volumes */ - lvol=(vreg->volume_left*32)/MAX_VOICE; //32ch -> 24ch - rvol=(vreg->volume_right*32)/MAX_VOICE; - - /* Set mixer outputs base pointers */ - lmix = info->mixer_buffer_left; - rmix = info->mixer_buffer_right; - - /* Retrieve sample start/end and calculate size */ - st=v->sample_start; - ed=v->sample_end; - sz=ed-st; - - /* Retrieve base pointer to the sample data */ - //pSampleData=(signed char*)((FPTR)info->pRom + find_sample(info, st, v->bank, i)); - pSampleData = (INT8*)info->pRom + find_sample(info, st, v->bank, i); - - /* Fetch back previous data pointers */ - offset=v->ptoffset; - pos=v->pos; - lastdt=v->lastdt; - prevdt=v->prevdt; - dltdt=v->dltdt; - - /* Switch on data type - compressed PCM is only for C140 */ - if ((v->mode&8) && (info->banking_type != C140_TYPE_ASIC219)) - { - //compressed PCM (maybe correct...) - /* Loop for enough to fill sample buffer as requested */ - for(j=0;j>16)&0x7fff; - offset &= 0xffff; - pos+=cnt; - //for(;cnt>0;cnt--) - { - /* Check for the end of the sample */ - if(pos >= sz) - { - /* Check if its a looping sample, either stop or loop */ - if(v->mode&0x10) - { - pos = (v->sample_loop - st); - } - else - { - v->key=0; - break; - } - } - - /* Read the chosen sample byte */ - dt=pSampleData[pos]; - - /* decompress to 13bit range */ //2000.06.26 CAB - sdt=dt>>3; //signed - if(sdt<0) sdt = (sdt<<(dt&7)) - info->pcmtbl[dt&7]; - else sdt = (sdt<<(dt&7)) + info->pcmtbl[dt&7]; - - prevdt=lastdt; - lastdt=sdt; - dltdt=(lastdt - prevdt); - } - - /* Caclulate the sample value */ - dt=((dltdt*offset)>>16)+prevdt; - - /* Write the data to the sample buffers */ - *lmix++ +=(dt*lvol)>>(5+5); - *rmix++ +=(dt*rvol)>>(5+5); - } - } - else - { - /* linear 8bit signed PCM */ - for(j=0;j>16)&0x7fff; - offset &= 0xffff; - pos += cnt; - /* Check for the end of the sample */ - if(pos >= sz) - { - /* Check if its a looping sample, either stop or loop */ - if( v->mode&0x10 ) - { - pos = (v->sample_loop - st); - } - else - { - v->key=0; - break; - } - } - - if( cnt ) - { - prevdt=lastdt; - - if (info->banking_type == C140_TYPE_ASIC219) - { - //lastdt = pSampleData[BYTE_XOR_BE(pos)]; - lastdt = pSampleData[pos ^ 0x01]; - - // Sign + magnitude format - if ((v->mode & 0x01) && (lastdt & 0x80)) - lastdt = -(lastdt & 0x7f); - - // Sign flip - if (v->mode & 0x40) - lastdt = -lastdt; - } - else - { - lastdt=pSampleData[pos]; - } - - dltdt = (lastdt - prevdt); - } - - /* Caclulate the sample value */ - dt=((dltdt*offset)>>16)+prevdt; - - /* Write the data to the sample buffers */ - *lmix++ +=(dt*lvol)>>5; - *rmix++ +=(dt*rvol)>>5; - } - } - - /* Save positional data for next callback */ - v->ptoffset=offset; - v->pos=pos; - v->lastdt=lastdt; - v->prevdt=prevdt; - v->dltdt=dltdt; - } - } - - /* render to MAME's stream buffer */ - lmix = info->mixer_buffer_left; - rmix = info->mixer_buffer_right; - { - stream_sample_t *dest1 = outputs[0]; - stream_sample_t *dest2 = outputs[1]; - for (i = 0; i < samples; i++) - { - //*dest1++ = limit(8*(*lmix++)); - //*dest2++ = limit(8*(*rmix++)); - *dest1++ = 8 * (*lmix ++); - *dest2++ = 8 * (*rmix ++); - } - } -} - -//static DEVICE_START( c140 ) -void * device_start_c140(int sample_rate, int clock, int banking_type) -{ - //const c140_interface *intf = (const c140_interface *)device->static_config(); - //c140_state *info = get_safe_token(device); - c140_state *info; - int i; - - info = (c140_state *) malloc(sizeof(c140_state)); - if (!info) return info; - - //info->sample_rate=info->baserate=device->clock(); - info->sample_rate = sample_rate; - info->baserate = clock; - - //info->banking_type = intf->banking_type; - info->banking_type = banking_type; - - //info->stream = device->machine().sound().stream_alloc(*device,0,2,info->sample_rate,info,update_stereo); - - //info->pRom=*device->region(); - info->pRomSize = 0x00; - info->pRom = NULL; - - /* make decompress pcm table */ //2000.06.26 CAB - { - INT32 segbase=0; - for(i=0;i<8;i++) - { - info->pcmtbl[i]=segbase; //segment base value - segbase += 16<REG,0,sizeof(info->REG)); - { - int i; - for(i=0;ivoi[i] ); - }*/ - - /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */ - //info->mixer_buffer_left = auto_alloc_array(device->machine(), INT16, 2 * info->sample_rate); - info->mixer_buffer_left = (INT16*)malloc(sizeof(INT16) * 2 * info->sample_rate); - info->mixer_buffer_right = info->mixer_buffer_left + info->sample_rate; - - for (i = 0; i < MAX_VOICE; i ++) - info->voi[i].Muted = 0x00; - - return info; -} - -void device_stop_c140(void *chip) -{ - c140_state *info = (c140_state *) chip; - - free(info->pRom); info->pRom = NULL; - free(info->mixer_buffer_left); - free(info); -} - -void device_reset_c140(void *chip) -{ - c140_state *info = (c140_state *) chip; - int i; - - memset(info->REG, 0, sizeof(info->REG)); - - for(i = 0; i < MAX_VOICE; i ++) - init_voice( &info->voi[i] ); - - return; -} - -void c140_write_rom(void *chip, offs_t ROMSize, offs_t DataStart, offs_t DataLength, - const UINT8* ROMData) -{ - c140_state *info = (c140_state *) chip; - - if (info->pRomSize != ROMSize) - { - info->pRom = (UINT8*)realloc(info->pRom, ROMSize); - info->pRomSize = ROMSize; - memset(info->pRom, 0xFF, ROMSize); - } - if (DataStart > ROMSize) - return; - if (DataStart + DataLength > ROMSize) - DataLength = ROMSize - DataStart; - - memcpy((INT8*)info->pRom + DataStart, ROMData, DataLength); - - return; -} - - -void c140_set_mute_mask(void *chip, UINT32 MuteMask) -{ - c140_state *info = (c140_state *) chip; - UINT8 CurChn; - - for (CurChn = 0; CurChn < MAX_VOICE; CurChn ++) - info->voi[CurChn].Muted = (MuteMask >> CurChn) & 0x01; - - return; -} - - - - -/************************************************************************** - * Generic get_info - **************************************************************************/ - -/*DEVICE_GET_INFO( c140 ) -{ - switch (state) - { - // --- the following bits of info are returned as 64-bit signed integers --- // - case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(c140_state); break; - - // --- the following bits of info are returned as pointers to data or functions --- // - case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( c140 ); break; - case DEVINFO_FCT_STOP: // nothing // break; - case DEVINFO_FCT_RESET: // nothing // break; - - // --- the following bits of info are returned as NULL-terminated strings --- // - case DEVINFO_STR_NAME: strcpy(info->s, "C140"); break; - case DEVINFO_STR_FAMILY: strcpy(info->s, "Namco PCM"); break; - case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; - case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; - case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; - } -} - - -DEFINE_LEGACY_SOUND_DEVICE(C140, c140);*/ +/* +C140.c + +Simulator based on AMUSE sources. +The C140 sound chip is used by Namco System 2 and System 21 +The 219 ASIC (which incorporates a modified C140) is used by Namco NA-1 and NA-2 +This chip controls 24 channels (C140) or 16 (219) of PCM. +16 bytes are associated with each channel. +Channels can be 8 bit signed PCM, or 12 bit signed PCM. + +Timer behavior is not yet handled. + +Unmapped registers: + 0x1f8:timer interval? (Nx0.1 ms) + 0x1fa:irq ack? timer restart? + 0x1fe:timer switch?(0:off 1:on) + +-------------- + + ASIC "219" notes + + On the 219 ASIC used on NA-1 and NA-2, the high registers have the following + meaning instead: + 0x1f7: bank for voices 0-3 + 0x1f1: bank for voices 4-7 + 0x1f3: bank for voices 8-11 + 0x1f5: bank for voices 12-15 + + Some games (bkrtmaq, xday2) write to 0x1fd for voices 12-15 instead. Probably the bank registers + mirror at 1f8, in which case 1ff is also 0-3, 1f9 is also 4-7, 1fb is also 8-11, and 1fd is also 12-15. + + Each bank is 0x20000 (128k), and the voice addresses on the 219 are all multiplied by 2. + Additionally, the 219's base pitch is the same as the C352's (42667). But these changes + are IMO not sufficient to make this a separate file - all the other registers are + fully compatible. + + Finally, the 219 only has 16 voices. +*/ +/* + 2000.06.26 CAB fixed compressed pcm playback + 2002.07.20 R.Belmont added support for multiple banking types + 2006.01.08 R.Belmont added support for NA-1/2 "219" derivative +*/ + + +//#include "emu.h" +#include +#include +#include "c140.h" + +#undef NULL +#define NULL ((void *)0) + +#define MAX_VOICE 24 + +struct voice_registers +{ + UINT8 volume_right; + UINT8 volume_left; + UINT8 frequency_msb; + UINT8 frequency_lsb; + UINT8 bank; + UINT8 mode; + UINT8 start_msb; + UINT8 start_lsb; + UINT8 end_msb; + UINT8 end_lsb; + UINT8 loop_msb; + UINT8 loop_lsb; + UINT8 reserved[4]; +}; + +typedef struct +{ + long ptoffset; + long pos; + long key; + //--work + long lastdt; + long prevdt; + long dltdt; + //--reg + long rvol; + long lvol; + long frequency; + long bank; + long mode; + + long sample_start; + long sample_end; + long sample_loop; + UINT8 Muted; +} VOICE; + +typedef struct _c140_state c140_state; +struct _c140_state +{ + int sample_rate; + //sound_stream *stream; + int banking_type; + /* internal buffers */ + INT16 *mixer_buffer_left; + INT16 *mixer_buffer_right; + + int baserate; + UINT32 pRomSize; + void *pRom; + UINT8 REG[0x200]; + + INT16 pcmtbl[8]; //2000.06.26 CAB + + VOICE voi[MAX_VOICE]; +}; + +/*INLINE c140_state *get_safe_token(device_t *device) +{ + assert(device != NULL); + assert(device->type() == C140); + return (c140_state *)downcast(device)->token(); +}*/ + + +static void init_voice( VOICE *v ) +{ + v->key=0; + v->ptoffset=0; + v->rvol=0; + v->lvol=0; + v->frequency=0; + v->bank=0; + v->mode=0; + v->sample_start=0; + v->sample_end=0; + v->sample_loop=0; +} +//READ8_DEVICE_HANDLER( c140_r ) +UINT8 c140_r(void *chip, offs_t offset) +{ + //c140_state *info = get_safe_token(device); + c140_state *info = (c140_state *) chip; + offset&=0x1ff; + return info->REG[offset]; +} + +/* + find_sample: compute the actual address of a sample given it's + address and banking registers, as well as the board type. + + I suspect in "real life" this works like the Sega MultiPCM where the banking + is done by a small PAL or GAL external to the sound chip, which can be switched + per-game or at least per-PCB revision as addressing range needs grow. + */ +static long find_sample(c140_state *info, long adrs, long bank, int voice) +{ + long newadr = 0; + + static const INT16 asic219banks[4] = { 0x1f7, 0x1f1, 0x1f3, 0x1f5 }; + + adrs=(bank<<16)+adrs; + + switch (info->banking_type) + { + case C140_TYPE_SYSTEM2: + // System 2 banking + newadr = ((adrs&0x200000)>>2)|(adrs&0x7ffff); + break; + + case C140_TYPE_SYSTEM21_A: + // System 21 type A (simple) banking. + // similar to System 2's. + newadr = ((adrs&0x300000)>>1)+(adrs&0x7ffff); + break; + + case C140_TYPE_SYSTEM21_B: + // System 21 type B (chip select) banking + + // get base address of sample inside the bank + newadr = ((adrs&0x100000)>>2) + (adrs&0x3ffff); + + // now add the starting bank offsets based on the 2 + // chip select bits. + // 0x40000 picks individual 512k ROMs + if (adrs & 0x40000) + { + newadr += 0x80000; + } + + // and 0x200000 which group of chips... + if (adrs & 0x200000) + { + newadr += 0x100000; + } + break; + + case C140_TYPE_ASIC219: + // ASIC219's banking is fairly simple + newadr = ((info->REG[asic219banks[voice/4]]&0x3) * 0x20000) + adrs; + break; + } + + return (newadr); +} +//WRITE8_DEVICE_HANDLER( c140_w ) +void c140_w(void *chip, offs_t offset, UINT8 data) +{ + //c140_state *info = get_safe_token(device); + c140_state *info = (c140_state *) chip; + //info->stream->update(); + + offset&=0x1ff; + + // mirror the bank registers on the 219, fixes bkrtmaq (and probably xday2 based on notes in the HLE) + if ((offset >= 0x1f8) && (info->banking_type == C140_TYPE_ASIC219)) + { + offset -= 8; + } + + info->REG[offset]=data; + if( offset<0x180 ) + { + VOICE *v = &info->voi[offset>>4]; + + if( (offset&0xf)==0x5 ) + { + if( data&0x80 ) + { + const struct voice_registers *vreg = (struct voice_registers *) &info->REG[offset&0x1f0]; + v->key=1; + v->ptoffset=0; + v->pos=0; + v->lastdt=0; + v->prevdt=0; + v->dltdt=0; + v->bank = vreg->bank; + v->mode = data; + + // on the 219 asic, addresses are in words + if (info->banking_type == C140_TYPE_ASIC219) + { + v->sample_loop = (vreg->loop_msb*256 + vreg->loop_lsb)*2; + v->sample_start = (vreg->start_msb*256 + vreg->start_lsb)*2; + v->sample_end = (vreg->end_msb*256 + vreg->end_lsb)*2; + + #if 0 + logerror("219: play v %d mode %02x start %x loop %x end %x\n", + offset>>4, v->mode, + find_sample(info, v->sample_start, v->bank, offset>>4), + find_sample(info, v->sample_loop, v->bank, offset>>4), + find_sample(info, v->sample_end, v->bank, offset>>4)); + #endif + } + else + { + v->sample_loop = vreg->loop_msb*256 + vreg->loop_lsb; + v->sample_start = vreg->start_msb*256 + vreg->start_lsb; + v->sample_end = vreg->end_msb*256 + vreg->end_lsb; + } + } + else + { + v->key=0; + } + } + } +} + +//void c140_set_base(device_t *device, void *base) +void c140_set_base(void *chip, void *base) +{ + //c140_state *info = get_safe_token(device); + c140_state *info = (c140_state *) chip; + info->pRom = base; +} + +/*INLINE int limit(INT32 in) +{ + if(in>0x7fff) return 0x7fff; + else if(in<-0x8000) return -0x8000; + return in; +}*/ + +//static STREAM_UPDATE( update_stereo ) +void c140_update(void *chip, stream_sample_t **outputs, int samples) +{ + //c140_state *info = (c140_state *)param; + c140_state *info = (c140_state *) chip; + int i,j; + + INT32 rvol,lvol; + INT32 dt; + INT32 sdt; + INT32 st,ed,sz; + + INT8 *pSampleData; + INT32 frequency,delta,offset,pos; + INT32 cnt, voicecnt; + INT32 lastdt,prevdt,dltdt; + float pbase=(float)info->baserate*2.0f / (float)info->sample_rate; + + INT16 *lmix, *rmix; + + if(samples>info->sample_rate) samples=info->sample_rate; + + /* zap the contents of the mixer buffer */ + memset(info->mixer_buffer_left, 0, samples * sizeof(INT16)); + memset(info->mixer_buffer_right, 0, samples * sizeof(INT16)); + if (info->pRom == NULL) + return; + + /* get the number of voices to update */ + voicecnt = (info->banking_type == C140_TYPE_ASIC219) ? 16 : 24; + + //--- audio update + for( i=0;ivoi[i]; + const struct voice_registers *vreg = (struct voice_registers *)&info->REG[i*16]; + + if( v->key && ! v->Muted) + { + frequency= vreg->frequency_msb*256 + vreg->frequency_lsb; + + /* Abort voice if no frequency value set */ + if(frequency==0) continue; + + /* Delta = frequency * ((8MHz/374)*2 / sample rate) */ + delta=(long)((float)frequency * pbase); + + /* Calculate left/right channel volumes */ + lvol=(vreg->volume_left*32)/MAX_VOICE; //32ch -> 24ch + rvol=(vreg->volume_right*32)/MAX_VOICE; + + /* Set mixer outputs base pointers */ + lmix = info->mixer_buffer_left; + rmix = info->mixer_buffer_right; + + /* Retrieve sample start/end and calculate size */ + st=v->sample_start; + ed=v->sample_end; + sz=ed-st; + + /* Retrieve base pointer to the sample data */ + //pSampleData=(signed char*)((FPTR)info->pRom + find_sample(info, st, v->bank, i)); + pSampleData = (INT8*)info->pRom + find_sample(info, st, v->bank, i); + + /* Fetch back previous data pointers */ + offset=v->ptoffset; + pos=v->pos; + lastdt=v->lastdt; + prevdt=v->prevdt; + dltdt=v->dltdt; + + /* Switch on data type - compressed PCM is only for C140 */ + if ((v->mode&8) && (info->banking_type != C140_TYPE_ASIC219)) + { + //compressed PCM (maybe correct...) + /* Loop for enough to fill sample buffer as requested */ + for(j=0;j>16)&0x7fff; + offset &= 0xffff; + pos+=cnt; + //for(;cnt>0;cnt--) + { + /* Check for the end of the sample */ + if(pos >= sz) + { + /* Check if its a looping sample, either stop or loop */ + if(v->mode&0x10) + { + pos = (v->sample_loop - st); + } + else + { + v->key=0; + break; + } + } + + /* Read the chosen sample byte */ + dt=pSampleData[pos]; + + /* decompress to 13bit range */ //2000.06.26 CAB + sdt=dt>>3; //signed + if(sdt<0) sdt = (sdt<<(dt&7)) - info->pcmtbl[dt&7]; + else sdt = (sdt<<(dt&7)) + info->pcmtbl[dt&7]; + + prevdt=lastdt; + lastdt=sdt; + dltdt=(lastdt - prevdt); + } + + /* Caclulate the sample value */ + dt=((dltdt*offset)>>16)+prevdt; + + /* Write the data to the sample buffers */ + *lmix++ +=(dt*lvol)>>(5+5); + *rmix++ +=(dt*rvol)>>(5+5); + } + } + else + { + /* linear 8bit signed PCM */ + for(j=0;j>16)&0x7fff; + offset &= 0xffff; + pos += cnt; + /* Check for the end of the sample */ + if(pos >= sz) + { + /* Check if its a looping sample, either stop or loop */ + if( v->mode&0x10 ) + { + pos = (v->sample_loop - st); + } + else + { + v->key=0; + break; + } + } + + if( cnt ) + { + prevdt=lastdt; + + if (info->banking_type == C140_TYPE_ASIC219) + { + //lastdt = pSampleData[BYTE_XOR_BE(pos)]; + lastdt = pSampleData[pos ^ 0x01]; + + // Sign + magnitude format + if ((v->mode & 0x01) && (lastdt & 0x80)) + lastdt = -(lastdt & 0x7f); + + // Sign flip + if (v->mode & 0x40) + lastdt = -lastdt; + } + else + { + lastdt=pSampleData[pos]; + } + + dltdt = (lastdt - prevdt); + } + + /* Caclulate the sample value */ + dt=((dltdt*offset)>>16)+prevdt; + + /* Write the data to the sample buffers */ + *lmix++ +=(dt*lvol)>>5; + *rmix++ +=(dt*rvol)>>5; + } + } + + /* Save positional data for next callback */ + v->ptoffset=offset; + v->pos=pos; + v->lastdt=lastdt; + v->prevdt=prevdt; + v->dltdt=dltdt; + } + } + + /* render to MAME's stream buffer */ + lmix = info->mixer_buffer_left; + rmix = info->mixer_buffer_right; + { + stream_sample_t *dest1 = outputs[0]; + stream_sample_t *dest2 = outputs[1]; + for (i = 0; i < samples; i++) + { + //*dest1++ = limit(8*(*lmix++)); + //*dest2++ = limit(8*(*rmix++)); + *dest1++ = 8 * (*lmix ++); + *dest2++ = 8 * (*rmix ++); + } + } +} + +//static DEVICE_START( c140 ) +void * device_start_c140(int sample_rate, int clock, int banking_type) +{ + //const c140_interface *intf = (const c140_interface *)device->static_config(); + //c140_state *info = get_safe_token(device); + c140_state *info; + int i; + + info = (c140_state *) malloc(sizeof(c140_state)); + if (!info) return info; + + //info->sample_rate=info->baserate=device->clock(); + info->sample_rate = sample_rate; + info->baserate = clock; + + //info->banking_type = intf->banking_type; + info->banking_type = banking_type; + + //info->stream = device->machine().sound().stream_alloc(*device,0,2,info->sample_rate,info,update_stereo); + + //info->pRom=*device->region(); + info->pRomSize = 0x00; + info->pRom = NULL; + + /* make decompress pcm table */ //2000.06.26 CAB + { + INT32 segbase=0; + for(i=0;i<8;i++) + { + info->pcmtbl[i]=segbase; //segment base value + segbase += 16<REG,0,sizeof(info->REG)); + { + int i; + for(i=0;ivoi[i] ); + }*/ + + /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */ + //info->mixer_buffer_left = auto_alloc_array(device->machine(), INT16, 2 * info->sample_rate); + info->mixer_buffer_left = (INT16*)malloc(sizeof(INT16) * 2 * info->sample_rate); + info->mixer_buffer_right = info->mixer_buffer_left + info->sample_rate; + + for (i = 0; i < MAX_VOICE; i ++) + info->voi[i].Muted = 0x00; + + return info; +} + +void device_stop_c140(void *chip) +{ + c140_state *info = (c140_state *) chip; + + free(info->pRom); info->pRom = NULL; + free(info->mixer_buffer_left); + free(info); +} + +void device_reset_c140(void *chip) +{ + c140_state *info = (c140_state *) chip; + int i; + + memset(info->REG, 0, sizeof(info->REG)); + + for(i = 0; i < MAX_VOICE; i ++) + init_voice( &info->voi[i] ); + + return; +} + +void c140_write_rom(void *chip, offs_t ROMSize, offs_t DataStart, offs_t DataLength, + const UINT8* ROMData) +{ + c140_state *info = (c140_state *) chip; + + if (info->pRomSize != ROMSize) + { + info->pRom = (UINT8*)realloc(info->pRom, ROMSize); + info->pRomSize = ROMSize; + memset(info->pRom, 0xFF, ROMSize); + } + if (DataStart > ROMSize) + return; + if (DataStart + DataLength > ROMSize) + DataLength = ROMSize - DataStart; + + memcpy((INT8*)info->pRom + DataStart, ROMData, DataLength); + + return; +} + + +void c140_set_mute_mask(void *chip, UINT32 MuteMask) +{ + c140_state *info = (c140_state *) chip; + UINT8 CurChn; + + for (CurChn = 0; CurChn < MAX_VOICE; CurChn ++) + info->voi[CurChn].Muted = (MuteMask >> CurChn) & 0x01; + + return; +} + + + + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +/*DEVICE_GET_INFO( c140 ) +{ + switch (state) + { + // --- the following bits of info are returned as 64-bit signed integers --- // + case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(c140_state); break; + + // --- the following bits of info are returned as pointers to data or functions --- // + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( c140 ); break; + case DEVINFO_FCT_STOP: // nothing // break; + case DEVINFO_FCT_RESET: // nothing // break; + + // --- the following bits of info are returned as NULL-terminated strings --- // + case DEVINFO_STR_NAME: strcpy(info->s, "C140"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Namco PCM"); break; + case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; + } +} + + +DEFINE_LEGACY_SOUND_DEVICE(C140, c140);*/ diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/C140_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/C140_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/C140_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/C140_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,77 +1,77 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "C140_Emu.h" -#include "c140.h" - -C140_Emu::C140_Emu() { chip = 0; } - -C140_Emu::~C140_Emu() -{ - if ( chip ) device_stop_c140( chip ); -} - -int C140_Emu::set_rate( int type, double sample_rate, double clock_rate ) -{ - if ( chip ) - { - device_stop_c140( chip ); - chip = 0; - } - - chip = device_start_c140( sample_rate, clock_rate, type ); - if ( !chip ) - return 1; - - reset(); - return 0; -} - -void C140_Emu::reset() -{ - device_reset_c140( chip ); - c140_set_mute_mask( chip, 0 ); -} - -void C140_Emu::write( int addr, int data ) -{ - c140_w( chip, addr, data ); -} - -void C140_Emu::write_rom( int size, int start, int length, void * data ) -{ - c140_write_rom( chip, size, start, length, (const UINT8 *) data ); -} - -void C140_Emu::mute_voices( int mask ) -{ - c140_set_mute_mask( chip, mask ); -} - -void C140_Emu::run( int pair_count, sample_t* out ) -{ - stream_sample_t bufL[ 1024 ]; - stream_sample_t bufR[ 1024 ]; - stream_sample_t * buffers[2] = { bufL, bufR }; - - while (pair_count > 0) - { - int todo = pair_count; - if (todo > 1024) todo = 1024; - c140_update( chip, buffers, todo ); - - for (int i = 0; i < todo; i++) - { - int output_l = bufL [i]; - int output_r = bufR [i]; - output_l += out [0]; - output_r += out [1]; - if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); - if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); - out [0] = output_l; - out [1] = output_r; - out += 2; - } - - pair_count -= todo; - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "C140_Emu.h" +#include "c140.h" + +C140_Emu::C140_Emu() { chip = 0; } + +C140_Emu::~C140_Emu() +{ + if ( chip ) device_stop_c140( chip ); +} + +int C140_Emu::set_rate( int type, double sample_rate, double clock_rate ) +{ + if ( chip ) + { + device_stop_c140( chip ); + chip = 0; + } + + chip = device_start_c140( sample_rate, clock_rate, type ); + if ( !chip ) + return 1; + + reset(); + return 0; +} + +void C140_Emu::reset() +{ + device_reset_c140( chip ); + c140_set_mute_mask( chip, 0 ); +} + +void C140_Emu::write( int addr, int data ) +{ + c140_w( chip, addr, data ); +} + +void C140_Emu::write_rom( int size, int start, int length, void * data ) +{ + c140_write_rom( chip, size, start, length, (const UINT8 *) data ); +} + +void C140_Emu::mute_voices( int mask ) +{ + c140_set_mute_mask( chip, mask ); +} + +void C140_Emu::run( int pair_count, sample_t* out ) +{ + stream_sample_t bufL[ 1024 ]; + stream_sample_t bufR[ 1024 ]; + stream_sample_t * buffers[2] = { bufL, bufR }; + + while (pair_count > 0) + { + int todo = pair_count; + if (todo > 1024) todo = 1024; + c140_update( chip, buffers, todo ); + + for (int i = 0; i < todo; i++) + { + int output_l = bufL [i]; + int output_r = bufR [i]; + output_l += out [0]; + output_r += out [1]; + if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); + if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); + out [0] = output_l; + out [1] = output_r; + out += 2; + } + + pair_count -= todo; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/C140_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/C140_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/C140_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/C140_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,36 +1,36 @@ -// C140 sound chip emulator interface - -// Game_Music_Emu $vers -#ifndef C140_EMU_H -#define C140_EMU_H - -class C140_Emu { - void* chip; -public: - C140_Emu(); - ~C140_Emu(); - - // Sets output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - int set_rate( int type, double sample_rate, double clock_rate ); - - // Resets to power-up state - void reset(); - - // Mutes voice n if bit n (1 << n) of mask is set - enum { channel_count = 24 }; - void mute_voices( int mask ); - - // Writes data to addr - void write( int addr, int data ); - - // Scales ROM size, then writes length bytes from data at start offset - void write_rom( int size, int start, int length, void * data ); - - // Runs and writes pair_count*2 samples to output - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif +// C140 sound chip emulator interface + +// Game_Music_Emu $vers +#ifndef C140_EMU_H +#define C140_EMU_H + +class C140_Emu { + void* chip; +public: + C140_Emu(); + ~C140_Emu(); + + // Sets output sample rate and chip clock rates, in Hz. Returns non-zero + // if error. + int set_rate( int type, double sample_rate, double clock_rate ); + + // Resets to power-up state + void reset(); + + // Mutes voice n if bit n (1 << n) of mask is set + enum { channel_count = 24 }; + void mute_voices( int mask ); + + // Writes data to addr + void write( int addr, int data ); + + // Scales ROM size, then writes length bytes from data at start offset + void write_rom( int size, int start, int length, void * data ); + + // Runs and writes pair_count*2 samples to output + typedef short sample_t; + enum { out_chan_count = 2 }; // stereo + void run( int pair_count, sample_t* out ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/c140.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/c140.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/c140.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/c140.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,58 +1,58 @@ -/* C140.h */ - -#pragma once - -#ifndef __OSDCOMM_H__ -#define __OSDCOMM_H__ -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ - -typedef INT32 stream_sample_t; -typedef UINT32 offs_t; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void c140_update(void * chip, stream_sample_t **outputs, int samples); -void * device_start_c140(int sample_rate, int clock, int banking_type); -void device_stop_c140(void * chip); -void device_reset_c140(void * chip); - -//READ8_DEVICE_HANDLER( c140_r ); -//WRITE8_DEVICE_HANDLER( c140_w ); -UINT8 c140_r(void * chip, offs_t offset); -void c140_w(void * chip, offs_t offset, UINT8 data); - -//void c140_set_base(device_t *device, void *base); -void c140_set_base(void *chip, void *base); - -enum -{ - C140_TYPE_SYSTEM2, - C140_TYPE_SYSTEM21_A, - C140_TYPE_SYSTEM21_B, - C140_TYPE_ASIC219 -}; - -/*typedef struct _c140_interface c140_interface; -struct _c140_interface { - int banking_type; -};*/ - - -void c140_write_rom(void * chip, offs_t ROMSize, offs_t DataStart, offs_t DataLength, - const UINT8* ROMData); - -void c140_set_mute_mask(void * chip, UINT32 MuteMask); - -#ifdef __cplusplus -} -#endif - -//DECLARE_LEGACY_SOUND_DEVICE(C140, c140); +/* C140.h */ + +#pragma once + +#ifndef __OSDCOMM_H__ +#define __OSDCOMM_H__ +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ + +typedef INT32 stream_sample_t; +typedef UINT32 offs_t; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void c140_update(void * chip, stream_sample_t **outputs, int samples); +void * device_start_c140(int sample_rate, int clock, int banking_type); +void device_stop_c140(void * chip); +void device_reset_c140(void * chip); + +//READ8_DEVICE_HANDLER( c140_r ); +//WRITE8_DEVICE_HANDLER( c140_w ); +UINT8 c140_r(void * chip, offs_t offset); +void c140_w(void * chip, offs_t offset, UINT8 data); + +//void c140_set_base(device_t *device, void *base); +void c140_set_base(void *chip, void *base); + +enum +{ + C140_TYPE_SYSTEM2, + C140_TYPE_SYSTEM21_A, + C140_TYPE_SYSTEM21_B, + C140_TYPE_ASIC219 +}; + +/*typedef struct _c140_interface c140_interface; +struct _c140_interface { + int banking_type; +};*/ + + +void c140_write_rom(void * chip, offs_t ROMSize, offs_t DataStart, offs_t DataLength, + const UINT8* ROMData); + +void c140_set_mute_mask(void * chip, UINT32 MuteMask); + +#ifdef __cplusplus +} +#endif + +//DECLARE_LEGACY_SOUND_DEVICE(C140, c140); diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/dac_control.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/dac_control.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/dac_control.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/dac_control.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,367 +1,367 @@ - /************************ - * DAC Stream Control * - ***********************/ -// (Custom Driver to handle PCM Streams of YM2612 DAC and PWM.) -// -// Written on 3 February 2011 by Valley Bell -// Last Update: 25 April 2011 -// -// Only for usage in non-commercial, VGM file related software. - -/* How it basically works: - -1. send command X with data Y at frequency F to chip C -2. do that until you receive a STOP command, or until you sent N commands - -*/ - -#include "dac_control.h" - -#include - -#define INLINE static __inline - -void chip_reg_write(void * context, UINT32 Sample, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset, UINT8 Data); - -typedef struct _dac_control -{ - UINT32 SampleRate; - - // Commands sent to dest-chip - UINT8 DstChipType; - UINT8 DstChipID; - UINT16 DstCommand; - UINT8 CmdSize; - - UINT32 Frequency; // Frequency (Hz) at which the commands are sent - UINT32 DataLen; // to protect from reading beyond End Of Data - const UINT8* Data; - UINT32 DataStart; // Position where to start - UINT8 StepSize; // usually 1, set to 2 for L/R interleaved data - UINT8 StepBase; // usually 0, set to 0/1 for L/R interleaved data - UINT32 CmdsToSend; - - // Running Bits: 0 (01) - is playing - // 2 (04) - loop sample (simple loop from start to end) - // 4 (10) - already sent this command - // 7 (80) - disabled - UINT8 Running; - UINT32 Step; - UINT32 Pos; - UINT32 RemainCmds; - UINT8 DataStep; // always StepSize * CmdSize - - void * context; // context data sent to chip_reg_write -} dac_control; - -#ifndef NULL -#define NULL (void*)0 -#endif - -static void daccontrol_SendCommand(dac_control *chip, UINT32 Sample) -{ - UINT8 Port; - UINT8 Command; - UINT8 Data; - const UINT8* ChipData; - - if (chip->Running & 0x10) // command already sent - return; - if (chip->DataStart + chip->Pos >= chip->DataLen) - return; - - ChipData = chip->Data + (chip->DataStart + chip->Pos); - switch(chip->DstChipType) - { - // Support for the important chips - case 0x02: // YM2612 - Port = (chip->DstCommand & 0xFF00) >> 8; - Command = (chip->DstCommand & 0x00FF) >> 0; - Data = ChipData[0x00]; - chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, Port, Command, Data); - break; - case 0x11: // PWM - Port = (chip->DstCommand & 0x000F) >> 0; - Command = ChipData[0x01] & 0x0F; - Data = ChipData[0x00]; - chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, Port, Command, Data); - break; - // (Generic) Support for other chips (just for completeness) - case 0x00: // SN76496 - Command = (chip->DstCommand & 0x00F0) >> 0; - Data = ChipData[0x00] & 0x0F; - if (Command & 0x10) - { - // Volume Change (4-Bit value) - chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, 0x00, 0x00, Command | Data); - } - else - { - // Frequency Write (10-Bit value) - Port = ((ChipData[0x01] & 0x03) << 4) | ((ChipData[0x00] & 0xF0) >> 4); - chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, 0x00, 0x00, Command | Data); - chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, 0x00, 0x00, Port); - } - break; - case 0x01: // YM2413 - case 0x03: // YM2151 - case 0x09: // YM3812 - case 0x0A: // YM3526 - case 0x0B: // Y8950 - case 0x0F: // YMZ280B - case 0x12: // AY8910 - Command = (chip->DstCommand & 0x00FF) >> 0; - Data = ChipData[0x00]; - chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, 0x00, Command, Data); - break; - case 0x06: // YM2203 - case 0x07: // YM2608 - case 0x08: // YM2610/B - case 0x0C: // YMF262 - case 0x0D: // YMF278B - case 0x0E: // YMF271 - Port = (chip->DstCommand & 0xFF00) >> 8; - Command = (chip->DstCommand & 0x00FF) >> 0; - Data = ChipData[0x00]; - chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, Port, Command, Data); - break; - } - chip->Running |= 0x10; - - return; -} - -INLINE UINT32 muldiv64round(UINT32 Multiplicand, UINT32 Multiplier, UINT32 Divisor) -{ - // Yes, I'm correctly rounding the values. - return (UINT32)(((UINT64)Multiplicand * Multiplier + Multiplier / 2) / Divisor); -} - -void daccontrol_update(void *_chip, UINT32 base_clock, UINT32 samples) -{ - dac_control *chip = (dac_control *) _chip; - UINT32 NewPos; - UINT32 Sample; - - if (chip->Running & 0x80) // disabled - return; - if (! (chip->Running & 0x01)) // stopped - return; - - /*if (samples > 0x20) - { - // very effective Speed Hack for fast seeking - NewPos = chip->Step + (samples - 0x10); - NewPos = muldiv64round(NewPos * chip->DataStep, chip->Frequency, chip->SampleRate); - while(chip->RemainCmds && chip->Pos < NewPos) - { - chip->Pos += chip->DataStep; - chip->RemainCmds --; - } - }*/ - - Sample = 0; - chip->Step += samples; - // Formula: Step * Freq / SampleRate - NewPos = muldiv64round(chip->Step * chip->DataStep, chip->Frequency, chip->SampleRate); - - while(chip->RemainCmds && chip->Pos < NewPos) - { - daccontrol_SendCommand(chip, base_clock + muldiv64round(Sample, chip->SampleRate, chip->Frequency)); - Sample++; - chip->Pos += chip->DataStep; - chip->Running &= ~0x10; - chip->RemainCmds --; - } - - if (! chip->RemainCmds && (chip->Running & 0x04)) - { - // loop back to start - chip->RemainCmds = chip->CmdsToSend; - chip->Step = 0x00; - chip->Pos = 0x00; - } - - if (! chip->RemainCmds) - chip->Running &= ~0x01; // stop - - return; -} - -void * device_start_daccontrol(UINT32 samplerate, void * context) -{ - dac_control *chip; - - chip = (dac_control *) calloc(1, sizeof(dac_control)); - - chip->SampleRate = samplerate; - chip->context = context; - - chip->DstChipType = 0xFF; - chip->DstChipID = 0x00; - chip->DstCommand = 0x0000; - - chip->Running = 0xFF; // disable all actions (except setup_chip) - - return chip; -} - -void device_stop_daccontrol(void *_chip) -{ - dac_control *chip = (dac_control *) _chip; - - free( chip ); -} - -void device_reset_daccontrol(void *_chip) -{ - dac_control *chip = (dac_control *) _chip; - - chip->DstChipType = 0x00; - chip->DstChipID = 0x00; - chip->DstCommand = 0x00; - chip->CmdSize = 0x00; - - chip->Frequency = 0; - chip->DataLen = 0x00; - chip->Data = NULL; - chip->DataStart = 0x00; - chip->StepSize = 0x00; - chip->StepBase = 0x00; - - chip->Running = 0x00; - chip->Step = 0x00; - chip->Pos = 0x00; - chip->RemainCmds = 0x00; - chip->DataStep = 0x00; - - return; -} - -void daccontrol_setup_chip(void *_chip, UINT8 ChType, UINT8 ChNum, UINT16 Command) -{ - dac_control *chip = (dac_control *) _chip; - - chip->DstChipType = ChType; // TypeID (e.g. 0x02 for YM2612) - chip->DstChipID = ChNum; // chip number (to send commands to 1st or 2nd chip) - chip->DstCommand = Command; // Port and Command (would be 0x02A for YM2612) - - switch(chip->DstChipType) - { - case 0x00: // SN76496 - if (chip->DstCommand & 0x0010) - chip->CmdSize = 0x01; // Volume Write - else - chip->CmdSize = 0x02; // Frequency Write - break; - case 0x02: // YM2612 - chip->CmdSize = 0x01; - break; - case 0x11: // PWM - chip->CmdSize = 0x02; - break; - default: - chip->CmdSize = 0x01; - break; - } - chip->DataStep = chip->CmdSize * chip->StepSize; - - return; -} - -void daccontrol_set_data(void *_chip, const UINT8* Data, UINT32 DataLen, UINT8 StepSize, UINT8 StepBase) -{ - dac_control *chip = (dac_control *) _chip; - - if (chip->Running & 0x80) - return; - - if (DataLen && Data != NULL) - { - chip->DataLen = DataLen; - chip->Data = Data; - } - else - { - chip->DataLen = 0x00; - chip->Data = NULL; - } - chip->StepSize = StepSize ? StepSize : 1; - chip->StepBase = StepBase; - chip->DataStep = chip->CmdSize * chip->StepSize; - - return; -} - -void daccontrol_set_frequency(void *_chip, UINT32 Frequency) -{ - dac_control *chip = (dac_control *) _chip; - - if (chip->Running & 0x80) - return; - - chip->Frequency = Frequency; - - return; -} - -void daccontrol_start(void *_chip, UINT32 DataPos, UINT8 LenMode, UINT32 Length) -{ - dac_control *chip = (dac_control *) _chip; - UINT16 CmdStepBase; - - if (chip->Running & 0x80) - return; - - CmdStepBase = chip->CmdSize * chip->StepBase; - if (DataPos != 0xFFFFFFFF) // skip setting DataStart, if Pos == -1 - { - chip->DataStart = DataPos + CmdStepBase; - if (chip->DataStart > chip->DataLen) // catch bad value and force silence - chip->DataStart = chip->DataLen; - } - - switch(LenMode & 0x0F) - { - case DCTRL_LMODE_IGNORE: // Length is already set - ignore - break; - case DCTRL_LMODE_CMDS: // Length = number of commands - chip->CmdsToSend = Length; - break; - case DCTRL_LMODE_MSEC: // Length = time in msec - chip->CmdsToSend = 1000 * Length / chip->Frequency; - break; - case DCTRL_LMODE_TOEND: // play unti stop-command is received (or data-end is reached) - chip->CmdsToSend = (chip->DataLen - (chip->DataStart - CmdStepBase)) / chip->DataStep; - break; - case DCTRL_LMODE_BYTES: // raw byte count - chip->CmdsToSend = Length / chip->DataStep; - break; - default: - chip->CmdsToSend = 0x00; - break; - } - chip->RemainCmds = chip->CmdsToSend; - chip->Step = 0x00; - chip->Pos = 0x00; - - chip->Running &= ~0x04; - chip->Running |= (LenMode & 0x80) ? 0x04 : 0x00; // set loop mode - - chip->Running |= 0x01; // start - chip->Running &= ~0x10; // command isn't yet sent - - return; -} - -void daccontrol_stop(void *_chip) -{ - dac_control *chip = (dac_control *) _chip; - - if (chip->Running & 0x80) - return; - - chip->Running &= ~0x01; // stop - - return; -} + /************************ + * DAC Stream Control * + ***********************/ +// (Custom Driver to handle PCM Streams of YM2612 DAC and PWM.) +// +// Written on 3 February 2011 by Valley Bell +// Last Update: 25 April 2011 +// +// Only for usage in non-commercial, VGM file related software. + +/* How it basically works: + +1. send command X with data Y at frequency F to chip C +2. do that until you receive a STOP command, or until you sent N commands + +*/ + +#include "dac_control.h" + +#include + +#define INLINE static __inline + +void chip_reg_write(void * context, UINT32 Sample, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset, UINT8 Data); + +typedef struct _dac_control +{ + UINT32 SampleRate; + + // Commands sent to dest-chip + UINT8 DstChipType; + UINT8 DstChipID; + UINT16 DstCommand; + UINT8 CmdSize; + + UINT32 Frequency; // Frequency (Hz) at which the commands are sent + UINT32 DataLen; // to protect from reading beyond End Of Data + const UINT8* Data; + UINT32 DataStart; // Position where to start + UINT8 StepSize; // usually 1, set to 2 for L/R interleaved data + UINT8 StepBase; // usually 0, set to 0/1 for L/R interleaved data + UINT32 CmdsToSend; + + // Running Bits: 0 (01) - is playing + // 2 (04) - loop sample (simple loop from start to end) + // 4 (10) - already sent this command + // 7 (80) - disabled + UINT8 Running; + UINT32 Step; + UINT32 Pos; + UINT32 RemainCmds; + UINT8 DataStep; // always StepSize * CmdSize + + void * context; // context data sent to chip_reg_write +} dac_control; + +#ifndef NULL +#define NULL (void*)0 +#endif + +static void daccontrol_SendCommand(dac_control *chip, UINT32 Sample) +{ + UINT8 Port; + UINT8 Command; + UINT8 Data; + const UINT8* ChipData; + + if (chip->Running & 0x10) // command already sent + return; + if (chip->DataStart + chip->Pos >= chip->DataLen) + return; + + ChipData = chip->Data + (chip->DataStart + chip->Pos); + switch(chip->DstChipType) + { + // Support for the important chips + case 0x02: // YM2612 + Port = (chip->DstCommand & 0xFF00) >> 8; + Command = (chip->DstCommand & 0x00FF) >> 0; + Data = ChipData[0x00]; + chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, Port, Command, Data); + break; + case 0x11: // PWM + Port = (chip->DstCommand & 0x000F) >> 0; + Command = ChipData[0x01] & 0x0F; + Data = ChipData[0x00]; + chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, Port, Command, Data); + break; + // (Generic) Support for other chips (just for completeness) + case 0x00: // SN76496 + Command = (chip->DstCommand & 0x00F0) >> 0; + Data = ChipData[0x00] & 0x0F; + if (Command & 0x10) + { + // Volume Change (4-Bit value) + chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, 0x00, 0x00, Command | Data); + } + else + { + // Frequency Write (10-Bit value) + Port = ((ChipData[0x01] & 0x03) << 4) | ((ChipData[0x00] & 0xF0) >> 4); + chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, 0x00, 0x00, Command | Data); + chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, 0x00, 0x00, Port); + } + break; + case 0x01: // YM2413 + case 0x03: // YM2151 + case 0x09: // YM3812 + case 0x0A: // YM3526 + case 0x0B: // Y8950 + case 0x0F: // YMZ280B + case 0x12: // AY8910 + Command = (chip->DstCommand & 0x00FF) >> 0; + Data = ChipData[0x00]; + chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, 0x00, Command, Data); + break; + case 0x06: // YM2203 + case 0x07: // YM2608 + case 0x08: // YM2610/B + case 0x0C: // YMF262 + case 0x0D: // YMF278B + case 0x0E: // YMF271 + Port = (chip->DstCommand & 0xFF00) >> 8; + Command = (chip->DstCommand & 0x00FF) >> 0; + Data = ChipData[0x00]; + chip_reg_write(chip->context, Sample, chip->DstChipType, chip->DstChipID, Port, Command, Data); + break; + } + chip->Running |= 0x10; + + return; +} + +INLINE UINT32 muldiv64round(UINT32 Multiplicand, UINT32 Multiplier, UINT32 Divisor) +{ + // Yes, I'm correctly rounding the values. + return (UINT32)(((UINT64)Multiplicand * Multiplier + Multiplier / 2) / Divisor); +} + +void daccontrol_update(void *_chip, UINT32 base_clock, UINT32 samples) +{ + dac_control *chip = (dac_control *) _chip; + UINT32 NewPos; + UINT32 Sample; + + if (chip->Running & 0x80) // disabled + return; + if (! (chip->Running & 0x01)) // stopped + return; + + /*if (samples > 0x20) + { + // very effective Speed Hack for fast seeking + NewPos = chip->Step + (samples - 0x10); + NewPos = muldiv64round(NewPos * chip->DataStep, chip->Frequency, chip->SampleRate); + while(chip->RemainCmds && chip->Pos < NewPos) + { + chip->Pos += chip->DataStep; + chip->RemainCmds --; + } + }*/ + + Sample = 0; + chip->Step += samples; + // Formula: Step * Freq / SampleRate + NewPos = muldiv64round(chip->Step * chip->DataStep, chip->Frequency, chip->SampleRate); + + while(chip->RemainCmds && chip->Pos < NewPos) + { + daccontrol_SendCommand(chip, base_clock + muldiv64round(Sample, chip->SampleRate, chip->Frequency)); + Sample++; + chip->Pos += chip->DataStep; + chip->Running &= ~0x10; + chip->RemainCmds --; + } + + if (! chip->RemainCmds && (chip->Running & 0x04)) + { + // loop back to start + chip->RemainCmds = chip->CmdsToSend; + chip->Step = 0x00; + chip->Pos = 0x00; + } + + if (! chip->RemainCmds) + chip->Running &= ~0x01; // stop + + return; +} + +void * device_start_daccontrol(UINT32 samplerate, void * context) +{ + dac_control *chip; + + chip = (dac_control *) calloc(1, sizeof(dac_control)); + + chip->SampleRate = samplerate; + chip->context = context; + + chip->DstChipType = 0xFF; + chip->DstChipID = 0x00; + chip->DstCommand = 0x0000; + + chip->Running = 0xFF; // disable all actions (except setup_chip) + + return chip; +} + +void device_stop_daccontrol(void *_chip) +{ + dac_control *chip = (dac_control *) _chip; + + free( chip ); +} + +void device_reset_daccontrol(void *_chip) +{ + dac_control *chip = (dac_control *) _chip; + + chip->DstChipType = 0x00; + chip->DstChipID = 0x00; + chip->DstCommand = 0x00; + chip->CmdSize = 0x00; + + chip->Frequency = 0; + chip->DataLen = 0x00; + chip->Data = NULL; + chip->DataStart = 0x00; + chip->StepSize = 0x00; + chip->StepBase = 0x00; + + chip->Running = 0x00; + chip->Step = 0x00; + chip->Pos = 0x00; + chip->RemainCmds = 0x00; + chip->DataStep = 0x00; + + return; +} + +void daccontrol_setup_chip(void *_chip, UINT8 ChType, UINT8 ChNum, UINT16 Command) +{ + dac_control *chip = (dac_control *) _chip; + + chip->DstChipType = ChType; // TypeID (e.g. 0x02 for YM2612) + chip->DstChipID = ChNum; // chip number (to send commands to 1st or 2nd chip) + chip->DstCommand = Command; // Port and Command (would be 0x02A for YM2612) + + switch(chip->DstChipType) + { + case 0x00: // SN76496 + if (chip->DstCommand & 0x0010) + chip->CmdSize = 0x01; // Volume Write + else + chip->CmdSize = 0x02; // Frequency Write + break; + case 0x02: // YM2612 + chip->CmdSize = 0x01; + break; + case 0x11: // PWM + chip->CmdSize = 0x02; + break; + default: + chip->CmdSize = 0x01; + break; + } + chip->DataStep = chip->CmdSize * chip->StepSize; + + return; +} + +void daccontrol_set_data(void *_chip, const UINT8* Data, UINT32 DataLen, UINT8 StepSize, UINT8 StepBase) +{ + dac_control *chip = (dac_control *) _chip; + + if (chip->Running & 0x80) + return; + + if (DataLen && Data != NULL) + { + chip->DataLen = DataLen; + chip->Data = Data; + } + else + { + chip->DataLen = 0x00; + chip->Data = NULL; + } + chip->StepSize = StepSize ? StepSize : 1; + chip->StepBase = StepBase; + chip->DataStep = chip->CmdSize * chip->StepSize; + + return; +} + +void daccontrol_set_frequency(void *_chip, UINT32 Frequency) +{ + dac_control *chip = (dac_control *) _chip; + + if (chip->Running & 0x80) + return; + + chip->Frequency = Frequency; + + return; +} + +void daccontrol_start(void *_chip, UINT32 DataPos, UINT8 LenMode, UINT32 Length) +{ + dac_control *chip = (dac_control *) _chip; + UINT16 CmdStepBase; + + if (chip->Running & 0x80) + return; + + CmdStepBase = chip->CmdSize * chip->StepBase; + if (DataPos != 0xFFFFFFFF) // skip setting DataStart, if Pos == -1 + { + chip->DataStart = DataPos + CmdStepBase; + if (chip->DataStart > chip->DataLen) // catch bad value and force silence + chip->DataStart = chip->DataLen; + } + + switch(LenMode & 0x0F) + { + case DCTRL_LMODE_IGNORE: // Length is already set - ignore + break; + case DCTRL_LMODE_CMDS: // Length = number of commands + chip->CmdsToSend = Length; + break; + case DCTRL_LMODE_MSEC: // Length = time in msec + chip->CmdsToSend = 1000 * Length / chip->Frequency; + break; + case DCTRL_LMODE_TOEND: // play unti stop-command is received (or data-end is reached) + chip->CmdsToSend = (chip->DataLen - (chip->DataStart - CmdStepBase)) / chip->DataStep; + break; + case DCTRL_LMODE_BYTES: // raw byte count + chip->CmdsToSend = Length / chip->DataStep; + break; + default: + chip->CmdsToSend = 0x00; + break; + } + chip->RemainCmds = chip->CmdsToSend; + chip->Step = 0x00; + chip->Pos = 0x00; + + chip->Running &= ~0x04; + chip->Running |= (LenMode & 0x80) ? 0x04 : 0x00; // set loop mode + + chip->Running |= 0x01; // start + chip->Running &= ~0x10; // command isn't yet sent + + return; +} + +void daccontrol_stop(void *_chip) +{ + dac_control *chip = (dac_control *) _chip; + + if (chip->Running & 0x80) + return; + + chip->Running &= ~0x01; // stop + + return; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/dac_control.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/dac_control.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/dac_control.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/dac_control.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,44 +1,44 @@ -#ifndef _DAC_CONTROL_H_ -#define _DAC_CONTROL_H_ - -#ifndef __OSDCOMM_H__ -#define __OSDCOMM_H__ -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef unsigned long long UINT64; /* unsigned 64bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ -typedef signed long long INT64; /* signed 64bit */ - -typedef INT32 stream_sample_t; -typedef UINT32 offs_t; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void * device_start_daccontrol(UINT32 samplerate, void *context); -void device_stop_daccontrol(void * chip); - -void daccontrol_update(void * chip, UINT32 base_clock, UINT32 samples); -void device_reset_daccontrol(void * chip); -void daccontrol_setup_chip(void * chip, UINT8 ChType, UINT8 ChNum, UINT16 Command); -void daccontrol_set_data(void *chip, const UINT8* Data, UINT32 DataLen, UINT8 StepSize, UINT8 StepBase); -void daccontrol_set_frequency(void *chip, UINT32 Frequency); -void daccontrol_start(void *chip, UINT32 DataPos, UINT8 LenMode, UINT32 Length); -void daccontrol_stop(void *chip); - -#define DCTRL_LMODE_IGNORE 0x00 -#define DCTRL_LMODE_CMDS 0x01 -#define DCTRL_LMODE_MSEC 0x02 -#define DCTRL_LMODE_TOEND 0x03 -#define DCTRL_LMODE_BYTES 0x0F - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _DAC_CONTROL_H_ +#define _DAC_CONTROL_H_ + +#ifndef __OSDCOMM_H__ +#define __OSDCOMM_H__ +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef unsigned long long UINT64; /* unsigned 64bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +typedef signed long long INT64; /* signed 64bit */ + +typedef INT32 stream_sample_t; +typedef UINT32 offs_t; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void * device_start_daccontrol(UINT32 samplerate, void *context); +void device_stop_daccontrol(void * chip); + +void daccontrol_update(void * chip, UINT32 base_clock, UINT32 samples); +void device_reset_daccontrol(void * chip); +void daccontrol_setup_chip(void * chip, UINT8 ChType, UINT8 ChNum, UINT16 Command); +void daccontrol_set_data(void *chip, const UINT8* Data, UINT32 DataLen, UINT8 StepSize, UINT8 StepBase); +void daccontrol_set_frequency(void *chip, UINT32 Frequency); +void daccontrol_start(void *chip, UINT32 DataPos, UINT8 LenMode, UINT32 Length); +void daccontrol_stop(void *chip); + +#define DCTRL_LMODE_IGNORE 0x00 +#define DCTRL_LMODE_CMDS 0x01 +#define DCTRL_LMODE_MSEC 0x02 +#define DCTRL_LMODE_TOEND 0x03 +#define DCTRL_LMODE_BYTES 0x0F + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Dual_Resampler.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Dual_Resampler.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Dual_Resampler.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Dual_Resampler.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,315 +1,315 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Dual_Resampler.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// TODO: fix this. hack since resampler holds back some output. -int const resampler_extra = 34; - -int const stereo = 2; - -Dual_Resampler::Dual_Resampler() { } - -Dual_Resampler::~Dual_Resampler() { } - -blargg_err_t Dual_Resampler::reset( int pairs ) -{ - // expand allocations a bit - RETURN_ERR( sample_buf.resize( (pairs + (pairs >> 2)) * 2 ) ); - resize( pairs ); - resampler_size = oversamples_per_frame + (oversamples_per_frame >> 2); - RETURN_ERR( resampler.resize_buffer( resampler_size ) ); - resampler.clear(); - return blargg_ok; -} - -void Dual_Resampler::resize( int pairs ) -{ - int new_sample_buf_size = pairs * 2; - //new_sample_buf_size = new_sample_buf_size / 4 * 4; // TODO: needed only for 3:2 downsampler - if ( sample_buf_size != new_sample_buf_size ) - { - if ( (unsigned) new_sample_buf_size > sample_buf.size() ) - { - check( false ); - return; - } - sample_buf_size = new_sample_buf_size; - oversamples_per_frame = int (pairs * resampler.rate()) * 2 + 2; - clear(); - } -} - -void Dual_Resampler::clear() -{ - buf_pos = buffered = 0; - resampler.clear(); -} - - -int Dual_Resampler::play_frame_( Stereo_Buffer& stereo_buf, dsample_t out [], Stereo_Buffer** secondary_buf_set, int secondary_buf_set_count ) -{ - int pair_count = sample_buf_size >> 1; - blip_time_t blip_time = stereo_buf.center()->count_clocks( pair_count ); - int sample_count = oversamples_per_frame - resampler.written() + resampler_extra; - - int new_count = set_callback.f( set_callback.data, blip_time, sample_count, resampler.buffer() ); - assert( new_count < resampler_size ); - - stereo_buf.end_frame( blip_time ); - assert( stereo_buf.samples_avail() == pair_count * 2 ); - if ( secondary_buf_set && secondary_buf_set_count ) - { - for ( int i = 0; i < secondary_buf_set_count; i++ ) - { - Stereo_Buffer * second_buf = secondary_buf_set[i]; - blip_time_t blip_time_2 = second_buf->center()->count_clocks( pair_count ); - second_buf->end_frame( blip_time_2 ); - assert( second_buf->samples_avail() == pair_count * 2 ); - } - } - - resampler.write( new_count ); - - int count = resampler.read( sample_buf.begin(), sample_buf_size ); - - mix_samples( stereo_buf, out, count, secondary_buf_set, secondary_buf_set_count ); - - pair_count = count >> 1; - stereo_buf.left()->remove_samples( pair_count ); - stereo_buf.right()->remove_samples( pair_count ); - stereo_buf.center()->remove_samples( pair_count ); - - if ( secondary_buf_set && secondary_buf_set_count ) - { - for ( int i = 0; i < secondary_buf_set_count; i++ ) - { - Stereo_Buffer * second_buf = secondary_buf_set[i]; - second_buf->left()->remove_samples( pair_count ); - second_buf->right()->remove_samples( pair_count ); - second_buf->center()->remove_samples( pair_count ); - } - } - - return count; -} - -void Dual_Resampler::dual_play( int count, dsample_t out [], Stereo_Buffer& stereo_buf, Stereo_Buffer** secondary_buf_set, int secondary_buf_set_count ) -{ - // empty extra buffer - int remain = buffered - buf_pos; - if ( remain ) - { - if ( remain > count ) - remain = count; - count -= remain; - memcpy( out, &sample_buf [buf_pos], remain * sizeof *out ); - out += remain; - buf_pos += remain; - } - - // entire frames - while ( count >= sample_buf_size ) - { - buf_pos = buffered = play_frame_( stereo_buf, out, secondary_buf_set, secondary_buf_set_count ); - out += buffered; - count -= buffered; - } - - while (count > 0) - { - buffered = play_frame_( stereo_buf, sample_buf.begin(), secondary_buf_set, secondary_buf_set_count ); - if ( buffered >= count ) - { - buf_pos = count; - memcpy( out, sample_buf.begin(), count * sizeof *out ); - out += count; - count = 0; - } - else - { - memcpy( out, sample_buf.begin(), buffered * sizeof *out ); - out += buffered; - count -= buffered; - } - } -} - -void Dual_Resampler::mix_samples( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count, Stereo_Buffer** secondary_buf_set, int secondary_buf_set_count ) -{ - // lol hax - if ( ((Tracked_Blip_Buffer*)stereo_buf.left())->non_silent() | ((Tracked_Blip_Buffer*)stereo_buf.right())->non_silent() ) - mix_stereo( stereo_buf, out_, count ); - else - mix_mono( stereo_buf, out_, count ); - - if ( secondary_buf_set && secondary_buf_set_count ) - { - for ( int i = 0; i < secondary_buf_set_count; i++ ) - { - Stereo_Buffer * second_buf = secondary_buf_set[i]; - if ( ((Tracked_Blip_Buffer*)second_buf->left())->non_silent() | ((Tracked_Blip_Buffer*)second_buf->right())->non_silent() ) - mix_extra_stereo( *second_buf, out_, count ); - else - mix_extra_mono( *second_buf, out_, count ); - } - } -} - -void Dual_Resampler::mix_mono( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count ) -{ - int const bass = BLIP_READER_BASS( *stereo_buf.center() ); - BLIP_READER_BEGIN( sn, *stereo_buf.center() ); - - count >>= 1; - BLIP_READER_ADJ_( sn, count ); - - typedef dsample_t stereo_dsample_t [2]; - stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; - stereo_dsample_t const* BLARGG_RESTRICT in = - (stereo_dsample_t const*) sample_buf.begin() + count; - int offset = -count; - int const gain = gain_; - do - { - int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16); - BLIP_READER_NEXT_IDX_( sn, bass, offset ); - - int l = (in [offset] [0] * gain >> gain_bits) + s; - int r = (in [offset] [1] * gain >> gain_bits) + s; - - BLIP_CLAMP( l, l ); - out [offset] [0] = (blip_sample_t) l; - - BLIP_CLAMP( r, r ); - out [offset] [1] = (blip_sample_t) r; - } - while ( ++offset ); - - BLIP_READER_END( sn, *stereo_buf.center() ); -} - -void Dual_Resampler::mix_stereo( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count ) -{ - int const bass = BLIP_READER_BASS( *stereo_buf.center() ); - BLIP_READER_BEGIN( snc, *stereo_buf.center() ); - BLIP_READER_BEGIN( snl, *stereo_buf.left() ); - BLIP_READER_BEGIN( snr, *stereo_buf.right() ); - - count >>= 1; - BLIP_READER_ADJ_( snc, count ); - BLIP_READER_ADJ_( snl, count ); - BLIP_READER_ADJ_( snr, count ); - - typedef dsample_t stereo_dsample_t [2]; - stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; - stereo_dsample_t const* BLARGG_RESTRICT in = - (stereo_dsample_t const*) sample_buf.begin() + count; - int offset = -count; - int const gain = gain_; - do - { - int sc = BLIP_READER_READ_RAW( snc ) >> (blip_sample_bits - 16); - int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16); - int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16); - BLIP_READER_NEXT_IDX_( snc, bass, offset ); - BLIP_READER_NEXT_IDX_( snl, bass, offset ); - BLIP_READER_NEXT_IDX_( snr, bass, offset ); - - int l = (in [offset] [0] * gain >> gain_bits) + sl + sc; - int r = (in [offset] [1] * gain >> gain_bits) + sr + sc; - - BLIP_CLAMP( l, l ); - out [offset] [0] = (blip_sample_t) l; - - BLIP_CLAMP( r, r ); - out [offset] [1] = (blip_sample_t) r; - } - while ( ++offset ); - - BLIP_READER_END( snc, *stereo_buf.center() ); - BLIP_READER_END( snl, *stereo_buf.left() ); - BLIP_READER_END( snr, *stereo_buf.right() ); -} - -void Dual_Resampler::mix_extra_mono( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count ) -{ - int const bass = BLIP_READER_BASS( *stereo_buf.center() ); - BLIP_READER_BEGIN( sn, *stereo_buf.center() ); - - count >>= 1; - BLIP_READER_ADJ_( sn, count ); - - typedef dsample_t stereo_dsample_t [2]; - stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; - int offset = -count; - do - { - int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16); - BLIP_READER_NEXT_IDX_( sn, bass, offset ); - - int l = out [offset] [0] + s; - int r = out [offset] [1] + s; - - BLIP_CLAMP( l, l ); - out [offset] [0] = (blip_sample_t) l; - - BLIP_CLAMP( r, r ); - out [offset] [1] = (blip_sample_t) r; - } - while ( ++offset ); - - BLIP_READER_END( sn, *stereo_buf.center() ); -} - -void Dual_Resampler::mix_extra_stereo( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count ) -{ - int const bass = BLIP_READER_BASS( *stereo_buf.center() ); - BLIP_READER_BEGIN( snc, *stereo_buf.center() ); - BLIP_READER_BEGIN( snl, *stereo_buf.left() ); - BLIP_READER_BEGIN( snr, *stereo_buf.right() ); - - count >>= 1; - BLIP_READER_ADJ_( snc, count ); - BLIP_READER_ADJ_( snl, count ); - BLIP_READER_ADJ_( snr, count ); - - typedef dsample_t stereo_dsample_t [2]; - stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; - int offset = -count; - do - { - int sc = BLIP_READER_READ_RAW( snc ) >> (blip_sample_bits - 16); - int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16); - int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16); - BLIP_READER_NEXT_IDX_( snc, bass, offset ); - BLIP_READER_NEXT_IDX_( snl, bass, offset ); - BLIP_READER_NEXT_IDX_( snr, bass, offset ); - - int l = out [offset] [0] + sl + sc; - int r = out [offset] [1] + sr + sc; - - BLIP_CLAMP( l, l ); - out [offset] [0] = (blip_sample_t) l; - - BLIP_CLAMP( r, r ); - out [offset] [1] = (blip_sample_t) r; - } - while ( ++offset ); - - BLIP_READER_END( snc, *stereo_buf.center() ); - BLIP_READER_END( snl, *stereo_buf.left() ); - BLIP_READER_END( snr, *stereo_buf.right() ); -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Dual_Resampler.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// TODO: fix this. hack since resampler holds back some output. +int const resampler_extra = 34; + +int const stereo = 2; + +Dual_Resampler::Dual_Resampler() { } + +Dual_Resampler::~Dual_Resampler() { } + +blargg_err_t Dual_Resampler::reset( int pairs ) +{ + // expand allocations a bit + RETURN_ERR( sample_buf.resize( (pairs + (pairs >> 2)) * 2 ) ); + resize( pairs ); + resampler_size = oversamples_per_frame + (oversamples_per_frame >> 2); + RETURN_ERR( resampler.resize_buffer( resampler_size ) ); + resampler.clear(); + return blargg_ok; +} + +void Dual_Resampler::resize( int pairs ) +{ + int new_sample_buf_size = pairs * 2; + //new_sample_buf_size = new_sample_buf_size / 4 * 4; // TODO: needed only for 3:2 downsampler + if ( sample_buf_size != new_sample_buf_size ) + { + if ( (unsigned) new_sample_buf_size > sample_buf.size() ) + { + check( false ); + return; + } + sample_buf_size = new_sample_buf_size; + oversamples_per_frame = int (pairs * resampler.rate()) * 2 + 2; + clear(); + } +} + +void Dual_Resampler::clear() +{ + buf_pos = buffered = 0; + resampler.clear(); +} + + +int Dual_Resampler::play_frame_( Stereo_Buffer& stereo_buf, dsample_t out [], Stereo_Buffer** secondary_buf_set, int secondary_buf_set_count ) +{ + int pair_count = sample_buf_size >> 1; + blip_time_t blip_time = stereo_buf.center()->count_clocks( pair_count ); + int sample_count = oversamples_per_frame - resampler.written() + resampler_extra; + + int new_count = set_callback.f( set_callback.data, blip_time, sample_count, resampler.buffer() ); + assert( new_count < resampler_size ); + + stereo_buf.end_frame( blip_time ); + assert( stereo_buf.samples_avail() == pair_count * 2 ); + if ( secondary_buf_set && secondary_buf_set_count ) + { + for ( int i = 0; i < secondary_buf_set_count; i++ ) + { + Stereo_Buffer * second_buf = secondary_buf_set[i]; + blip_time_t blip_time_2 = second_buf->center()->count_clocks( pair_count ); + second_buf->end_frame( blip_time_2 ); + assert( second_buf->samples_avail() == pair_count * 2 ); + } + } + + resampler.write( new_count ); + + int count = resampler.read( sample_buf.begin(), sample_buf_size ); + + mix_samples( stereo_buf, out, count, secondary_buf_set, secondary_buf_set_count ); + + pair_count = count >> 1; + stereo_buf.left()->remove_samples( pair_count ); + stereo_buf.right()->remove_samples( pair_count ); + stereo_buf.center()->remove_samples( pair_count ); + + if ( secondary_buf_set && secondary_buf_set_count ) + { + for ( int i = 0; i < secondary_buf_set_count; i++ ) + { + Stereo_Buffer * second_buf = secondary_buf_set[i]; + second_buf->left()->remove_samples( pair_count ); + second_buf->right()->remove_samples( pair_count ); + second_buf->center()->remove_samples( pair_count ); + } + } + + return count; +} + +void Dual_Resampler::dual_play( int count, dsample_t out [], Stereo_Buffer& stereo_buf, Stereo_Buffer** secondary_buf_set, int secondary_buf_set_count ) +{ + // empty extra buffer + int remain = buffered - buf_pos; + if ( remain ) + { + if ( remain > count ) + remain = count; + count -= remain; + memcpy( out, &sample_buf [buf_pos], remain * sizeof *out ); + out += remain; + buf_pos += remain; + } + + // entire frames + while ( count >= sample_buf_size ) + { + buf_pos = buffered = play_frame_( stereo_buf, out, secondary_buf_set, secondary_buf_set_count ); + out += buffered; + count -= buffered; + } + + while (count > 0) + { + buffered = play_frame_( stereo_buf, sample_buf.begin(), secondary_buf_set, secondary_buf_set_count ); + if ( buffered >= count ) + { + buf_pos = count; + memcpy( out, sample_buf.begin(), count * sizeof *out ); + out += count; + count = 0; + } + else + { + memcpy( out, sample_buf.begin(), buffered * sizeof *out ); + out += buffered; + count -= buffered; + } + } +} + +void Dual_Resampler::mix_samples( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count, Stereo_Buffer** secondary_buf_set, int secondary_buf_set_count ) +{ + // lol hax + if ( ((Tracked_Blip_Buffer*)stereo_buf.left())->non_silent() | ((Tracked_Blip_Buffer*)stereo_buf.right())->non_silent() ) + mix_stereo( stereo_buf, out_, count ); + else + mix_mono( stereo_buf, out_, count ); + + if ( secondary_buf_set && secondary_buf_set_count ) + { + for ( int i = 0; i < secondary_buf_set_count; i++ ) + { + Stereo_Buffer * second_buf = secondary_buf_set[i]; + if ( ((Tracked_Blip_Buffer*)second_buf->left())->non_silent() | ((Tracked_Blip_Buffer*)second_buf->right())->non_silent() ) + mix_extra_stereo( *second_buf, out_, count ); + else + mix_extra_mono( *second_buf, out_, count ); + } + } +} + +void Dual_Resampler::mix_mono( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count ) +{ + int const bass = BLIP_READER_BASS( *stereo_buf.center() ); + BLIP_READER_BEGIN( sn, *stereo_buf.center() ); + + count >>= 1; + BLIP_READER_ADJ_( sn, count ); + + typedef dsample_t stereo_dsample_t [2]; + stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; + stereo_dsample_t const* BLARGG_RESTRICT in = + (stereo_dsample_t const*) sample_buf.begin() + count; + int offset = -count; + int const gain = gain_; + do + { + int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16); + BLIP_READER_NEXT_IDX_( sn, bass, offset ); + + int l = (in [offset] [0] * gain >> gain_bits) + s; + int r = (in [offset] [1] * gain >> gain_bits) + s; + + BLIP_CLAMP( l, l ); + out [offset] [0] = (blip_sample_t) l; + + BLIP_CLAMP( r, r ); + out [offset] [1] = (blip_sample_t) r; + } + while ( ++offset ); + + BLIP_READER_END( sn, *stereo_buf.center() ); +} + +void Dual_Resampler::mix_stereo( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count ) +{ + int const bass = BLIP_READER_BASS( *stereo_buf.center() ); + BLIP_READER_BEGIN( snc, *stereo_buf.center() ); + BLIP_READER_BEGIN( snl, *stereo_buf.left() ); + BLIP_READER_BEGIN( snr, *stereo_buf.right() ); + + count >>= 1; + BLIP_READER_ADJ_( snc, count ); + BLIP_READER_ADJ_( snl, count ); + BLIP_READER_ADJ_( snr, count ); + + typedef dsample_t stereo_dsample_t [2]; + stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; + stereo_dsample_t const* BLARGG_RESTRICT in = + (stereo_dsample_t const*) sample_buf.begin() + count; + int offset = -count; + int const gain = gain_; + do + { + int sc = BLIP_READER_READ_RAW( snc ) >> (blip_sample_bits - 16); + int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16); + int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16); + BLIP_READER_NEXT_IDX_( snc, bass, offset ); + BLIP_READER_NEXT_IDX_( snl, bass, offset ); + BLIP_READER_NEXT_IDX_( snr, bass, offset ); + + int l = (in [offset] [0] * gain >> gain_bits) + sl + sc; + int r = (in [offset] [1] * gain >> gain_bits) + sr + sc; + + BLIP_CLAMP( l, l ); + out [offset] [0] = (blip_sample_t) l; + + BLIP_CLAMP( r, r ); + out [offset] [1] = (blip_sample_t) r; + } + while ( ++offset ); + + BLIP_READER_END( snc, *stereo_buf.center() ); + BLIP_READER_END( snl, *stereo_buf.left() ); + BLIP_READER_END( snr, *stereo_buf.right() ); +} + +void Dual_Resampler::mix_extra_mono( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count ) +{ + int const bass = BLIP_READER_BASS( *stereo_buf.center() ); + BLIP_READER_BEGIN( sn, *stereo_buf.center() ); + + count >>= 1; + BLIP_READER_ADJ_( sn, count ); + + typedef dsample_t stereo_dsample_t [2]; + stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; + int offset = -count; + do + { + int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16); + BLIP_READER_NEXT_IDX_( sn, bass, offset ); + + int l = out [offset] [0] + s; + int r = out [offset] [1] + s; + + BLIP_CLAMP( l, l ); + out [offset] [0] = (blip_sample_t) l; + + BLIP_CLAMP( r, r ); + out [offset] [1] = (blip_sample_t) r; + } + while ( ++offset ); + + BLIP_READER_END( sn, *stereo_buf.center() ); +} + +void Dual_Resampler::mix_extra_stereo( Stereo_Buffer& stereo_buf, dsample_t out_ [], int count ) +{ + int const bass = BLIP_READER_BASS( *stereo_buf.center() ); + BLIP_READER_BEGIN( snc, *stereo_buf.center() ); + BLIP_READER_BEGIN( snl, *stereo_buf.left() ); + BLIP_READER_BEGIN( snr, *stereo_buf.right() ); + + count >>= 1; + BLIP_READER_ADJ_( snc, count ); + BLIP_READER_ADJ_( snl, count ); + BLIP_READER_ADJ_( snr, count ); + + typedef dsample_t stereo_dsample_t [2]; + stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; + int offset = -count; + do + { + int sc = BLIP_READER_READ_RAW( snc ) >> (blip_sample_bits - 16); + int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16); + int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16); + BLIP_READER_NEXT_IDX_( snc, bass, offset ); + BLIP_READER_NEXT_IDX_( snl, bass, offset ); + BLIP_READER_NEXT_IDX_( snr, bass, offset ); + + int l = out [offset] [0] + sl + sc; + int r = out [offset] [1] + sr + sc; + + BLIP_CLAMP( l, l ); + out [offset] [0] = (blip_sample_t) l; + + BLIP_CLAMP( r, r ); + out [offset] [1] = (blip_sample_t) r; + } + while ( ++offset ); + + BLIP_READER_END( snc, *stereo_buf.center() ); + BLIP_READER_END( snl, *stereo_buf.left() ); + BLIP_READER_END( snr, *stereo_buf.right() ); +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Effects_Buffer.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Effects_Buffer.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Effects_Buffer.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Effects_Buffer.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,23 +1,23 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Effects_Buffer.h" - -/* Copyright (C) 2006-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Effects_Buffer.h" + +/* Copyright (C) 2006-2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#ifdef BLARGG_ENABLE_OPTIMIZER + #include BLARGG_ENABLE_OPTIMIZER +#endif int const fixed_shift = 12; #define TO_FIXED( f ) fixed_t ((f) * ((fixed_t) 1 << fixed_shift)) @@ -25,616 +25,616 @@ int const max_read = 2560; // determines minimum delay -Effects_Buffer::Effects_Buffer( int max_bufs, int echo_size_ ) : Multi_Buffer( stereo ) -{ - echo_size = max( max_read * (int) stereo, echo_size_ & ~1 ); - clock_rate_ = 0; - bass_freq_ = 90; - bufs = NULL; - bufs_size = 0; - bufs_max = max( max_bufs, (int) extra_chans ); - no_echo = true; - no_effects = true; - - // defaults - config_.enabled = false; - config_.delay [0] = 120; - config_.delay [1] = 122; - config_.feedback = 0.2f; - config_.treble = 0.4f; - - static float const sep = 0.8f; - config_.side_chans [0].pan = -sep; - config_.side_chans [1].pan = +sep; - config_.side_chans [0].vol = 1.0f; - config_.side_chans [1].vol = 1.0f; - - memset( &s, 0, sizeof s ); - clear(); -} - -Effects_Buffer::~Effects_Buffer() -{ - delete_bufs(); -} - -// avoid using new [] -blargg_err_t Effects_Buffer::new_bufs( int size ) -{ - bufs = (buf_t*) malloc( size * sizeof *bufs ); - CHECK_ALLOC( bufs ); - for ( int i = 0; i < size; i++ ) - new (bufs + i) buf_t; - bufs_size = size; - return blargg_ok; -} - -void Effects_Buffer::delete_bufs() -{ - if ( bufs ) - { - for ( int i = bufs_size; --i >= 0; ) - bufs [i].~buf_t(); - free( bufs ); - bufs = NULL; - } - bufs_size = 0; -} - -blargg_err_t Effects_Buffer::set_sample_rate( int rate, int msec ) -{ - // extra to allow farther past-the-end pointers - mixer.samples_read = 0; - RETURN_ERR( echo.resize( echo_size + stereo ) ); - return Multi_Buffer::set_sample_rate( rate, msec ); -} - -void Effects_Buffer::clock_rate( int rate ) -{ - clock_rate_ = rate; - for ( int i = bufs_size; --i >= 0; ) - bufs [i].clock_rate( clock_rate_ ); -} - -void Effects_Buffer::bass_freq( int freq ) -{ - bass_freq_ = freq; - for ( int i = bufs_size; --i >= 0; ) - bufs [i].bass_freq( bass_freq_ ); -} - -blargg_err_t Effects_Buffer::set_channel_count( int count, int const types [] ) -{ - RETURN_ERR( Multi_Buffer::set_channel_count( count, types ) ); - - delete_bufs(); - - mixer.samples_read = 0; - - RETURN_ERR( chans.resize( count + extra_chans ) ); - - RETURN_ERR( new_bufs( min( bufs_max, count + extra_chans ) ) ); - - for ( int i = bufs_size; --i >= 0; ) - RETURN_ERR( bufs [i].set_sample_rate( sample_rate(), length() ) ); - - for ( int i = chans.size(); --i >= 0; ) - { - chan_t& ch = chans [i]; - ch.cfg.vol = 1.0f; - ch.cfg.pan = 0.0f; - ch.cfg.surround = false; - ch.cfg.echo = false; - } - // side channels with echo - chans [2].cfg.echo = true; - chans [3].cfg.echo = true; - - clock_rate( clock_rate_ ); - bass_freq( bass_freq_ ); - apply_config(); - clear(); - - return blargg_ok; -} - -void Effects_Buffer::clear_echo() -{ - if ( echo.size() ) - memset( echo.begin(), 0, echo.size() * sizeof echo [0] ); -} - -void Effects_Buffer::clear() -{ - echo_pos = 0; - s.low_pass [0] = 0; - s.low_pass [1] = 0; - mixer.samples_read = 0; - - for ( int i = bufs_size; --i >= 0; ) - bufs [i].clear(); - clear_echo(); -} - -Effects_Buffer::channel_t Effects_Buffer::channel( int i ) -{ - i += extra_chans; - require( extra_chans <= i && i < (int) chans.size() ); - return chans [i].channel; -} - - -// Configuration - -// 3 wave positions with/without surround, 2 multi (one with same config as wave) -int const simple_bufs = 3 * 2 + 2 - 1; - -Simple_Effects_Buffer::Simple_Effects_Buffer() : - Effects_Buffer( extra_chans + simple_bufs, 18 * 1024 ) -{ - config_.echo = 0.20f; - config_.stereo = 0.20f; - config_.surround = true; - config_.enabled = false; -} - -void Simple_Effects_Buffer::apply_config() -{ - Effects_Buffer::config_t& c = Effects_Buffer::config(); - - c.enabled = config_.enabled; - if ( c.enabled ) - { - c.delay [0] = 120; - c.delay [1] = 122; - c.feedback = config_.echo * 0.7f; - c.treble = 0.6f - 0.3f * config_.echo; - - float sep = config_.stereo + 0.80f; - if ( sep > 1.0f ) - sep = 1.0f; - - c.side_chans [0].pan = -sep; - c.side_chans [1].pan = +sep; - - for ( int i = channel_count(); --i >= 0; ) - { - chan_config_t& ch = Effects_Buffer::chan_config( i ); - - ch.pan = 0.0f; - ch.surround = config_.surround; - ch.echo = false; - - int const type = (channel_types() ? channel_types() [i] : 0); - if ( !(type & noise_type) ) - { - int index = (type & type_index_mask) % 6 - 3; - if ( index < 0 ) - { - index += 3; - ch.surround = false; - ch.echo = true; - } - if ( index >= 1 ) - { - ch.pan = config_.stereo; - if ( index == 1 ) - ch.pan = -ch.pan; - } - } - else if ( type & 1 ) - { - ch.surround = false; - } - } - } - - Effects_Buffer::apply_config(); -} - -int Effects_Buffer::min_delay() const -{ - require( sample_rate() ); - return max_read * 1000 / sample_rate(); -} - -int Effects_Buffer::max_delay() const -{ - require( sample_rate() ); - return (echo_size / stereo - max_read) * 1000 / sample_rate(); -} - -void Effects_Buffer::apply_config() -{ - int i; - - if ( !bufs_size ) - return; - - s.treble = TO_FIXED( config_.treble ); - - bool echo_dirty = false; - - fixed_t old_feedback = s.feedback; - s.feedback = TO_FIXED( config_.feedback ); - if ( !old_feedback && s.feedback ) - echo_dirty = true; - - // delays - for ( i = stereo; --i >= 0; ) - { - int delay = config_.delay [i] * sample_rate() / 1000 * stereo; - delay = max( delay, (int) (max_read * stereo) ); - delay = min( delay, (int) (echo_size - max_read * stereo) ); - if ( s.delay [i] != delay ) - { - s.delay [i] = delay; - echo_dirty = true; - } - } - - // side channels - for ( i = 2; --i >= 0; ) - { - chans [i+2].cfg.vol = chans [i].cfg.vol = config_.side_chans [i].vol * 0.5f; - chans [i+2].cfg.pan = chans [i].cfg.pan = config_.side_chans [i].pan; - } - - // convert volumes - for ( i = chans.size(); --i >= 0; ) - { - chan_t& ch = chans [i]; - ch.vol [0] = TO_FIXED( ch.cfg.vol - ch.cfg.vol * ch.cfg.pan ); - ch.vol [1] = TO_FIXED( ch.cfg.vol + ch.cfg.vol * ch.cfg.pan ); - if ( ch.cfg.surround ) - ch.vol [0] = -ch.vol [0]; - } - - assign_buffers(); - - // set side channels - for ( i = chans.size(); --i >= 0; ) - { - chan_t& ch = chans [i]; - ch.channel.left = chans [ch.cfg.echo*2 ].channel.center; - ch.channel.right = chans [ch.cfg.echo*2+1].channel.center; - } - - bool old_echo = !no_echo && !no_effects; - - // determine whether effects and echo are needed at all - no_effects = true; - no_echo = true; - for ( i = chans.size(); --i >= extra_chans; ) - { - chan_t& ch = chans [i]; - if ( ch.cfg.echo && s.feedback ) - no_echo = false; - - if ( ch.vol [0] != TO_FIXED( 1 ) || ch.vol [1] != TO_FIXED( 1 ) ) - no_effects = false; - } - if ( !no_echo ) - no_effects = false; - - if ( chans [0].vol [0] != TO_FIXED( 1 ) || - chans [0].vol [1] != TO_FIXED( 0 ) || - chans [1].vol [0] != TO_FIXED( 0 ) || - chans [1].vol [1] != TO_FIXED( 1 ) ) - no_effects = false; - - if ( !config_.enabled ) - no_effects = true; - - if ( no_effects ) - { - for ( i = chans.size(); --i >= 0; ) - { - chan_t& ch = chans [i]; - ch.channel.center = &bufs [2]; - ch.channel.left = &bufs [0]; - ch.channel.right = &bufs [1]; - } - } - - mixer.bufs [0] = &bufs [0]; - mixer.bufs [1] = &bufs [1]; - mixer.bufs [2] = &bufs [2]; - - if ( echo_dirty || (!old_echo && (!no_echo && !no_effects)) ) - clear_echo(); - - channels_changed(); -} - -void Effects_Buffer::assign_buffers() -{ - // assign channels to buffers - int buf_count = 0; - for ( int i = 0; i < (int) chans.size(); i++ ) - { - // put second two side channels at end to give priority to main channels - // in case closest matching is necessary - int x = i; - if ( i > 1 ) - x += 2; - if ( x >= (int) chans.size() ) - x -= (chans.size() - 2); - chan_t& ch = chans [x]; - - int b = 0; - for ( ; b < buf_count; b++ ) - { - if ( ch.vol [0] == bufs [b].vol [0] && - ch.vol [1] == bufs [b].vol [1] && - (ch.cfg.echo == bufs [b].echo || !s.feedback) ) - break; - } - - if ( b >= buf_count ) - { - if ( buf_count < bufs_max ) - { - bufs [b].vol [0] = ch.vol [0]; - bufs [b].vol [1] = ch.vol [1]; - bufs [b].echo = ch.cfg.echo; - buf_count++; - } - else - { - // TODO: this is a mess, needs refinement - dprintf( "Effects_Buffer ran out of buffers; using closest match\n" ); - b = 0; - fixed_t best_dist = TO_FIXED( 8 ); - for ( int h = buf_count; --h >= 0; ) - { - #define CALC_LEVELS( vols, sum, diff, surround ) \ - fixed_t sum, diff;\ - bool surround = false;\ - {\ - fixed_t vol_0 = vols [0];\ - if ( vol_0 < 0 ) vol_0 = -vol_0, surround = true;\ - fixed_t vol_1 = vols [1];\ - if ( vol_1 < 0 ) vol_1 = -vol_1, surround = true;\ - sum = vol_0 + vol_1;\ - diff = vol_0 - vol_1;\ - } - CALC_LEVELS( ch.vol, ch_sum, ch_diff, ch_surround ); - CALC_LEVELS( bufs [h].vol, buf_sum, buf_diff, buf_surround ); - - fixed_t dist = abs( ch_sum - buf_sum ) + abs( ch_diff - buf_diff ); - - if ( ch_surround != buf_surround ) - dist += TO_FIXED( 1 ) / 2; - - if ( s.feedback && ch.cfg.echo != bufs [h].echo ) - dist += TO_FIXED( 1 ) / 2; - - if ( best_dist > dist ) - { - best_dist = dist; - b = h; - } - } - } - } - - //dprintf( "ch %d->buf %d\n", x, b ); - ch.channel.center = &bufs [b]; - } -} - - -// Mixing - -void Effects_Buffer::end_frame( blip_time_t time ) -{ - for ( int i = bufs_size; --i >= 0; ) - bufs [i].end_frame( time ); -} - -int Effects_Buffer::read_samples( blip_sample_t out [], int out_size ) -{ - out_size = min( out_size, samples_avail() ); - - int pair_count = int (out_size >> 1); - require( pair_count * stereo == out_size ); // must read an even number of samples - if ( pair_count ) - { - if ( no_effects ) - { - mixer.read_pairs( out, pair_count ); - } - else - { - int pairs_remain = pair_count; - do - { - // mix at most max_read pairs at a time - int count = max_read; - if ( count > pairs_remain ) - count = pairs_remain; - - if ( no_echo ) - { - // optimization: clear echo here to keep mix_effects() a leaf function - echo_pos = 0; - memset( echo.begin(), 0, count * stereo * sizeof echo [0] ); - } - mix_effects( out, count ); - - int new_echo_pos = echo_pos + count * stereo; - if ( new_echo_pos >= echo_size ) - new_echo_pos -= echo_size; - echo_pos = new_echo_pos; - assert( echo_pos < echo_size ); - - out += count * stereo; - mixer.samples_read += count; - pairs_remain -= count; - } - while ( pairs_remain ); - } - - if ( samples_avail() <= 0 || immediate_removal() ) - { - for ( int i = bufs_size; --i >= 0; ) - { - buf_t& b = bufs [i]; - // TODO: might miss non-silence settling since it checks END of last read - if ( b.non_silent() ) - b.remove_samples( mixer.samples_read ); - else - b.remove_silence( mixer.samples_read ); - } - mixer.samples_read = 0; - } - } - return out_size; -} - -void Effects_Buffer::mix_effects( blip_sample_t out_ [], int pair_count ) -{ - typedef fixed_t stereo_fixed_t [stereo]; - - // add channels with echo, do echo, add channels without echo, then convert to 16-bit and output - int echo_phase = 1; - do - { - // mix any modified buffers - { - buf_t* buf = bufs; - int bufs_remain = bufs_size; - do - { - if ( buf->non_silent() && buf->echo == echo_phase ) - { - stereo_fixed_t* BLARGG_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos]; - int const bass = BLIP_READER_BASS( *buf ); - BLIP_READER_BEGIN( in, *buf ); - BLIP_READER_ADJ_( in, mixer.samples_read ); - fixed_t const vol_0 = buf->vol [0]; - fixed_t const vol_1 = buf->vol [1]; - - int count = (unsigned) (echo_size - echo_pos) / stereo; - int remain = pair_count; - if ( count > remain ) - count = remain; - do - { - remain -= count; - BLIP_READER_ADJ_( in, count ); - - out += count; - int offset = -count; - do - { - fixed_t s = BLIP_READER_READ( in ); - BLIP_READER_NEXT_IDX_( in, bass, offset ); - - out [offset] [0] += s * vol_0; - out [offset] [1] += s * vol_1; - } - while ( ++offset ); - - out = (stereo_fixed_t*) echo.begin(); - count = remain; - } - while ( remain ); - - BLIP_READER_END( in, *buf ); - } - buf++; - } - while ( --bufs_remain ); - } - - // add echo - if ( echo_phase && !no_echo ) - { - fixed_t const feedback = s.feedback; - fixed_t const treble = s.treble; - - int i = 1; - do - { - fixed_t low_pass = s.low_pass [i]; - - fixed_t* echo_end = &echo [echo_size + i]; - fixed_t const* BLARGG_RESTRICT in_pos = &echo [echo_pos + i]; - int out_offset = echo_pos + i + s.delay [i]; - if ( out_offset >= echo_size ) - out_offset -= echo_size; - assert( out_offset < echo_size ); - fixed_t* BLARGG_RESTRICT out_pos = &echo [out_offset]; - - // break into up to three chunks to avoid having to handle wrap-around - // in middle of core loop - int remain = pair_count; - do - { - fixed_t const* pos = in_pos; - if ( pos < out_pos ) - pos = out_pos; - int count = (unsigned) ((char*) echo_end - (char const*) pos) / - (unsigned) (stereo * sizeof (fixed_t)); - if ( count > remain ) - count = remain; - remain -= count; - - in_pos += count * stereo; - out_pos += count * stereo; - int offset = -count; - do - { - low_pass += FROM_FIXED( in_pos [offset * stereo] - low_pass ) * treble; - out_pos [offset * stereo] = FROM_FIXED( low_pass ) * feedback; - } - while ( ++offset ); - - if ( in_pos >= echo_end ) in_pos -= echo_size; - if ( out_pos >= echo_end ) out_pos -= echo_size; - } - while ( remain ); - - s.low_pass [i] = low_pass; - } - while ( --i >= 0 ); - } - } - while ( --echo_phase >= 0 ); - - // clamp to 16 bits - { - stereo_fixed_t const* BLARGG_RESTRICT in = (stereo_fixed_t*) &echo [echo_pos]; - typedef blip_sample_t stereo_blip_sample_t [stereo]; - stereo_blip_sample_t* BLARGG_RESTRICT out = (stereo_blip_sample_t*) out_; - int count = (unsigned) (echo_size - echo_pos) / (unsigned) stereo; - int remain = pair_count; - if ( count > remain ) - count = remain; - do - { - remain -= count; - in += count; - out += count; - int offset = -count; - do - { - fixed_t in_0 = FROM_FIXED( in [offset] [0] ); - fixed_t in_1 = FROM_FIXED( in [offset] [1] ); - - BLIP_CLAMP( in_0, in_0 ); - out [offset] [0] = (blip_sample_t) in_0; - - BLIP_CLAMP( in_1, in_1 ); - out [offset] [1] = (blip_sample_t) in_1; - } - while ( ++offset ); - - in = (stereo_fixed_t*) echo.begin(); - count = remain; - } - while ( remain ); - } -} +Effects_Buffer::Effects_Buffer( int max_bufs, int echo_size_ ) : Multi_Buffer( stereo ) +{ + echo_size = max( max_read * (int) stereo, echo_size_ & ~1 ); + clock_rate_ = 0; + bass_freq_ = 90; + bufs = NULL; + bufs_size = 0; + bufs_max = max( max_bufs, (int) extra_chans ); + no_echo = true; + no_effects = true; + + // defaults + config_.enabled = false; + config_.delay [0] = 120; + config_.delay [1] = 122; + config_.feedback = 0.2f; + config_.treble = 0.4f; + + static float const sep = 0.8f; + config_.side_chans [0].pan = -sep; + config_.side_chans [1].pan = +sep; + config_.side_chans [0].vol = 1.0f; + config_.side_chans [1].vol = 1.0f; + + memset( &s, 0, sizeof s ); + clear(); +} + +Effects_Buffer::~Effects_Buffer() +{ + delete_bufs(); +} + +// avoid using new [] +blargg_err_t Effects_Buffer::new_bufs( int size ) +{ + bufs = (buf_t*) malloc( size * sizeof *bufs ); + CHECK_ALLOC( bufs ); + for ( int i = 0; i < size; i++ ) + new (bufs + i) buf_t; + bufs_size = size; + return blargg_ok; +} + +void Effects_Buffer::delete_bufs() +{ + if ( bufs ) + { + for ( int i = bufs_size; --i >= 0; ) + bufs [i].~buf_t(); + free( bufs ); + bufs = NULL; + } + bufs_size = 0; +} + +blargg_err_t Effects_Buffer::set_sample_rate( int rate, int msec ) +{ + // extra to allow farther past-the-end pointers + mixer.samples_read = 0; + RETURN_ERR( echo.resize( echo_size + stereo ) ); + return Multi_Buffer::set_sample_rate( rate, msec ); +} + +void Effects_Buffer::clock_rate( int rate ) +{ + clock_rate_ = rate; + for ( int i = bufs_size; --i >= 0; ) + bufs [i].clock_rate( clock_rate_ ); +} + +void Effects_Buffer::bass_freq( int freq ) +{ + bass_freq_ = freq; + for ( int i = bufs_size; --i >= 0; ) + bufs [i].bass_freq( bass_freq_ ); +} + +blargg_err_t Effects_Buffer::set_channel_count( int count, int const types [] ) +{ + RETURN_ERR( Multi_Buffer::set_channel_count( count, types ) ); + + delete_bufs(); + + mixer.samples_read = 0; + + RETURN_ERR( chans.resize( count + extra_chans ) ); + + RETURN_ERR( new_bufs( min( bufs_max, count + extra_chans ) ) ); + + for ( int i = bufs_size; --i >= 0; ) + RETURN_ERR( bufs [i].set_sample_rate( sample_rate(), length() ) ); + + for ( int i = chans.size(); --i >= 0; ) + { + chan_t& ch = chans [i]; + ch.cfg.vol = 1.0f; + ch.cfg.pan = 0.0f; + ch.cfg.surround = false; + ch.cfg.echo = false; + } + // side channels with echo + chans [2].cfg.echo = true; + chans [3].cfg.echo = true; + + clock_rate( clock_rate_ ); + bass_freq( bass_freq_ ); + apply_config(); + clear(); + + return blargg_ok; +} + +void Effects_Buffer::clear_echo() +{ + if ( echo.size() ) + memset( echo.begin(), 0, echo.size() * sizeof echo [0] ); +} + +void Effects_Buffer::clear() +{ + echo_pos = 0; + s.low_pass [0] = 0; + s.low_pass [1] = 0; + mixer.samples_read = 0; + + for ( int i = bufs_size; --i >= 0; ) + bufs [i].clear(); + clear_echo(); +} + +Effects_Buffer::channel_t Effects_Buffer::channel( int i ) +{ + i += extra_chans; + require( extra_chans <= i && i < (int) chans.size() ); + return chans [i].channel; +} + + +// Configuration + +// 3 wave positions with/without surround, 2 multi (one with same config as wave) +int const simple_bufs = 3 * 2 + 2 - 1; + +Simple_Effects_Buffer::Simple_Effects_Buffer() : + Effects_Buffer( extra_chans + simple_bufs, 18 * 1024 ) +{ + config_.echo = 0.20f; + config_.stereo = 0.20f; + config_.surround = true; + config_.enabled = false; +} + +void Simple_Effects_Buffer::apply_config() +{ + Effects_Buffer::config_t& c = Effects_Buffer::config(); + + c.enabled = config_.enabled; + if ( c.enabled ) + { + c.delay [0] = 120; + c.delay [1] = 122; + c.feedback = config_.echo * 0.7f; + c.treble = 0.6f - 0.3f * config_.echo; + + float sep = config_.stereo + 0.80f; + if ( sep > 1.0f ) + sep = 1.0f; + + c.side_chans [0].pan = -sep; + c.side_chans [1].pan = +sep; + + for ( int i = channel_count(); --i >= 0; ) + { + chan_config_t& ch = Effects_Buffer::chan_config( i ); + + ch.pan = 0.0f; + ch.surround = config_.surround; + ch.echo = false; + + int const type = (channel_types() ? channel_types() [i] : 0); + if ( !(type & noise_type) ) + { + int index = (type & type_index_mask) % 6 - 3; + if ( index < 0 ) + { + index += 3; + ch.surround = false; + ch.echo = true; + } + if ( index >= 1 ) + { + ch.pan = config_.stereo; + if ( index == 1 ) + ch.pan = -ch.pan; + } + } + else if ( type & 1 ) + { + ch.surround = false; + } + } + } + + Effects_Buffer::apply_config(); +} + +int Effects_Buffer::min_delay() const +{ + require( sample_rate() ); + return max_read * 1000 / sample_rate(); +} + +int Effects_Buffer::max_delay() const +{ + require( sample_rate() ); + return (echo_size / stereo - max_read) * 1000 / sample_rate(); +} + +void Effects_Buffer::apply_config() +{ + int i; + + if ( !bufs_size ) + return; + + s.treble = TO_FIXED( config_.treble ); + + bool echo_dirty = false; + + fixed_t old_feedback = s.feedback; + s.feedback = TO_FIXED( config_.feedback ); + if ( !old_feedback && s.feedback ) + echo_dirty = true; + + // delays + for ( i = stereo; --i >= 0; ) + { + int delay = config_.delay [i] * sample_rate() / 1000 * stereo; + delay = max( delay, (int) (max_read * stereo) ); + delay = min( delay, (int) (echo_size - max_read * stereo) ); + if ( s.delay [i] != delay ) + { + s.delay [i] = delay; + echo_dirty = true; + } + } + + // side channels + for ( i = 2; --i >= 0; ) + { + chans [i+2].cfg.vol = chans [i].cfg.vol = config_.side_chans [i].vol * 0.5f; + chans [i+2].cfg.pan = chans [i].cfg.pan = config_.side_chans [i].pan; + } + + // convert volumes + for ( i = chans.size(); --i >= 0; ) + { + chan_t& ch = chans [i]; + ch.vol [0] = TO_FIXED( ch.cfg.vol - ch.cfg.vol * ch.cfg.pan ); + ch.vol [1] = TO_FIXED( ch.cfg.vol + ch.cfg.vol * ch.cfg.pan ); + if ( ch.cfg.surround ) + ch.vol [0] = -ch.vol [0]; + } + + assign_buffers(); + + // set side channels + for ( i = chans.size(); --i >= 0; ) + { + chan_t& ch = chans [i]; + ch.channel.left = chans [ch.cfg.echo*2 ].channel.center; + ch.channel.right = chans [ch.cfg.echo*2+1].channel.center; + } + + bool old_echo = !no_echo && !no_effects; + + // determine whether effects and echo are needed at all + no_effects = true; + no_echo = true; + for ( i = chans.size(); --i >= extra_chans; ) + { + chan_t& ch = chans [i]; + if ( ch.cfg.echo && s.feedback ) + no_echo = false; + + if ( ch.vol [0] != TO_FIXED( 1 ) || ch.vol [1] != TO_FIXED( 1 ) ) + no_effects = false; + } + if ( !no_echo ) + no_effects = false; + + if ( chans [0].vol [0] != TO_FIXED( 1 ) || + chans [0].vol [1] != TO_FIXED( 0 ) || + chans [1].vol [0] != TO_FIXED( 0 ) || + chans [1].vol [1] != TO_FIXED( 1 ) ) + no_effects = false; + + if ( !config_.enabled ) + no_effects = true; + + if ( no_effects ) + { + for ( i = chans.size(); --i >= 0; ) + { + chan_t& ch = chans [i]; + ch.channel.center = &bufs [2]; + ch.channel.left = &bufs [0]; + ch.channel.right = &bufs [1]; + } + } + + mixer.bufs [0] = &bufs [0]; + mixer.bufs [1] = &bufs [1]; + mixer.bufs [2] = &bufs [2]; + + if ( echo_dirty || (!old_echo && (!no_echo && !no_effects)) ) + clear_echo(); + + channels_changed(); +} + +void Effects_Buffer::assign_buffers() +{ + // assign channels to buffers + int buf_count = 0; + for ( int i = 0; i < (int) chans.size(); i++ ) + { + // put second two side channels at end to give priority to main channels + // in case closest matching is necessary + int x = i; + if ( i > 1 ) + x += 2; + if ( x >= (int) chans.size() ) + x -= (chans.size() - 2); + chan_t& ch = chans [x]; + + int b = 0; + for ( ; b < buf_count; b++ ) + { + if ( ch.vol [0] == bufs [b].vol [0] && + ch.vol [1] == bufs [b].vol [1] && + (ch.cfg.echo == bufs [b].echo || !s.feedback) ) + break; + } + + if ( b >= buf_count ) + { + if ( buf_count < bufs_max ) + { + bufs [b].vol [0] = ch.vol [0]; + bufs [b].vol [1] = ch.vol [1]; + bufs [b].echo = ch.cfg.echo; + buf_count++; + } + else + { + // TODO: this is a mess, needs refinement + dprintf( "Effects_Buffer ran out of buffers; using closest match\n" ); + b = 0; + fixed_t best_dist = TO_FIXED( 8 ); + for ( int h = buf_count; --h >= 0; ) + { + #define CALC_LEVELS( vols, sum, diff, surround ) \ + fixed_t sum, diff;\ + bool surround = false;\ + {\ + fixed_t vol_0 = vols [0];\ + if ( vol_0 < 0 ) vol_0 = -vol_0, surround = true;\ + fixed_t vol_1 = vols [1];\ + if ( vol_1 < 0 ) vol_1 = -vol_1, surround = true;\ + sum = vol_0 + vol_1;\ + diff = vol_0 - vol_1;\ + } + CALC_LEVELS( ch.vol, ch_sum, ch_diff, ch_surround ); + CALC_LEVELS( bufs [h].vol, buf_sum, buf_diff, buf_surround ); + + fixed_t dist = abs( ch_sum - buf_sum ) + abs( ch_diff - buf_diff ); + + if ( ch_surround != buf_surround ) + dist += TO_FIXED( 1 ) / 2; + + if ( s.feedback && ch.cfg.echo != bufs [h].echo ) + dist += TO_FIXED( 1 ) / 2; + + if ( best_dist > dist ) + { + best_dist = dist; + b = h; + } + } + } + } + + //dprintf( "ch %d->buf %d\n", x, b ); + ch.channel.center = &bufs [b]; + } +} + + +// Mixing + +void Effects_Buffer::end_frame( blip_time_t time ) +{ + for ( int i = bufs_size; --i >= 0; ) + bufs [i].end_frame( time ); +} + +int Effects_Buffer::read_samples( blip_sample_t out [], int out_size ) +{ + out_size = min( out_size, samples_avail() ); + + int pair_count = int (out_size >> 1); + require( pair_count * stereo == out_size ); // must read an even number of samples + if ( pair_count ) + { + if ( no_effects ) + { + mixer.read_pairs( out, pair_count ); + } + else + { + int pairs_remain = pair_count; + do + { + // mix at most max_read pairs at a time + int count = max_read; + if ( count > pairs_remain ) + count = pairs_remain; + + if ( no_echo ) + { + // optimization: clear echo here to keep mix_effects() a leaf function + echo_pos = 0; + memset( echo.begin(), 0, count * stereo * sizeof echo [0] ); + } + mix_effects( out, count ); + + int new_echo_pos = echo_pos + count * stereo; + if ( new_echo_pos >= echo_size ) + new_echo_pos -= echo_size; + echo_pos = new_echo_pos; + assert( echo_pos < echo_size ); + + out += count * stereo; + mixer.samples_read += count; + pairs_remain -= count; + } + while ( pairs_remain ); + } + + if ( samples_avail() <= 0 || immediate_removal() ) + { + for ( int i = bufs_size; --i >= 0; ) + { + buf_t& b = bufs [i]; + // TODO: might miss non-silence settling since it checks END of last read + if ( b.non_silent() ) + b.remove_samples( mixer.samples_read ); + else + b.remove_silence( mixer.samples_read ); + } + mixer.samples_read = 0; + } + } + return out_size; +} + +void Effects_Buffer::mix_effects( blip_sample_t out_ [], int pair_count ) +{ + typedef fixed_t stereo_fixed_t [stereo]; + + // add channels with echo, do echo, add channels without echo, then convert to 16-bit and output + int echo_phase = 1; + do + { + // mix any modified buffers + { + buf_t* buf = bufs; + int bufs_remain = bufs_size; + do + { + if ( buf->non_silent() && buf->echo == echo_phase ) + { + stereo_fixed_t* BLARGG_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos]; + int const bass = BLIP_READER_BASS( *buf ); + BLIP_READER_BEGIN( in, *buf ); + BLIP_READER_ADJ_( in, mixer.samples_read ); + fixed_t const vol_0 = buf->vol [0]; + fixed_t const vol_1 = buf->vol [1]; + + int count = (unsigned) (echo_size - echo_pos) / stereo; + int remain = pair_count; + if ( count > remain ) + count = remain; + do + { + remain -= count; + BLIP_READER_ADJ_( in, count ); + + out += count; + int offset = -count; + do + { + fixed_t s = BLIP_READER_READ( in ); + BLIP_READER_NEXT_IDX_( in, bass, offset ); + + out [offset] [0] += s * vol_0; + out [offset] [1] += s * vol_1; + } + while ( ++offset ); + + out = (stereo_fixed_t*) echo.begin(); + count = remain; + } + while ( remain ); + + BLIP_READER_END( in, *buf ); + } + buf++; + } + while ( --bufs_remain ); + } + + // add echo + if ( echo_phase && !no_echo ) + { + fixed_t const feedback = s.feedback; + fixed_t const treble = s.treble; + + int i = 1; + do + { + fixed_t low_pass = s.low_pass [i]; + + fixed_t* echo_end = &echo [echo_size + i]; + fixed_t const* BLARGG_RESTRICT in_pos = &echo [echo_pos + i]; + int out_offset = echo_pos + i + s.delay [i]; + if ( out_offset >= echo_size ) + out_offset -= echo_size; + assert( out_offset < echo_size ); + fixed_t* BLARGG_RESTRICT out_pos = &echo [out_offset]; + + // break into up to three chunks to avoid having to handle wrap-around + // in middle of core loop + int remain = pair_count; + do + { + fixed_t const* pos = in_pos; + if ( pos < out_pos ) + pos = out_pos; + int count = (unsigned) ((char*) echo_end - (char const*) pos) / + (unsigned) (stereo * sizeof (fixed_t)); + if ( count > remain ) + count = remain; + remain -= count; + + in_pos += count * stereo; + out_pos += count * stereo; + int offset = -count; + do + { + low_pass += FROM_FIXED( in_pos [offset * stereo] - low_pass ) * treble; + out_pos [offset * stereo] = FROM_FIXED( low_pass ) * feedback; + } + while ( ++offset ); + + if ( in_pos >= echo_end ) in_pos -= echo_size; + if ( out_pos >= echo_end ) out_pos -= echo_size; + } + while ( remain ); + + s.low_pass [i] = low_pass; + } + while ( --i >= 0 ); + } + } + while ( --echo_phase >= 0 ); + + // clamp to 16 bits + { + stereo_fixed_t const* BLARGG_RESTRICT in = (stereo_fixed_t*) &echo [echo_pos]; + typedef blip_sample_t stereo_blip_sample_t [stereo]; + stereo_blip_sample_t* BLARGG_RESTRICT out = (stereo_blip_sample_t*) out_; + int count = (unsigned) (echo_size - echo_pos) / (unsigned) stereo; + int remain = pair_count; + if ( count > remain ) + count = remain; + do + { + remain -= count; + in += count; + out += count; + int offset = -count; + do + { + fixed_t in_0 = FROM_FIXED( in [offset] [0] ); + fixed_t in_1 = FROM_FIXED( in [offset] [1] ); + + BLIP_CLAMP( in_0, in_0 ); + out [offset] [0] = (blip_sample_t) in_0; + + BLIP_CLAMP( in_1, in_1 ); + out [offset] [1] = (blip_sample_t) in_1; + } + while ( ++offset ); + + in = (stereo_fixed_t*) echo.begin(); + count = remain; + } + while ( remain ); + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/emuconfig.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/emuconfig.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/emuconfig.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/emuconfig.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,78 +1,78 @@ -///////////////////////////////////////////////////////////////////////////// -// -// Configuration for emulation libraries -// -///////////////////////////////////////////////////////////////////////////// - -#ifndef __EMUCONFIG_H__ -#define __EMUCONFIG_H__ - -///////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////// -// -// WIN32 native project definitions -// -///////////////////////////////////////////////////////////////////////////// -#if defined(WIN32) && !defined(__GNUC__) - -#define EMU_CALL __fastcall -#define EMU_CALL_ __cdecl -#define EMU_INLINE __inline - -#define uint8 unsigned char -#define uint16 unsigned short -#define uint32 unsigned int -#define uint64 unsigned __int64 -#define sint8 signed char -#define sint16 signed short -#define sint32 signed int -#define sint64 signed __int64 - -///////////////////////////////////////////////////////////////////////////// -// -// LINUX / other platform definitions -// -///////////////////////////////////////////////////////////////////////////// -#else - -//#if defined(__GNUC__) && defined(__i386__) -//#define EMU_CALL __attribute__((__regparm__(2))) -//#else -#define EMU_CALL -//#endif - -#define EMU_CALL_ -#define EMU_INLINE __inline - -#ifdef HAVE_STDINT_H -#include -#define uint8 uint8_t -#define uint16 uint16_t -#define uint32 uint32_t -#define uint64 uint64_t -#define sint8 int8_t -#define sint16 int16_t -#define sint32 int32_t -#define sint64 int64_t -#else -#define uint8 unsigned char -#define uint16 unsigned short -#define uint32 unsigned int -#define uint64 unsigned long long -#define sint8 signed char -#define sint16 signed short -#define sint32 signed int -#define sint64 signed long long -#endif - -#endif - -///////////////////////////////////////////////////////////////////////////// - -#endif +///////////////////////////////////////////////////////////////////////////// +// +// Configuration for emulation libraries +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef __EMUCONFIG_H__ +#define __EMUCONFIG_H__ + +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////// +// +// WIN32 native project definitions +// +///////////////////////////////////////////////////////////////////////////// +#if defined(WIN32) && !defined(__GNUC__) + +#define EMU_CALL __fastcall +#define EMU_CALL_ __cdecl +#define EMU_INLINE __inline + +#define uint8 unsigned char +#define uint16 unsigned short +#define uint32 unsigned int +#define uint64 unsigned __int64 +#define sint8 signed char +#define sint16 signed short +#define sint32 signed int +#define sint64 signed __int64 + +///////////////////////////////////////////////////////////////////////////// +// +// LINUX / other platform definitions +// +///////////////////////////////////////////////////////////////////////////// +#else + +//#if defined(__GNUC__) && defined(__i386__) +//#define EMU_CALL __attribute__((__regparm__(2))) +//#else +#define EMU_CALL +//#endif + +#define EMU_CALL_ +#define EMU_INLINE __inline + +#ifdef HAVE_STDINT_H +#include +#define uint8 uint8_t +#define uint16 uint16_t +#define uint32 uint32_t +#define uint64 uint64_t +#define sint8 int8_t +#define sint16 int16_t +#define sint32 int32_t +#define sint64 int64_t +#else +#define uint8 unsigned char +#define uint16 unsigned short +#define uint32 unsigned int +#define uint64 unsigned long long +#define sint8 signed char +#define sint16 signed short +#define sint32 signed int +#define sint64 signed long long +#endif + +#endif + +///////////////////////////////////////////////////////////////////////////// + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/fmopl.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/fmopl.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/fmopl.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/fmopl.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,2621 +1,2621 @@ -/* -** -** File: fmopl.c - software implementation of FM sound generator -** types OPL and OPL2 -** -** Copyright Jarek Burczynski (bujar at mame dot net) -** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development -** -** Version 0.72 -** - -Revision History: - -04-08-2003 Jarek Burczynski: - - removed BFRDY hack. BFRDY is busy flag, and it should be 0 only when the chip - handles memory read/write or during the adpcm synthesis when the chip - requests another byte of ADPCM data. - -24-07-2003 Jarek Burczynski: - - added a small hack for Y8950 status BFRDY flag (bit 3 should be set after - some (unknown) delay). Right now it's always set. - -14-06-2003 Jarek Burczynski: - - implemented all of the status register flags in Y8950 emulation - - renamed y8950_set_delta_t_memory() parameters from _rom_ to _mem_ since - they can be either RAM or ROM - -08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip) - - corrected ym3526_read() to always set bit 2 and bit 1 - to HIGH state - identical to ym3812_read (verified on real YM3526) - -04-28-2002 Jarek Burczynski: - - binary exact Envelope Generator (verified on real YM3812); - compared to YM2151: the EG clock is equal to internal_clock, - rates are 2 times slower and volume resolution is one bit less - - modified interface functions (they no longer return pointer - - that's internal to the emulator now): - - new wrapper functions for OPLCreate: ym3526_init(), ym3812_init() and y8950_init() - - corrected 'off by one' error in feedback calculations (when feedback is off) - - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) - - speeded up noise generator calculations (Nicola Salmoria) - -03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) - Complete rewrite (all verified on real YM3812): - - corrected sin_tab and tl_tab data - - corrected operator output calculations - - corrected waveform_select_enable register; - simply: ignore all writes to waveform_select register when - waveform_select_enable == 0 and do not change the waveform previously selected. - - corrected KSR handling - - corrected Envelope Generator: attack shape, Sustain mode and - Percussive/Non-percussive modes handling - - Envelope Generator rates are two times slower now - - LFO amplitude (tremolo) and phase modulation (vibrato) - - rhythm sounds phase generation - - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm) - - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM) - - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1) - -12-28-2001 Acho A. Tang - - reflected Delta-T EOS status on Y8950 status port. - - fixed subscription range of attack/decay tables - - - To do: - add delay before key off in CSM mode (see CSMKeyControll) - verify volume of the FM part on the Y8950 -*/ - -#include -#include -#define _USE_MATH_DEFINES -#include -#include "fmopl.h" -#include "ymdeltat.h" - -#ifndef INLINE -#define INLINE __inline -#endif -#ifndef NULL - #define NULL ((void *)0) -#endif -#ifndef logerror -#define logerror (void) -#endif - -#ifndef M_PI - #define M_PI 3.14159265358979323846 -#endif - -/* output final shift */ -#if (OPL_SAMPLE_BITS==16) - #define FINAL_SH (0) - #define MAXOUT (+32767) - #define MINOUT (-32768) -#else - #define FINAL_SH (8) - #define MAXOUT (+127) - #define MINOUT (-128) -#endif - - -#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define EG_SH 16 /* 16.16 fixed point (EG timing) */ -#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ -#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ - -#define FREQ_MASK ((1<=0) - { - if (value < 0x0200) - return (value & ~0); - if (value < 0x0400) - return (value & ~1); - if (value < 0x0800) - return (value & ~3); - if (value < 0x1000) - return (value & ~7); - if (value < 0x2000) - return (value & ~15); - if (value < 0x4000) - return (value & ~31); - return (value & ~63); - } - /*else value < 0*/ - if (value > -0x0200) - return (~abs(value) & ~0); - if (value > -0x0400) - return (~abs(value) & ~1); - if (value > -0x0800) - return (~abs(value) & ~3); - if (value > -0x1000) - return (~abs(value) & ~7); - if (value > -0x2000) - return (~abs(value) & ~15); - if (value > -0x4000) - return (~abs(value) & ~31); - return (~abs(value) & ~63); -} - - -static FILE *sample[1]; - #if 1 /*save to MONO file */ - #define SAVE_ALL_CHANNELS \ - { signed int pom = acc_calc(lt); \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - } - #else /*save to STEREO file */ - #define SAVE_ALL_CHANNELS \ - { signed int pom = lt; \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - pom = rt; \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - } - #endif -#endif - -#define LOG_CYM_FILE 0 -//static FILE * cymfile = NULL; - - - -#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ -#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ -#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ -#define OPL_TYPE_IO 0x08 /* I/O port */ - -/* ---------- Generic interface section ---------- */ -#define OPL_TYPE_YM3526 (0) -#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) -#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) - - - -typedef struct{ - UINT32 ar; /* attack rate: AR<<2 */ - UINT32 dr; /* decay rate: DR<<2 */ - UINT32 rr; /* release rate:RR<<2 */ - UINT8 KSR; /* key scale rate */ - UINT8 ksl; /* keyscale level */ - UINT8 ksr; /* key scale rate: kcode>>KSR */ - UINT8 mul; /* multiple: mul_tab[ML] */ - - /* Phase Generator */ - UINT32 Cnt; /* frequency counter */ - UINT32 Incr; /* frequency counter step */ - UINT8 FB; /* feedback shift value */ - INT32 *connect1; /* slot1 output pointer */ - INT32 op1_out[2]; /* slot1 output for feedback */ - UINT8 CON; /* connection (algorithm) type */ - - /* Envelope Generator */ - UINT8 eg_type; /* percussive/non-percussive mode */ - UINT8 state; /* phase type */ - UINT32 TL; /* total level: TL << 2 */ - INT32 TLL; /* adjusted now TL */ - INT32 volume; /* envelope counter */ - UINT32 sl; /* sustain level: sl_tab[SL] */ - UINT8 eg_sh_ar; /* (attack state) */ - UINT8 eg_sel_ar; /* (attack state) */ - UINT8 eg_sh_dr; /* (decay state) */ - UINT8 eg_sel_dr; /* (decay state) */ - UINT8 eg_sh_rr; /* (release state) */ - UINT8 eg_sel_rr; /* (release state) */ - UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ - - /* LFO */ - UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ - UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ - - /* waveform select */ - UINT16 wavetable; -} OPL_SLOT; - -typedef struct{ - OPL_SLOT SLOT[2]; - /* phase generator state */ - UINT32 block_fnum; /* block+fnum */ - UINT32 fc; /* Freq. Increment base */ - UINT32 ksl_base; /* KeyScaleLevel Base step */ - UINT8 kcode; /* key code (for key scaling) */ -} OPL_CH; - -/* OPL state */ -typedef struct fm_opl_f { - /* FM channel slots */ - OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ - - UINT32 eg_cnt; /* global envelope generator counter */ - UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ - UINT32 eg_timer_add; /* step of eg_timer */ - UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ - - UINT8 rhythm; /* Rhythm mode */ - - UINT32 fn_tab[1024]; /* fnumber->increment counter */ - - /* LFO */ - UINT8 lfo_am_depth; - UINT8 lfo_pm_depth_range; - UINT32 lfo_am_cnt; - UINT32 lfo_am_inc; - UINT32 lfo_pm_cnt; - UINT32 lfo_pm_inc; - - UINT32 noise_rng; /* 23 bit noise shift register */ - UINT32 noise_p; /* current noise 'phase' */ - UINT32 noise_f; /* current noise period */ - - UINT8 wavesel; /* waveform select enable flag */ - - UINT32 T[2]; /* timer counters */ - UINT8 st[2]; /* timer enable */ - -#if BUILD_Y8950 - /* Delta-T ADPCM unit (Y8950) */ - - YM_DELTAT *deltat; - - /* Keyboard and I/O ports interface */ - UINT8 portDirection; - UINT8 portLatch; - OPL_PORTHANDLER_R porthandler_r; - OPL_PORTHANDLER_W porthandler_w; - void * port_param; - OPL_PORTHANDLER_R keyboardhandler_r; - OPL_PORTHANDLER_W keyboardhandler_w; - void * keyboard_param; -#endif - - /* external event callback handlers */ - //OPL_TIMERHANDLER timer_handler; /* TIMER handler */ - void *TimerParam; /* TIMER parameter */ - OPL_IRQHANDLER IRQHandler; /* IRQ handler */ - void *IRQParam; /* IRQ parameter */ - OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ - void *UpdateParam; /* stream update parameter */ - - UINT8 type; /* chip type */ - UINT8 address; /* address register */ - UINT8 status; /* status flag */ - UINT8 statusmask; /* status mask */ - UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ - - UINT32 clock; /* master clock (Hz) */ - UINT32 rate; /* sampling rate (Hz) */ - double freqbase; /* frequency base */ - //attotime TimerBase; /* Timer base time (==sampling time)*/ - - OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2; - - signed int phase_modulation; /* phase modulation input (SLOT 2) */ - signed int output[1]; - -#if BUILD_Y8950 - INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */ -#endif - - UINT32 LFO_AM; - INT32 LFO_PM; -} FM_OPL; - - - -/* mapping of register number (offset) to slot number used by the emulator */ -static const int slot_array[32]= -{ - 0, 2, 4, 1, 3, 5,-1,-1, - 6, 8,10, 7, 9,11,-1,-1, - 12,14,16,13,15,17,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1 -}; - -/* key scale level */ -/* table is 3dB/octave , DV converts this into 6dB/octave */ -/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ -#define DV (0.1875/2.0) -static const UINT32 ksl_tab[8*16]= -{ - /* OCT 0 */ - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), - /* OCT 1 */ - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), - UINT32( 0.000/DV), UINT32( 0.750/DV), UINT32( 1.125/DV), UINT32( 1.500/DV), - UINT32( 1.875/DV), UINT32( 2.250/DV), UINT32( 2.625/DV), UINT32( 3.000/DV), - /* OCT 2 */ - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), - UINT32( 0.000/DV), UINT32( 1.125/DV), UINT32( 1.875/DV), UINT32( 2.625/DV), - UINT32( 3.000/DV), UINT32( 3.750/DV), UINT32( 4.125/DV), UINT32( 4.500/DV), - UINT32( 4.875/DV), UINT32( 5.250/DV), UINT32( 5.625/DV), UINT32( 6.000/DV), - /* OCT 3 */ - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 1.875/DV), - UINT32( 3.000/DV), UINT32( 4.125/DV), UINT32( 4.875/DV), UINT32( 5.625/DV), - UINT32( 6.000/DV), UINT32( 6.750/DV), UINT32( 7.125/DV), UINT32( 7.500/DV), - UINT32( 7.875/DV), UINT32( 8.250/DV), UINT32( 8.625/DV), UINT32( 9.000/DV), - /* OCT 4 */ - UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 3.000/DV), UINT32( 4.875/DV), - UINT32( 6.000/DV), UINT32( 7.125/DV), UINT32( 7.875/DV), UINT32( 8.625/DV), - UINT32( 9.000/DV), UINT32( 9.750/DV), UINT32(10.125/DV), UINT32(10.500/DV), - UINT32(10.875/DV), UINT32(11.250/DV), UINT32(11.625/DV), UINT32(12.000/DV), - /* OCT 5 */ - UINT32( 0.000/DV), UINT32( 3.000/DV), UINT32( 6.000/DV), UINT32( 7.875/DV), - UINT32( 9.000/DV), UINT32(10.125/DV), UINT32(10.875/DV), UINT32(11.625/DV), - UINT32(12.000/DV), UINT32(12.750/DV), UINT32(13.125/DV), UINT32(13.500/DV), - UINT32(13.875/DV), UINT32(14.250/DV), UINT32(14.625/DV), UINT32(15.000/DV), - /* OCT 6 */ - UINT32( 0.000/DV), UINT32( 6.000/DV), UINT32( 9.000/DV), UINT32(10.875/DV), - UINT32(12.000/DV), UINT32(13.125/DV), UINT32(13.875/DV), UINT32(14.625/DV), - UINT32(15.000/DV), UINT32(15.750/DV), UINT32(16.125/DV), UINT32(16.500/DV), - UINT32(16.875/DV), UINT32(17.250/DV), UINT32(17.625/DV), UINT32(18.000/DV), - /* OCT 7 */ - UINT32( 0.000/DV), UINT32( 9.000/DV), UINT32(12.000/DV), UINT32(13.875/DV), - UINT32(15.000/DV), UINT32(16.125/DV), UINT32(16.875/DV), UINT32(17.625/DV), - UINT32(18.000/DV), UINT32(18.750/DV), UINT32(19.125/DV), UINT32(19.500/DV), - UINT32(19.875/DV), UINT32(20.250/DV), UINT32(20.625/DV), UINT32(21.000/DV) -}; -#undef DV - -/* sustain level table (3dB per step) */ -/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) -static const UINT32 sl_tab[16]={ - SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), - SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) -}; -#undef SC - - -#define RATE_STEPS (8) -static const unsigned char eg_inc[15*RATE_STEPS]={ - -/*cycle:0 1 2 3 4 5 6 7*/ - -/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ -/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ -/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ -/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ - -/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ -/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ -/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ -/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ - -/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ -/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ -/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ -/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ - -/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ -/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ -/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ -}; - - -#define O(a) (a*RATE_STEPS) - -/*note that there is no O(13) in this table - it's directly in the code */ -static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ -/* 16 infinite time rates */ -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), - -/* rates 00-12 */ -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), - -/* rate 13 */ -O( 4),O( 5),O( 6),O( 7), - -/* rate 14 */ -O( 8),O( 9),O(10),O(11), - -/* rate 15 */ -O(12),O(12),O(12),O(12), - -/* 16 dummy rates (same as 15 3) */ -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), - -}; -#undef O - -/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ -/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ -/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ - -#define O(a) (a*1) -static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ -/* 16 infinite time rates */ -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), - -/* rates 00-12 */ -O(12),O(12),O(12),O(12), -O(11),O(11),O(11),O(11), -O(10),O(10),O(10),O(10), -O( 9),O( 9),O( 9),O( 9), -O( 8),O( 8),O( 8),O( 8), -O( 7),O( 7),O( 7),O( 7), -O( 6),O( 6),O( 6),O( 6), -O( 5),O( 5),O( 5),O( 5), -O( 4),O( 4),O( 4),O( 4), -O( 3),O( 3),O( 3),O( 3), -O( 2),O( 2),O( 2),O( 2), -O( 1),O( 1),O( 1),O( 1), -O( 0),O( 0),O( 0),O( 0), - -/* rate 13 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 14 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 15 */ -O( 0),O( 0),O( 0),O( 0), - -/* 16 dummy rates (same as 15 3) */ -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), - -}; -#undef O - - -/* multiple table */ -#define ML 2 -static const UINT8 mul_tab[16]= { -/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ - UINT8( 0.50*ML),UINT8( 1.00*ML),UINT8( 2.00*ML),UINT8( 3.00*ML),UINT8( 4.00*ML),UINT8( 5.00*ML),UINT8( 6.00*ML),UINT8( 7.00*ML), - UINT8( 8.00*ML),UINT8( 9.00*ML),UINT8(10.00*ML),UINT8(10.00*ML),UINT8(12.00*ML),UINT8(12.00*ML),UINT8(15.00*ML),UINT8(15.00*ML) -}; -#undef ML - -/* TL_TAB_LEN is calculated as: -* 12 - sinus amplitude bits (Y axis) -* 2 - sinus sign bit (Y axis) -* TL_RES_LEN - sinus resolution (X axis) -*/ -#define TL_TAB_LEN (12*2*TL_RES_LEN) -static signed int tl_tab[TL_TAB_LEN]; - -#define ENV_QUIET (TL_TAB_LEN>>4) - -/* sin waveform table in 'decibel' scale */ -/* four waveforms on OPL2 type chips */ -static unsigned int sin_tab[SIN_LEN * 4]; - - -/* LFO Amplitude Modulation table (verified on real YM3812) - 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples - - Length: 210 elements. - - Each of the elements has to be repeated - exactly 64 times (on 64 consecutive samples). - The whole table takes: 64 * 210 = 13440 samples. - - When AM = 1 data is used directly - When AM = 0 data is divided by 4 before being used (loosing precision is important) -*/ - -#define LFO_AM_TAB_ELEMENTS 210 - -static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { -0,0,0,0,0,0,0, -1,1,1,1, -2,2,2,2, -3,3,3,3, -4,4,4,4, -5,5,5,5, -6,6,6,6, -7,7,7,7, -8,8,8,8, -9,9,9,9, -10,10,10,10, -11,11,11,11, -12,12,12,12, -13,13,13,13, -14,14,14,14, -15,15,15,15, -16,16,16,16, -17,17,17,17, -18,18,18,18, -19,19,19,19, -20,20,20,20, -21,21,21,21, -22,22,22,22, -23,23,23,23, -24,24,24,24, -25,25,25,25, -26,26,26, -25,25,25,25, -24,24,24,24, -23,23,23,23, -22,22,22,22, -21,21,21,21, -20,20,20,20, -19,19,19,19, -18,18,18,18, -17,17,17,17, -16,16,16,16, -15,15,15,15, -14,14,14,14, -13,13,13,13, -12,12,12,12, -11,11,11,11, -10,10,10,10, -9,9,9,9, -8,8,8,8, -7,7,7,7, -6,6,6,6, -5,5,5,5, -4,4,4,4, -3,3,3,3, -2,2,2,2, -1,1,1,1 -}; - -/* LFO Phase Modulation table (verified on real YM3812) */ -static const INT8 lfo_pm_table[8*8*2] = { - -/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ -4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ -5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ -6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ -7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ -}; - - -/* lock level of common table */ -//static int num_lock = 0; - - -//static void *cur_chip = NULL; /* current chip pointer */ - -INLINE int limit( int val, int max, int min ) { - if ( val > max ) - val = max; - else if ( val < min ) - val = min; - - return val; -} - - -/* status set and IRQ handling */ -INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) -{ - /* set status flag */ - OPL->status |= flag; - if(!(OPL->status & 0x80)) - { - if(OPL->status & OPL->statusmask) - { /* IRQ on */ - OPL->status |= 0x80; - /* callback user interrupt handler (IRQ is OFF to ON) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); - } - } -} - -/* status reset and IRQ handling */ -INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) -{ - /* reset status flag */ - OPL->status &=~flag; - if((OPL->status & 0x80)) - { - if (!(OPL->status & OPL->statusmask) ) - { - OPL->status &= 0x7f; - /* callback user interrupt handler (IRQ is ON to OFF) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); - } - } -} - -/* IRQ mask set */ -INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) -{ - OPL->statusmask = flag; - /* IRQ handling check */ - OPL_STATUS_SET(OPL,0); - OPL_STATUS_RESET(OPL,0); -} - - -/* advance LFO to next sample */ -INLINE void advance_lfo(FM_OPL *OPL) -{ - UINT8 tmp; - - /* LFO */ - OPL->lfo_am_cnt += OPL->lfo_am_inc; - if (OPL->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; - - if (OPL->lfo_am_depth) - OPL->LFO_AM = tmp; - else - OPL->LFO_AM = tmp>>2; - - OPL->lfo_pm_cnt += OPL->lfo_pm_inc; - OPL->LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; -} - -/* advance to next sample */ -INLINE void advance(FM_OPL *OPL) -{ - OPL_CH *CH; - OPL_SLOT *op; - int i; - - OPL->eg_timer += OPL->eg_timer_add; - - while (OPL->eg_timer >= OPL->eg_timer_overflow) - { - OPL->eg_timer -= OPL->eg_timer_overflow; - - OPL->eg_cnt++; - - for (i=0; i<9*2; i++) - { - CH = &OPL->P_CH[i/2]; - op = &CH->SLOT[i&1]; - - /* Envelope Generator */ - switch(op->state) - { - case EG_ATT: /* attack phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_ar)-1) ) ) - { - op->volume += (~op->volume * - (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) - ) >>3; - - if (op->volume <= MIN_ATT_INDEX) - { - op->volume = MIN_ATT_INDEX; - op->state = EG_DEC; - } - - } - break; - - case EG_DEC: /* decay phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; - - if ( op->volume >= op->sl ) - op->state = EG_SUS; - - } - break; - - case EG_SUS: /* sustain phase */ - - /* this is important behaviour: - one can change percusive/non-percussive modes on the fly and - the chip will remain in sustain phase - verified on real YM3812 */ - - if(op->eg_type) /* non-percussive mode */ - { - /* do nothing */ - } - else /* percussive mode */ - { - /* during sustain phase chip adds Release Rate (in percussive mode) */ - if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - op->volume = MAX_ATT_INDEX; - } - /* else do nothing in sustain phase */ - } - break; - - case EG_REL: /* release phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_OFF; - } - - } - break; - - default: - break; - } - } - } - - for (i=0; i<9*2; i++) - { - CH = &OPL->P_CH[i/2]; - op = &CH->SLOT[i&1]; - - /* Phase Generator */ - if(op->vib) - { - UINT8 block; - unsigned int block_fnum = CH->block_fnum; - - unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; - - signed int lfo_fn_table_index_offset = lfo_pm_table[OPL->LFO_PM + 16*fnum_lfo ]; - - if (lfo_fn_table_index_offset) /* LFO phase modulation active */ - { - block_fnum += lfo_fn_table_index_offset; - block = (block_fnum&0x1c00) >> 10; - op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; - } - else /* LFO phase modulation = zero */ - { - op->Cnt += op->Incr; - } - } - else /* LFO phase modulation disabled for this operator */ - { - op->Cnt += op->Incr; - } - } - - /* The Noise Generator of the YM3812 is 23-bit shift register. - * Period is equal to 2^23-2 samples. - * Register works at sampling frequency of the chip, so output - * can change on every sample. - * - * Output of the register and input to the bit 22 is: - * bit0 XOR bit14 XOR bit15 XOR bit22 - * - * Simply use bit 22 as the noise output. - */ - - OPL->noise_p += OPL->noise_f; - i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ - OPL->noise_p &= FREQ_MASK; - while (i) - { - /* - UINT32 j; - j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; - OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); - */ - - /* - Instead of doing all the logic operations above, we - use a trick here (and use bit 0 as the noise output). - The difference is only that the noise bit changes one - step ahead. This doesn't matter since we don't know - what is real state of the noise_rng after the reset. - */ - - if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; - OPL->noise_rng >>= 1; - - i--; - } -} - - -INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - UINT32 p; - - p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - -INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - UINT32 p; - - p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - - -#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (OPL->LFO_AM & (OP)->AMmask)) - -/* calculate output */ -INLINE void OPL_CALC_CH( FM_OPL *OPL, OPL_CH *CH ) -{ - OPL_SLOT *SLOT; - unsigned int env; - signed int out; - - OPL->phase_modulation = 0; - - /* SLOT 1 */ - SLOT = &CH->SLOT[SLOT1]; - env = volume_calc(SLOT); - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - SLOT->op1_out[0] = SLOT->op1_out[1]; - *SLOT->connect1 += SLOT->op1_out[0]; - SLOT->op1_out[1] = 0; - if( env < ENV_QUIET ) - { - if (!SLOT->FB) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); - } - - /* SLOT 2 */ - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable); -} - -/* - operators used in the rhythm sounds generation process: - - Envelope Generator: - -channel operator register number Bass High Snare Tom Top -/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal - 6 / 0 12 50 70 90 f0 + - 6 / 1 15 53 73 93 f3 + - 7 / 0 13 51 71 91 f1 + - 7 / 1 16 54 74 94 f4 + - 8 / 0 14 52 72 92 f2 + - 8 / 1 17 55 75 95 f5 + - - Phase Generator: - -channel operator register number Bass High Snare Tom Top -/ slot number MULTIPLE Drum Hat Drum Tom Cymbal - 6 / 0 12 30 + - 6 / 1 15 33 + - 7 / 0 13 31 + + + - 7 / 1 16 34 ----- n o t u s e d ----- - 8 / 0 14 32 + - 8 / 1 17 35 + + - -channel operator register number Bass High Snare Tom Top -number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal - 6 12,15 B6 A6 + - - 7 13,16 B7 A7 + + + - - 8 14,17 B8 A8 + + + - -*/ - -/* calculate rhythm */ - -INLINE void OPL_CALC_RH( FM_OPL *OPL, OPL_CH *CH, unsigned int noise ) -{ - OPL_SLOT *SLOT; - signed int out; - unsigned int env; - - - /* Bass Drum (verified on real YM3812): - - depends on the channel 6 'connect' register: - when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) - when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored - - output sample always is multiplied by 2 - */ - - OPL->phase_modulation = 0; - /* SLOT 1 */ - SLOT = &CH[6].SLOT[SLOT1]; - env = volume_calc(SLOT); - - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - SLOT->op1_out[0] = SLOT->op1_out[1]; - - if (!SLOT->CON) - OPL->phase_modulation = SLOT->op1_out[0]; - /* else ignore output of operator 1 */ - - SLOT->op1_out[1] = 0; - if( env < ENV_QUIET ) - { - if (!SLOT->FB) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); - } - - /* SLOT 2 */ - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable) * 2; - - - /* Phase generation is based on: */ - /* HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) */ - /* SD (16) channel 7->slot 1 */ - /* TOM (14) channel 8->slot 1 */ - /* TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ - - /* Envelope generation based on: */ - /* HH channel 7->slot1 */ - /* SD channel 7->slot2 */ - /* TOM channel 8->slot1 */ - /* TOP channel 8->slot2 */ - - - /* The following formulas can be well optimized. - I leave them in direct form for now (in case I've missed something). - */ - - /* High Hat (verified on real YM3812) */ - env = volume_calc(OPL->SLOT7_1); - if( env < ENV_QUIET ) - { - - /* high hat phase generation: - phase = d0 or 234 (based on frequency only) - phase = 34 or 2d0 (based on noise) - */ - - /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit7 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>7)&1; - unsigned char bit3 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>2)&1; - - unsigned char res1 = (bit2 ^ bit7) | bit3; - - /* when res1 = 0 phase = 0x000 | 0xd0; */ - /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ - UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; - - /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((OPL->SLOT8_2->Cnt>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((OPL->SLOT8_2->Cnt>>FREQ_SH)>>3)&1; - - unsigned char res2 = (bit3e ^ bit5e); - - /* when res2 = 0 pass the phase from calculation above (res1); */ - /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ - if (res2) - phase = (0x200|(0xd0>>2)); - - - /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ - /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ - if (phase&0x200) - { - if (noise) - phase = 0x200|0xd0; - } - else - /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ - /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ - { - if (noise) - phase = 0xd0>>2; - } - - OPL->output[0] += op_calc(phase<SLOT7_1->wavetable) * 2; - } - - /* Snare Drum (verified on real YM3812) */ - env = volume_calc(OPL->SLOT7_2); - if( env < ENV_QUIET ) - { - /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit8 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>8)&1; - - /* when bit8 = 0 phase = 0x100; */ - /* when bit8 = 1 phase = 0x200; */ - UINT32 phase = bit8 ? 0x200 : 0x100; - - /* Noise bit XOR'es phase by 0x100 */ - /* when noisebit = 0 pass the phase from calculation above */ - /* when noisebit = 1 phase ^= 0x100; */ - /* in other words: phase ^= (noisebit<<8); */ - if (noise) - phase ^= 0x100; - - OPL->output[0] += op_calc(phase<SLOT7_2->wavetable) * 2; - } - - /* Tom Tom (verified on real YM3812) */ - env = volume_calc(OPL->SLOT8_1); - if( env < ENV_QUIET ) - OPL->output[0] += op_calc(OPL->SLOT8_1->Cnt, env, 0, OPL->SLOT8_1->wavetable) * 2; - - /* Top Cymbal (verified on real YM3812) */ - env = volume_calc(OPL->SLOT8_2); - if( env < ENV_QUIET ) - { - /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit7 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>7)&1; - unsigned char bit3 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>2)&1; - - unsigned char res1 = (bit2 ^ bit7) | bit3; - - /* when res1 = 0 phase = 0x000 | 0x100; */ - /* when res1 = 1 phase = 0x200 | 0x100; */ - UINT32 phase = res1 ? 0x300 : 0x100; - - /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((OPL->SLOT8_2->Cnt>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((OPL->SLOT8_2->Cnt>>FREQ_SH)>>3)&1; - - unsigned char res2 = (bit3e ^ bit5e); - /* when res2 = 0 pass the phase from calculation above (res1); */ - /* when res2 = 1 phase = 0x200 | 0x100; */ - if (res2) - phase = 0x300; - - OPL->output[0] += op_calc(phase<SLOT8_2->wavetable) * 2; - } - -} - - -/* generic table initialize */ -static int init_tables(void) -{ - signed int i,x; - signed int n; - double o,m; - - - for (x=0; x>= 4; /* 12 bits here */ - if (n&1) /* round to nearest */ - n = (n>>1)+1; - else - n = n>>1; - /* 11 bits here (rounded) */ - n <<= 1; /* 12 bits here (as in real chip) */ - tl_tab[ x*2 + 0 ] = n; - tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; - - for (i=1; i<12; i++) - { - tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; - tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; - } - #if 0 - logerror("tl %04i", x*2); - for (i=0; i<12; i++) - logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); - logerror("\n"); - #endif - } - /*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ - - - for (i=0; i0.0) - o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ - else - o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ - - o = o / (ENV_STEP/4); - - n = (int)(2.0*o); - if (n&1) /* round to nearest */ - n = (n>>1)+1; - else - n = n>>1; - - sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); - - /*logerror("FMOPL.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ - } - - for (i=0; i>1) ]; - - /* waveform 3: _ _ _ _ */ - /* / |_/ |_/ |_/ |_*/ - /* abs(output only first quarter of the sinus waveform) */ - - if (i & (1<<(SIN_BITS-2)) ) - sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; - else - sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; - - /*logerror("FMOPL.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); - logerror("FMOPL.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); - logerror("FMOPL.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );*/ - } - /*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ - - -#ifdef SAVE_SAMPLE - sample[0]=fopen("sampsum.pcm","wb"); -#endif - - return 1; -} - -static void OPLCloseTable( void ) -{ -#ifdef SAVE_SAMPLE - fclose(sample[0]); -#endif -} - - - -static void OPL_initalize(FM_OPL *OPL) -{ - int i; - - /* frequency base */ - OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate : 0; -#if 0 - OPL->rate = (double)OPL->clock / 72.0; - OPL->freqbase = 1.0; -#endif - - /*logerror("freqbase=%f\n", OPL->freqbase);*/ - - /* Timer base time */ - //OPL->TimerBase = attotime_mul(ATTOTIME_IN_HZ(OPL->clock), 72); - - /* make fnumber -> increment counter table */ - for( i=0 ; i < 1024 ; i++ ) - { - /* opn phase increment counter = 20bit */ - OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ -#if 0 - logerror("FMOPL.C: fn_tab[%4i] = %08x (dec=%8i)\n", - i, OPL->fn_tab[i]>>6, OPL->fn_tab[i]>>6 ); -#endif - } - -#if 0 - for( i=0 ; i < 16 ; i++ ) - { - logerror("FMOPL.C: sl_tab[%i] = %08x\n", - i, sl_tab[i] ); - } - for( i=0 ; i < 8 ; i++ ) - { - int j; - logerror("FMOPL.C: ksl_tab[oct=%2i] =",i); - for (j=0; j<16; j++) - { - logerror("%08x ", ksl_tab[i*16+j] ); - } - logerror("\n"); - } -#endif - - - /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ - /* One entry from LFO_AM_TABLE lasts for 64 samples */ - OPL->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; - - /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ - OPL->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; - - /*logerror ("OPL->lfo_am_inc = %8x ; OPL->lfo_pm_inc = %8x\n", OPL->lfo_am_inc, OPL->lfo_pm_inc);*/ - - /* Noise generator: a step takes 1 sample */ - OPL->noise_f = (1.0 / 1.0) * (1<freqbase; - - OPL->eg_timer_add = (1<freqbase; - OPL->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, OPL->eg_timer_overflow);*/ - -} - -INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) -{ - if( !SLOT->key ) - { - /* restart Phase Generator */ - SLOT->Cnt = 0; - /* phase -> Attack */ - SLOT->state = EG_ATT; - } - SLOT->key |= key_set; -} - -INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) -{ - if( SLOT->key ) - { - SLOT->key &= key_clr; - - if( !SLOT->key ) - { - /* phase -> Release */ - if (SLOT->state>EG_REL) - SLOT->state = EG_REL; - } - } -} - -/* update phase increment counter of operator (also update the EG rates if necessary) */ -INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) -{ - int ksr; - - /* (frequency) phase increment counter */ - SLOT->Incr = CH->fc * SLOT->mul; - ksr = CH->kcode >> SLOT->KSR; - - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - - /* calculate envelope generator rates */ - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; - } -} - -/* set multi,am,vib,EG-TYP,KSR,mul */ -INLINE void set_mul(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->mul = mul_tab[v&0x0f]; - SLOT->KSR = (v&0x10) ? 0 : 2; - SLOT->eg_type = (v&0x20); - SLOT->vib = (v&0x40); - SLOT->AMmask = (v&0x80) ? ~0 : 0; - CALC_FCSLOT(CH,SLOT); -} - -/* set ksl & tl */ -INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ - - SLOT->ksl = ksl ? 3-ksl : 31; - SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ - - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); -} - -/* set attack rate & decay rate */ -INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; - - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - - SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; -} - -/* set sustain level & release rate */ -INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->sl = sl_tab[ v>>4 ]; - - SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; -} - - -/* write a value v to register r on OPL chip */ -static void OPLWriteReg(FM_OPL *OPL, int r, int v) -{ - OPL_CH *CH; - int slot; - UINT32 block_fnum; - - - /* adjust bus to 8 bits */ - r &= 0xff; - v &= 0xff; - - /*if (LOG_CYM_FILE && (cymfile) && (r!=0) ) - { - fputc( (unsigned char)r, cymfile ); - fputc( (unsigned char)v, cymfile ); - }*/ - - - switch(r&0xe0) - { - case 0x00: /* 00-1f:control */ - switch(r&0x1f) - { - case 0x01: /* waveform select enable */ - if(OPL->type&OPL_TYPE_WAVESEL) - { - OPL->wavesel = v&0x20; - /* do not change the waveform previously selected */ - } - break; - case 0x02: /* Timer 1 */ - OPL->T[0] = (256-v)*4; - break; - case 0x03: /* Timer 2 */ - OPL->T[1] = (256-v)*16; - break; - case 0x04: /* IRQ clear / mask and Timer enable */ - if(v&0x80) - { /* IRQ flag clear */ - OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */ - } - else - { /* set IRQ mask ,timer enable*/ - /*UINT8 st1 = v&1; - UINT8 st2 = (v>>1)&1;*/ - - /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ - OPL_STATUS_RESET(OPL, v & (0x78-0x08) ); - OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); - - /* timer 2 */ - /*if(OPL->st[1] != st2) - { - attotime period = st2 ? attotime_mul(OPL->TimerBase, OPL->T[1]) : attotime_zero; - OPL->st[1] = st2; - if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,1,period); - }*/ - /* timer 1 */ - /*if(OPL->st[0] != st1) - { - attotime period = st1 ? attotime_mul(OPL->TimerBase, OPL->T[0]) : attotime_zero; - OPL->st[0] = st1; - if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,0,period); - }*/ - } - break; -#if BUILD_Y8950 - case 0x06: /* Key Board OUT */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_w) - OPL->keyboardhandler_w(OPL->keyboard_param,v); - /*else - logerror("Y8950: write unmapped KEYBOARD port\n");*/ - } - break; - case 0x07: /* DELTA-T control 1 : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); - break; -#endif - case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ - OPL->mode = v; -#if BUILD_Y8950 - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v&0x0f); /* mask 4 LSBs in register 08 for DELTA-T unit */ -#endif - break; - -#if BUILD_Y8950 - case 0x09: /* START ADD */ - case 0x0a: - case 0x0b: /* STOP ADD */ - case 0x0c: - case 0x0d: /* PRESCALE */ - case 0x0e: - case 0x0f: /* ADPCM data write */ - case 0x10: /* DELTA-N */ - case 0x11: /* DELTA-N */ - case 0x12: /* ADPCM volume */ - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); - break; - - case 0x15: /* DAC data high 8 bits (F7,F6...F2) */ - case 0x16: /* DAC data low 2 bits (F1, F0 in bits 7,6) */ - case 0x17: /* DAC data shift (S2,S1,S0 in bits 2,1,0) */ - /*logerror("FMOPL.C: DAC data register written, but not implemented reg=%02x val=%02x\n",r,v);*/ - break; - - case 0x18: /* I/O CTRL (Direction) */ - if(OPL->type&OPL_TYPE_IO) - OPL->portDirection = v&0x0f; - break; - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - OPL->portLatch = v; - if(OPL->porthandler_w) - OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); - } - break; -#endif - default: - /*logerror("FMOPL.C: write to unknown register: %02x\n",r);*/ - break; - } - break; - case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_mul(OPL,slot,v); - break; - case 0x40: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_ksl_tl(OPL,slot,v); - break; - case 0x60: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_ar_dr(OPL,slot,v); - break; - case 0x80: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_sl_rr(OPL,slot,v); - break; - case 0xa0: - if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ - { - OPL->lfo_am_depth = v & 0x80; - OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; - - OPL->rhythm = v&0x3f; - - if(OPL->rhythm&0x20) - { - /* BD key on/off */ - if(v&0x10) - { - FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2); - FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2); - } - else - { - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); - } - /* HH key on/off */ - if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2); - else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); - /* SD key on/off */ - if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2); - else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); - /* TOM key on/off */ - if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2); - else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); - /* TOP-CY key on/off */ - if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2); - else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); - } - else - { - /* BD key off */ - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); - /* HH key off */ - FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); - /* SD key off */ - FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); - /* TOM key off */ - FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); - /* TOP-CY off */ - FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); - } - return; - } - /* keyon,block,fnum */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - if(!(r&0x10)) - { /* a0-a8 */ - block_fnum = (CH->block_fnum&0x1f00) | v; - } - else - { /* b0-b8 */ - block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); - - if(v&0x20) - { - FM_KEYON (&CH->SLOT[SLOT1], 1); - FM_KEYON (&CH->SLOT[SLOT2], 1); - } - else - { - FM_KEYOFF(&CH->SLOT[SLOT1],~1); - FM_KEYOFF(&CH->SLOT[SLOT2],~1); - } - } - /* update */ - if(CH->block_fnum != block_fnum) - { - UINT8 block = block_fnum >> 10; - - CH->block_fnum = block_fnum; - - CH->ksl_base = ksl_tab[block_fnum>>6]; - CH->fc = OPL->fn_tab[block_fnum&0x03ff] >> (7-block); - - /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ - CH->kcode = (CH->block_fnum&0x1c00)>>9; - - /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ - /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ - /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ - if (OPL->mode&0x40) - CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ - else - CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ - - /* refresh Total Level in both SLOTs of this channel */ - CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); - CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); - - /* refresh frequency counter in both SLOTs of this channel */ - CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); - CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); - } - break; - case 0xc0: - /* FB,C */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; - CH->SLOT[SLOT1].CON = v&1; - CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &OPL->output[0] : &OPL->phase_modulation; - break; - case 0xe0: /* waveform select */ - /* simply ignore write to the waveform select register if selecting not enabled in test register */ - if(OPL->wavesel) - { - slot = slot_array[r&0x1f]; - if(slot < 0) return; - CH = &OPL->P_CH[slot/2]; - - CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; - } - break; - } -} - -/*static TIMER_CALLBACK( cymfile_callback ) -{ - if (cymfile) - { - fputc( (unsigned char)0, cymfile ); - } -}*/ - -/* lock/unlock for common table */ -#if 0 -static int OPL_LockTable(/*const device_config *device*/) -{ - num_lock++; - if(num_lock>1) return 0; - - /* first time */ - - cur_chip = NULL; - /* allocate total level table (128kb space) */ - if( !init_tables() ) - { - num_lock--; - return -1; - } - -#if 0 - if (LOG_CYM_FILE) - { - cymfile = fopen("3812_.cym","wb"); - if (cymfile) - timer_pulse ( device->machine, ATTOTIME_IN_HZ(110), NULL, 0, cymfile_callback); /*110 Hz pulse timer*/ - else - logerror("Could not create file 3812_.cym\n"); - } -#endif - - return 0; -} - -static void OPL_UnLockTable(void) -{ - if(num_lock) num_lock--; - if(num_lock) return; - - /* last time */ - - cur_chip = NULL; - OPLCloseTable(); - - /*if (cymfile) - fclose (cymfile); - cymfile = NULL;*/ -} -#endif - -static void OPLResetChip(FM_OPL *OPL) -{ - int c,s; - int i; - - OPL->eg_timer = 0; - OPL->eg_cnt = 0; - - OPL->noise_rng = 1; /* noise shift register */ - OPL->mode = 0; /* normal mode */ - OPL_STATUS_RESET(OPL,0x7f); - - /* reset with register write */ - OPLWriteReg(OPL,0x01,0); /* wavesel disable */ - OPLWriteReg(OPL,0x02,0); /* Timer1 */ - OPLWriteReg(OPL,0x03,0); /* Timer2 */ - OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ - for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); - - /* reset operator parameters */ - for( c = 0 ; c < 9 ; c++ ) - { - OPL_CH *CH = &OPL->P_CH[c]; - for(s = 0 ; s < 2 ; s++ ) - { - /* wave table */ - CH->SLOT[s].wavetable = 0; - CH->SLOT[s].state = EG_OFF; - CH->SLOT[s].volume = MAX_ATT_INDEX; - } - } -#if BUILD_Y8950 - if(OPL->type&OPL_TYPE_ADPCM) - { - YM_DELTAT *DELTAT = OPL->deltat; - - DELTAT->freqbase = OPL->freqbase; - DELTAT->output_pointer = &OPL->output_deltat[0]; - DELTAT->portshift = 5; - DELTAT->output_range = 1<<23; - YM_DELTAT_ADPCM_Reset(DELTAT,0,YM_DELTAT_EMULATION_MODE_NORMAL); - } -#endif -} - - -#if 0 -static STATE_POSTLOAD( OPL_postload ) -{ - FM_OPL *OPL = (FM_OPL *)param; - int slot, ch; - - for( ch=0 ; ch < 9 ; ch++ ) - { - OPL_CH *CH = &OPL->P_CH[ch]; - - /* Look up key scale level */ - UINT32 block_fnum = CH->block_fnum; - CH->ksl_base = ksl_tab[block_fnum >> 6]; - CH->fc = OPL->fn_tab[block_fnum & 0x03ff] >> (7 - (block_fnum >> 10)); - - for( slot=0 ; slot < 2 ; slot++ ) - { - OPL_SLOT *SLOT = &CH->SLOT[slot]; - - /* Calculate key scale rate */ - SLOT->ksr = CH->kcode >> SLOT->KSR; - - /* Calculate attack, decay and release rates */ - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; - - /* Calculate phase increment */ - SLOT->Incr = CH->fc * SLOT->mul; - - /* Total level */ - SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl); - - /* Connect output */ - SLOT->connect1 = SLOT->CON ? &OPL->output[0] : &OPL->phase_modulation; - } - } -#if BUILD_Y8950 - if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) - { - // We really should call the postlod function for the YM_DELTAT, but it's hard without registers - // (see the way the YM2610 does it) - //YM_DELTAT_postload(OPL->deltat, REGS); - } -#endif -} - - -static void OPLsave_state_channel(const device_config *device, OPL_CH *CH) -{ - int slot, ch; - - for( ch=0 ; ch < 9 ; ch++, CH++ ) - { - /* channel */ - state_save_register_device_item(device, ch, CH->block_fnum); - state_save_register_device_item(device, ch, CH->kcode); - /* slots */ - for( slot=0 ; slot < 2 ; slot++ ) - { - OPL_SLOT *SLOT = &CH->SLOT[slot]; - - state_save_register_device_item(device, ch * 2 + slot, SLOT->ar); - state_save_register_device_item(device, ch * 2 + slot, SLOT->dr); - state_save_register_device_item(device, ch * 2 + slot, SLOT->rr); - state_save_register_device_item(device, ch * 2 + slot, SLOT->KSR); - state_save_register_device_item(device, ch * 2 + slot, SLOT->ksl); - state_save_register_device_item(device, ch * 2 + slot, SLOT->mul); - - state_save_register_device_item(device, ch * 2 + slot, SLOT->Cnt); - state_save_register_device_item(device, ch * 2 + slot, SLOT->FB); - state_save_register_device_item_array(device, ch * 2 + slot, SLOT->op1_out); - state_save_register_device_item(device, ch * 2 + slot, SLOT->CON); - - state_save_register_device_item(device, ch * 2 + slot, SLOT->eg_type); - state_save_register_device_item(device, ch * 2 + slot, SLOT->state); - state_save_register_device_item(device, ch * 2 + slot, SLOT->TL); - state_save_register_device_item(device, ch * 2 + slot, SLOT->volume); - state_save_register_device_item(device, ch * 2 + slot, SLOT->sl); - state_save_register_device_item(device, ch * 2 + slot, SLOT->key); - - state_save_register_device_item(device, ch * 2 + slot, SLOT->AMmask); - state_save_register_device_item(device, ch * 2 + slot, SLOT->vib); - - state_save_register_device_item(device, ch * 2 + slot, SLOT->wavetable); - } - } -} - - -/* Register savestate for a virtual YM3812/YM3526Y8950 */ - -static void OPL_save_state(FM_OPL *OPL, const device_config *device) -{ - OPLsave_state_channel(device, OPL->P_CH); - - state_save_register_device_item(device, 0, OPL->eg_cnt); - state_save_register_device_item(device, 0, OPL->eg_timer); - - state_save_register_device_item(device, 0, OPL->rhythm); - - state_save_register_device_item(device, 0, OPL->lfo_am_depth); - state_save_register_device_item(device, 0, OPL->lfo_pm_depth_range); - state_save_register_device_item(device, 0, OPL->lfo_am_cnt); - state_save_register_device_item(device, 0, OPL->lfo_pm_cnt); - - state_save_register_device_item(device, 0, OPL->noise_rng); - state_save_register_device_item(device, 0, OPL->noise_p); - - if( OPL->type & OPL_TYPE_WAVESEL ) - { - state_save_register_device_item(device, 0, OPL->wavesel); - } - - state_save_register_device_item_array(device, 0, OPL->T); - state_save_register_device_item_array(device, 0, OPL->st); - -#if BUILD_Y8950 - if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) - { - YM_DELTAT_savestate(device, OPL->deltat); - } - - if ( OPL->type & OPL_TYPE_IO ) - { - state_save_register_device_item(device, 0, OPL->portDirection); - state_save_register_device_item(device, 0, OPL->portLatch); - } -#endif - - state_save_register_device_item(device, 0, OPL->address); - state_save_register_device_item(device, 0, OPL->status); - state_save_register_device_item(device, 0, OPL->statusmask); - state_save_register_device_item(device, 0, OPL->mode); - - state_save_register_postload(device->machine, OPL_postload, OPL); -} -#endif - - -/* Create one of virtual YM3812/YM3526/Y8950 */ -/* 'clock' is chip clock in Hz */ -/* 'rate' is sampling rate */ -static FM_OPL *OPLCreate(UINT32 clock, UINT32 rate, int type) -{ - char *ptr; - FM_OPL *OPL; - int state_size; - - //if (OPL_LockTable(device) == -1) return NULL; - init_tables(); - - /* calculate OPL state size */ - state_size = sizeof(FM_OPL); - -#if BUILD_Y8950 - if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); -#endif - - /* allocate memory block */ - ptr = (char *)malloc(state_size); - - if (ptr==NULL) - return 0; - - /* clear */ - memset(ptr,0,state_size); - - OPL = (FM_OPL *)ptr; - - ptr += sizeof(FM_OPL); - -#if BUILD_Y8950 - if (type&OPL_TYPE_ADPCM) - { - OPL->deltat = (YM_DELTAT *)ptr; - } - ptr += sizeof(YM_DELTAT); -#endif - - OPL->type = type; - OPL->clock = clock; - OPL->rate = rate; - - /* init global tables */ - OPL_initalize(OPL); - - return OPL; -} - -/* Destroy one of virtual YM3812 */ -static void OPLDestroy(FM_OPL *OPL) -{ - //OPL_UnLockTable(); - free(OPL); -} - -/* Optional handlers */ - -/*static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER timer_handler,void *param) -{ - OPL->timer_handler = timer_handler; - OPL->TimerParam = param; -}*/ -static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,void *param) -{ - OPL->IRQHandler = IRQHandler; - OPL->IRQParam = param; -} -static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,void *param) -{ - OPL->UpdateHandler = UpdateHandler; - OPL->UpdateParam = param; -} - -static int OPLWrite(FM_OPL *OPL,int a,int v) -{ - if( !(a&1) ) - { /* address port */ - OPL->address = v & 0xff; - } - else - { /* data port */ - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - OPLWriteReg(OPL,OPL->address,v); - } - return OPL->status>>7; -} - -static unsigned char OPLRead(FM_OPL *OPL,int a) -{ - if( !(a&1) ) - { - /* status port */ - - #if BUILD_Y8950 - - if(OPL->type&OPL_TYPE_ADPCM) /* Y8950 */ - { - return (OPL->status & (OPL->statusmask|0x80)) | (OPL->deltat->PCM_BSY&1); - } - - #endif - - /* OPL and OPL2 */ - return OPL->status & (OPL->statusmask|0x80); - } - -#if BUILD_Y8950 - /* data port */ - switch(OPL->address) - { - case 0x05: /* KeyBoard IN */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_r) - return OPL->keyboardhandler_r(OPL->keyboard_param); - /*else - logerror("Y8950: read unmapped KEYBOARD port\n");*/ - } - return 0; - - case 0x0f: /* ADPCM-DATA */ - if(OPL->type&OPL_TYPE_ADPCM) - { - UINT8 val; - - val = YM_DELTAT_ADPCM_Read(OPL->deltat); - /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/ - return val; - } - return 0; - - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - if(OPL->porthandler_r) - return OPL->porthandler_r(OPL->port_param); - /*else - logerror("Y8950:read unmapped I/O port\n");*/ - } - return 0; - case 0x1a: /* PCM-DATA */ - if(OPL->type&OPL_TYPE_ADPCM) - { - /*logerror("Y8950 A/D convertion is accessed but not implemented !\n");*/ - return 0x80; /* 2's complement PCM data - result from A/D convertion */ - } - return 0; - } -#endif - - return 0xff; -} - -/* CSM Key Controll */ -INLINE void CSMKeyControll(OPL_CH *CH) -{ - FM_KEYON (&CH->SLOT[SLOT1], 4); - FM_KEYON (&CH->SLOT[SLOT2], 4); - - /* The key off should happen exactly one sample later - not implemented correctly yet */ - - FM_KEYOFF(&CH->SLOT[SLOT1], ~4); - FM_KEYOFF(&CH->SLOT[SLOT2], ~4); -} - - -static int OPLTimerOver(FM_OPL *OPL,int c) -{ - if( c ) - { /* Timer B */ - OPL_STATUS_SET(OPL,0x20); - } - else - { /* Timer A */ - OPL_STATUS_SET(OPL,0x40); - /* CSM mode key,TL controll */ - if( OPL->mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - int ch; - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - for(ch=0; ch<9; ch++) - CSMKeyControll( &OPL->P_CH[ch] ); - } - } - /* reload timer */ - //if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,c,attotime_mul(OPL->TimerBase, OPL->T[c])); - return OPL->status>>7; -} - - -#define MAX_OPL_CHIPS 2 - - -#if (BUILD_YM3812) - -void * ym3812_init(UINT32 clock, UINT32 rate) -{ - /* emulator create */ - FM_OPL *YM3812 = OPLCreate(clock,rate,OPL_TYPE_YM3812); - if (YM3812) - { - //OPL_save_state(YM3812); - ym3812_reset_chip(YM3812); - } - return YM3812; -} - -void ym3812_shutdown(void *chip) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - - /* emulator shutdown */ - OPLDestroy(YM3812); -} -void ym3812_reset_chip(void *chip) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLResetChip(YM3812); -} - -int ym3812_write(void *chip, int a, int v) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - return OPLWrite(YM3812, a, v); -} - -unsigned char ym3812_read(void *chip, int a) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - /* YM3812 always returns bit2 and bit1 in HIGH state */ - return OPLRead(YM3812, a) | 0x06 ; -} -int ym3812_timer_over(void *chip, int c) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - return OPLTimerOver(YM3812, c); -} - -/*void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetTimerHandler(YM3812, timer_handler, param); -}*/ -void ym3812_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetIRQHandler(YM3812, IRQHandler, param); -} -void ym3812_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetUpdateHandler(YM3812, UpdateHandler, param); -} - - -/* -** Generate samples for one of the YM3812's -** -** 'which' is the virtual YM3812 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length) -{ - FM_OPL *OPL = (FM_OPL *)chip; - UINT8 rhythm = OPL->rhythm&0x20; - OPLSAMPLE *buf = buffer; - int i; - - /* rhythm slots */ - OPL->SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; - OPL->SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; - OPL->SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; - OPL->SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; - for( i=0; i < length ; i++ ) - { - int lt; - - OPL->output[0] = 0; - - advance_lfo(OPL); - - /* FM part */ - OPL_CALC_CH(OPL, &OPL->P_CH[0]); - OPL_CALC_CH(OPL, &OPL->P_CH[1]); - OPL_CALC_CH(OPL, &OPL->P_CH[2]); - OPL_CALC_CH(OPL, &OPL->P_CH[3]); - OPL_CALC_CH(OPL, &OPL->P_CH[4]); - OPL_CALC_CH(OPL, &OPL->P_CH[5]); - - if(!rhythm) - { - OPL_CALC_CH(OPL, &OPL->P_CH[6]); - OPL_CALC_CH(OPL, &OPL->P_CH[7]); - OPL_CALC_CH(OPL, &OPL->P_CH[8]); - } - else /* Rhythm part */ - { - OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); - } - - lt = OPL->output[0]; - - lt >>= FINAL_SH; - - /* limit check */ - lt = limit( lt , MAXOUT, MINOUT ); - - #ifdef SAVE_SAMPLE - if (which==0) - { - SAVE_ALL_CHANNELS - } - #endif - - /* store to sound buffer */ - buf[i] = lt; - - advance(OPL); - } - -} -#endif /* BUILD_YM3812 */ - - - -#if (BUILD_YM3526) - -void *ym3526_init(UINT32 clock, UINT32 rate) -{ - /* emulator create */ - FM_OPL *YM3526 = OPLCreate(clock,rate,OPL_TYPE_YM3526); - if (YM3526) - { - /*OPL_save_state(YM3526);*/ - ym3526_reset_chip(YM3526); - } - return YM3526; -} - -void ym3526_shutdown(void *chip) -{ - FM_OPL *YM3526 = (FM_OPL *)chip; - /* emulator shutdown */ - OPLDestroy(YM3526); -} -void ym3526_reset_chip(void *chip) -{ - FM_OPL *YM3526 = (FM_OPL *)chip; - OPLResetChip(YM3526); -} - -int ym3526_write(void *chip, int a, int v) -{ - FM_OPL *YM3526 = (FM_OPL *)chip; - return OPLWrite(YM3526, a, v); -} - -unsigned char ym3526_read(void *chip, int a) -{ - FM_OPL *YM3526 = (FM_OPL *)chip; - /* YM3526 always returns bit2 and bit1 in HIGH state */ - return OPLRead(YM3526, a) | 0x06 ; -} -int ym3526_timer_over(void *chip, int c) -{ - FM_OPL *YM3526 = (FM_OPL *)chip; - return OPLTimerOver(YM3526, c); -} - -/*void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) -{ - FM_OPL *YM3526 = (FM_OPL *)chip; - OPLSetTimerHandler(YM3526, timer_handler, param); -}*/ -void ym3526_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) -{ - FM_OPL *YM3526 = (FM_OPL *)chip; - OPLSetIRQHandler(YM3526, IRQHandler, param); -} -void ym3526_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) -{ - FM_OPL *YM3526 = (FM_OPL *)chip; - OPLSetUpdateHandler(YM3526, UpdateHandler, param); -} - - -/* -** Generate samples for one of the YM3526's -** -** 'which' is the virtual YM3526 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length) -{ - FM_OPL *OPL = (FM_OPL *)chip; - UINT8 rhythm = OPL->rhythm&0x20; - OPLSAMPLE *buf = buffer; - int i; - - /* rhythm slots */ - OPL->SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; - OPL->SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; - OPL->SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; - OPL->SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; - for( i=0; i < length ; i++ ) - { - int lt; - - OPL->output[0] = 0; - - advance_lfo(OPL); - - /* FM part */ - OPL_CALC_CH(OPL, &OPL->P_CH[0]); - OPL_CALC_CH(OPL, &OPL->P_CH[1]); - OPL_CALC_CH(OPL, &OPL->P_CH[2]); - OPL_CALC_CH(OPL, &OPL->P_CH[3]); - OPL_CALC_CH(OPL, &OPL->P_CH[4]); - OPL_CALC_CH(OPL, &OPL->P_CH[5]); - - if(!rhythm) - { - OPL_CALC_CH(OPL, &OPL->P_CH[6]); - OPL_CALC_CH(OPL, &OPL->P_CH[7]); - OPL_CALC_CH(OPL, &OPL->P_CH[8]); - } - else /* Rhythm part */ - { - OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); - } - - lt = OPL->output[0]; - - lt >>= FINAL_SH; - - /* limit check */ - lt = limit( lt , MAXOUT, MINOUT ); - - #ifdef SAVE_SAMPLE - if (which==0) - { - SAVE_ALL_CHANNELS - } - #endif - - /* store to sound buffer */ - buf[i] = lt; - - advance(OPL); - } - -} -#endif /* BUILD_YM3526 */ - - - - -#if BUILD_Y8950 - -static void Y8950_deltat_status_set(void *chip, UINT8 changebits) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - OPL_STATUS_SET(Y8950, changebits); -} -static void Y8950_deltat_status_reset(void *chip, UINT8 changebits) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - OPL_STATUS_RESET(Y8950, changebits); -} - -void *y8950_init(UINT32 clock, UINT32 rate) -{ - /* emulator create */ - FM_OPL *Y8950 = OPLCreate(clock,rate,OPL_TYPE_Y8950); - if (Y8950) - { - Y8950->deltat->status_set_handler = Y8950_deltat_status_set; - Y8950->deltat->status_reset_handler = Y8950_deltat_status_reset; - Y8950->deltat->status_change_which_chip = Y8950; - Y8950->deltat->status_change_EOS_bit = 0x10; /* status flag: set bit4 on End Of Sample */ - Y8950->deltat->status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY (End Of: ADPCM analysis/synthesis, memory reading/writing) */ - - /*Y8950->deltat->write_time = 10.0 / clock;*/ /* a single byte write takes 10 cycles of main clock */ - /*Y8950->deltat->read_time = 8.0 / clock;*/ /* a single byte read takes 8 cycles of main clock */ - /* reset */ - /*OPL_save_state(Y8950);*/ - y8950_reset_chip(Y8950); - } - - return Y8950; -} - -void y8950_shutdown(void *chip) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - /* emulator shutdown */ - OPLDestroy(Y8950); -} -void y8950_reset_chip(void *chip) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - OPLResetChip(Y8950); -} - -int y8950_write(void *chip, int a, int v) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - return OPLWrite(Y8950, a, v); -} - -unsigned char y8950_read(void *chip, int a) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - return OPLRead(Y8950, a); -} -int y8950_timer_over(void *chip, int c) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - return OPLTimerOver(Y8950, c); -} - -/*void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - OPLSetTimerHandler(Y8950, timer_handler, param); -}*/ -void y8950_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - OPLSetIRQHandler(Y8950, IRQHandler, param); -} -void y8950_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) -{ - FM_OPL *Y8950 = (FM_OPL *)chip; - OPLSetUpdateHandler(Y8950, UpdateHandler, param); -} - -void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ) -{ - FM_OPL *OPL = (FM_OPL *)chip; - OPL->deltat->memory = (UINT8 *)(deltat_mem_ptr); - OPL->deltat->memory_size = deltat_mem_size; -} - -/* -** Generate samples for one of the Y8950's -** -** 'which' is the virtual Y8950 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length) -{ - int i; - FM_OPL *OPL = (FM_OPL *)chip; - UINT8 rhythm = OPL->rhythm&0x20; - YM_DELTAT *DELTAT = OPL->deltat; - OPLSAMPLE *buf = buffer; - - /* rhythm slots */ - OPL->SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; - OPL->SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; - OPL->SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; - OPL->SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; - - for( i=0; i < length ; i++ ) - { - int lt; - - OPL->output[0] = 0; - OPL->output_deltat[0] = 0; - - advance_lfo(OPL); - - /* deltaT ADPCM */ - if( DELTAT->portstate&0x80 ) - YM_DELTAT_ADPCM_CALC(DELTAT); - - /* FM part */ - OPL_CALC_CH(OPL, &OPL->P_CH[0]); - OPL_CALC_CH(OPL, &OPL->P_CH[1]); - OPL_CALC_CH(OPL, &OPL->P_CH[2]); - OPL_CALC_CH(OPL, &OPL->P_CH[3]); - OPL_CALC_CH(OPL, &OPL->P_CH[4]); - OPL_CALC_CH(OPL, &OPL->P_CH[5]); - - if(!rhythm) - { - OPL_CALC_CH(OPL, &OPL->P_CH[6]); - OPL_CALC_CH(OPL, &OPL->P_CH[7]); - OPL_CALC_CH(OPL, &OPL->P_CH[8]); - } - else /* Rhythm part */ - { - OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); - } - - lt = OPL->output[0] + (OPL->output_deltat[0]>>11); - - lt >>= FINAL_SH; - - /* limit check */ - lt = limit( lt , MAXOUT, MINOUT ); - - #ifdef SAVE_SAMPLE - if (which==0) - { - SAVE_ALL_CHANNELS - } - #endif - - /* store to sound buffer */ - buf[i] = lt; - - advance(OPL); - } - -} - -void y8950_set_port_handler(void *chip,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,void * param) -{ - FM_OPL *OPL = (FM_OPL *)chip; - OPL->porthandler_w = PortHandler_w; - OPL->porthandler_r = PortHandler_r; - OPL->port_param = param; -} - -void y8950_set_keyboard_handler(void *chip,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,void * param) -{ - FM_OPL *OPL = (FM_OPL *)chip; - OPL->keyboardhandler_w = KeyboardHandler_w; - OPL->keyboardhandler_r = KeyboardHandler_r; - OPL->keyboard_param = param; -} - -#endif - +/* +** +** File: fmopl.c - software implementation of FM sound generator +** types OPL and OPL2 +** +** Copyright Jarek Burczynski (bujar at mame dot net) +** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development +** +** Version 0.72 +** + +Revision History: + +04-08-2003 Jarek Burczynski: + - removed BFRDY hack. BFRDY is busy flag, and it should be 0 only when the chip + handles memory read/write or during the adpcm synthesis when the chip + requests another byte of ADPCM data. + +24-07-2003 Jarek Burczynski: + - added a small hack for Y8950 status BFRDY flag (bit 3 should be set after + some (unknown) delay). Right now it's always set. + +14-06-2003 Jarek Burczynski: + - implemented all of the status register flags in Y8950 emulation + - renamed y8950_set_delta_t_memory() parameters from _rom_ to _mem_ since + they can be either RAM or ROM + +08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip) + - corrected ym3526_read() to always set bit 2 and bit 1 + to HIGH state - identical to ym3812_read (verified on real YM3526) + +04-28-2002 Jarek Burczynski: + - binary exact Envelope Generator (verified on real YM3812); + compared to YM2151: the EG clock is equal to internal_clock, + rates are 2 times slower and volume resolution is one bit less + - modified interface functions (they no longer return pointer - + that's internal to the emulator now): + - new wrapper functions for OPLCreate: ym3526_init(), ym3812_init() and y8950_init() + - corrected 'off by one' error in feedback calculations (when feedback is off) + - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) + - speeded up noise generator calculations (Nicola Salmoria) + +03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) + Complete rewrite (all verified on real YM3812): + - corrected sin_tab and tl_tab data + - corrected operator output calculations + - corrected waveform_select_enable register; + simply: ignore all writes to waveform_select register when + waveform_select_enable == 0 and do not change the waveform previously selected. + - corrected KSR handling + - corrected Envelope Generator: attack shape, Sustain mode and + Percussive/Non-percussive modes handling + - Envelope Generator rates are two times slower now + - LFO amplitude (tremolo) and phase modulation (vibrato) + - rhythm sounds phase generation + - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm) + - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM) + - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1) + +12-28-2001 Acho A. Tang + - reflected Delta-T EOS status on Y8950 status port. + - fixed subscription range of attack/decay tables + + + To do: + add delay before key off in CSM mode (see CSMKeyControll) + verify volume of the FM part on the Y8950 +*/ + +#include +#include +#define _USE_MATH_DEFINES +#include +#include "fmopl.h" +#include "ymdeltat.h" + +#ifndef INLINE +#define INLINE __inline +#endif +#ifndef NULL + #define NULL ((void *)0) +#endif +#ifndef logerror +#define logerror (void) +#endif + +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif + +/* output final shift */ +#if (OPL_SAMPLE_BITS==16) + #define FINAL_SH (0) + #define MAXOUT (+32767) + #define MINOUT (-32768) +#else + #define FINAL_SH (8) + #define MAXOUT (+127) + #define MINOUT (-128) +#endif + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<=0) + { + if (value < 0x0200) + return (value & ~0); + if (value < 0x0400) + return (value & ~1); + if (value < 0x0800) + return (value & ~3); + if (value < 0x1000) + return (value & ~7); + if (value < 0x2000) + return (value & ~15); + if (value < 0x4000) + return (value & ~31); + return (value & ~63); + } + /*else value < 0*/ + if (value > -0x0200) + return (~abs(value) & ~0); + if (value > -0x0400) + return (~abs(value) & ~1); + if (value > -0x0800) + return (~abs(value) & ~3); + if (value > -0x1000) + return (~abs(value) & ~7); + if (value > -0x2000) + return (~abs(value) & ~15); + if (value > -0x4000) + return (~abs(value) & ~31); + return (~abs(value) & ~63); +} + + +static FILE *sample[1]; + #if 1 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = acc_calc(lt); \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = lt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = rt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + +#define LOG_CYM_FILE 0 +//static FILE * cymfile = NULL; + + + +#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ +#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ +#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ +#define OPL_TYPE_IO 0x08 /* I/O port */ + +/* ---------- Generic interface section ---------- */ +#define OPL_TYPE_YM3526 (0) +#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) +#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) + + + +typedef struct{ + UINT32 ar; /* attack rate: AR<<2 */ + UINT32 dr; /* decay rate: DR<<2 */ + UINT32 rr; /* release rate:RR<<2 */ + UINT8 KSR; /* key scale rate */ + UINT8 ksl; /* keyscale level */ + UINT8 ksr; /* key scale rate: kcode>>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 Cnt; /* frequency counter */ + UINT32 Incr; /* frequency counter step */ + UINT8 FB; /* feedback shift value */ + INT32 *connect1; /* slot1 output pointer */ + INT32 op1_out[2]; /* slot1 output for feedback */ + UINT8 CON; /* connection (algorithm) type */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/non-percussive mode */ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + UINT16 wavetable; +} OPL_SLOT; + +typedef struct{ + OPL_SLOT SLOT[2]; + /* phase generator state */ + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ +} OPL_CH; + +/* OPL state */ +typedef struct fm_opl_f { + /* FM channel slots */ + OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT8 rhythm; /* Rhythm mode */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + /* LFO */ + UINT8 lfo_am_depth; + UINT8 lfo_pm_depth_range; + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + UINT8 wavesel; /* waveform select enable flag */ + + UINT32 T[2]; /* timer counters */ + UINT8 st[2]; /* timer enable */ + +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + + YM_DELTAT *deltat; + + /* Keyboard and I/O ports interface */ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + void * port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + void * keyboard_param; +#endif + + /* external event callback handlers */ + //OPL_TIMERHANDLER timer_handler; /* TIMER handler */ + void *TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + void *IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ + void *UpdateParam; /* stream update parameter */ + + UINT8 type; /* chip type */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ + + UINT32 clock; /* master clock (Hz) */ + UINT32 rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + //attotime TimerBase; /* Timer base time (==sampling time)*/ + + OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2; + + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + signed int output[1]; + +#if BUILD_Y8950 + INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */ +#endif + + UINT32 LFO_AM; + INT32 LFO_PM; +} FM_OPL; + + + +/* mapping of register number (offset) to slot number used by the emulator */ +static const int slot_array[32]= +{ + 0, 2, 4, 1, 3, 5,-1,-1, + 6, 8,10, 7, 9,11,-1,-1, + 12,14,16,13,15,17,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1 +}; + +/* key scale level */ +/* table is 3dB/octave , DV converts this into 6dB/octave */ +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define DV (0.1875/2.0) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), + /* OCT 1 */ + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), + UINT32( 0.000/DV), UINT32( 0.750/DV), UINT32( 1.125/DV), UINT32( 1.500/DV), + UINT32( 1.875/DV), UINT32( 2.250/DV), UINT32( 2.625/DV), UINT32( 3.000/DV), + /* OCT 2 */ + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), + UINT32( 0.000/DV), UINT32( 1.125/DV), UINT32( 1.875/DV), UINT32( 2.625/DV), + UINT32( 3.000/DV), UINT32( 3.750/DV), UINT32( 4.125/DV), UINT32( 4.500/DV), + UINT32( 4.875/DV), UINT32( 5.250/DV), UINT32( 5.625/DV), UINT32( 6.000/DV), + /* OCT 3 */ + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 1.875/DV), + UINT32( 3.000/DV), UINT32( 4.125/DV), UINT32( 4.875/DV), UINT32( 5.625/DV), + UINT32( 6.000/DV), UINT32( 6.750/DV), UINT32( 7.125/DV), UINT32( 7.500/DV), + UINT32( 7.875/DV), UINT32( 8.250/DV), UINT32( 8.625/DV), UINT32( 9.000/DV), + /* OCT 4 */ + UINT32( 0.000/DV), UINT32( 0.000/DV), UINT32( 3.000/DV), UINT32( 4.875/DV), + UINT32( 6.000/DV), UINT32( 7.125/DV), UINT32( 7.875/DV), UINT32( 8.625/DV), + UINT32( 9.000/DV), UINT32( 9.750/DV), UINT32(10.125/DV), UINT32(10.500/DV), + UINT32(10.875/DV), UINT32(11.250/DV), UINT32(11.625/DV), UINT32(12.000/DV), + /* OCT 5 */ + UINT32( 0.000/DV), UINT32( 3.000/DV), UINT32( 6.000/DV), UINT32( 7.875/DV), + UINT32( 9.000/DV), UINT32(10.125/DV), UINT32(10.875/DV), UINT32(11.625/DV), + UINT32(12.000/DV), UINT32(12.750/DV), UINT32(13.125/DV), UINT32(13.500/DV), + UINT32(13.875/DV), UINT32(14.250/DV), UINT32(14.625/DV), UINT32(15.000/DV), + /* OCT 6 */ + UINT32( 0.000/DV), UINT32( 6.000/DV), UINT32( 9.000/DV), UINT32(10.875/DV), + UINT32(12.000/DV), UINT32(13.125/DV), UINT32(13.875/DV), UINT32(14.625/DV), + UINT32(15.000/DV), UINT32(15.750/DV), UINT32(16.125/DV), UINT32(16.500/DV), + UINT32(16.875/DV), UINT32(17.250/DV), UINT32(17.625/DV), UINT32(18.000/DV), + /* OCT 7 */ + UINT32( 0.000/DV), UINT32( 9.000/DV), UINT32(12.000/DV), UINT32(13.875/DV), + UINT32(15.000/DV), UINT32(16.125/DV), UINT32(16.875/DV), UINT32(17.625/DV), + UINT32(18.000/DV), UINT32(18.750/DV), UINT32(19.125/DV), UINT32(19.500/DV), + UINT32(19.875/DV), UINT32(20.250/DV), UINT32(20.625/DV), UINT32(21.000/DV) +}; +#undef DV + +/* sustain level table (3dB per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) +static const UINT32 sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#define RATE_STEPS (8) +static const unsigned char eg_inc[15*RATE_STEPS]={ + +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ +/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ +/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(13) in this table - it's directly in the code */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), + +/* rates 00-12 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 13 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 14 */ +O( 8),O( 9),O(10),O(11), + +/* rate 15 */ +O(12),O(12),O(12),O(12), + +/* 16 dummy rates (same as 15 3) */ +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ +/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ +/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-12 */ +O(12),O(12),O(12),O(12), +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 16 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), + +}; +#undef O + + +/* multiple table */ +#define ML 2 +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + UINT8( 0.50*ML),UINT8( 1.00*ML),UINT8( 2.00*ML),UINT8( 3.00*ML),UINT8( 4.00*ML),UINT8( 5.00*ML),UINT8( 6.00*ML),UINT8( 7.00*ML), + UINT8( 8.00*ML),UINT8( 9.00*ML),UINT8(10.00*ML),UINT8(10.00*ML),UINT8(12.00*ML),UINT8(12.00*ML),UINT8(15.00*ML),UINT8(15.00*ML) +}; +#undef ML + +/* TL_TAB_LEN is calculated as: +* 12 - sinus amplitude bits (Y axis) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +#define TL_TAB_LEN (12*2*TL_RES_LEN) +static signed int tl_tab[TL_TAB_LEN]; + +#define ENV_QUIET (TL_TAB_LEN>>4) + +/* sin waveform table in 'decibel' scale */ +/* four waveforms on OPL2 type chips */ +static unsigned int sin_tab[SIN_LEN * 4]; + + +/* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples + + Length: 210 elements. + + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. + + When AM = 1 data is used directly + When AM = 0 data is divided by 4 before being used (loosing precision is important) +*/ + +#define LFO_AM_TAB_ELEMENTS 210 + +static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +0,0,0,0,0,0,0, +1,1,1,1, +2,2,2,2, +3,3,3,3, +4,4,4,4, +5,5,5,5, +6,6,6,6, +7,7,7,7, +8,8,8,8, +9,9,9,9, +10,10,10,10, +11,11,11,11, +12,12,12,12, +13,13,13,13, +14,14,14,14, +15,15,15,15, +16,16,16,16, +17,17,17,17, +18,18,18,18, +19,19,19,19, +20,20,20,20, +21,21,21,21, +22,22,22,22, +23,23,23,23, +24,24,24,24, +25,25,25,25, +26,26,26, +25,25,25,25, +24,24,24,24, +23,23,23,23, +22,22,22,22, +21,21,21,21, +20,20,20,20, +19,19,19,19, +18,18,18,18, +17,17,17,17, +16,16,16,16, +15,15,15,15, +14,14,14,14, +13,13,13,13, +12,12,12,12, +11,11,11,11, +10,10,10,10, +9,9,9,9, +8,8,8,8, +7,7,7,7, +6,6,6,6, +5,5,5,5, +4,4,4,4, +3,3,3,3, +2,2,2,2, +1,1,1,1 +}; + +/* LFO Phase Modulation table (verified on real YM3812) */ +static const INT8 lfo_pm_table[8*8*2] = { + +/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ +}; + + +/* lock level of common table */ +//static int num_lock = 0; + + +//static void *cur_chip = NULL; /* current chip pointer */ + +INLINE int limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + + +/* status set and IRQ handling */ +INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) +{ + /* set status flag */ + OPL->status |= flag; + if(!(OPL->status & 0x80)) + { + if(OPL->status & OPL->statusmask) + { /* IRQ on */ + OPL->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) +{ + /* reset status flag */ + OPL->status &=~flag; + if((OPL->status & 0x80)) + { + if (!(OPL->status & OPL->statusmask) ) + { + OPL->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); + } + } +} + +/* IRQ mask set */ +INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) +{ + OPL->statusmask = flag; + /* IRQ handling check */ + OPL_STATUS_SET(OPL,0); + OPL_STATUS_RESET(OPL,0); +} + + +/* advance LFO to next sample */ +INLINE void advance_lfo(FM_OPL *OPL) +{ + UINT8 tmp; + + /* LFO */ + OPL->lfo_am_cnt += OPL->lfo_am_inc; + if (OPL->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; + + if (OPL->lfo_am_depth) + OPL->LFO_AM = tmp; + else + OPL->LFO_AM = tmp>>2; + + OPL->lfo_pm_cnt += OPL->lfo_pm_inc; + OPL->LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; +} + +/* advance to next sample */ +INLINE void advance(FM_OPL *OPL) +{ + OPL_CH *CH; + OPL_SLOT *op; + int i; + + OPL->eg_timer += OPL->eg_timer_add; + + while (OPL->eg_timer >= OPL->eg_timer_overflow) + { + OPL->eg_timer -= OPL->eg_timer_overflow; + + OPL->eg_cnt++; + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Envelope Generator */ + switch(op->state) + { + case EG_ATT: /* attack phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>3; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + break; + + case EG_DEC: /* decay phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= op->sl ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + default: + break; + } + } + } + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Phase Generator */ + if(op->vib) + { + UINT8 block; + unsigned int block_fnum = CH->block_fnum; + + unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; + + signed int lfo_fn_table_index_offset = lfo_pm_table[OPL->LFO_PM + 16*fnum_lfo ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + block_fnum += lfo_fn_table_index_offset; + block = (block_fnum&0x1c00) >> 10; + op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; + } + else /* LFO phase modulation = zero */ + { + op->Cnt += op->Incr; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->Cnt += op->Incr; + } + } + + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. + * + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 + * + * Simply use bit 22 as the noise output. + */ + + OPL->noise_p += OPL->noise_f; + i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + OPL->noise_p &= FREQ_MASK; + while (i) + { + /* + UINT32 j; + j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; + OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; + OPL->noise_rng >>= 1; + + i--; + } +} + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (OPL->LFO_AM & (OP)->AMmask)) + +/* calculate output */ +INLINE void OPL_CALC_CH( FM_OPL *OPL, OPL_CH *CH ) +{ + OPL_SLOT *SLOT; + unsigned int env; + signed int out; + + OPL->phase_modulation = 0; + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + *SLOT->connect1 += SLOT->op1_out[0]; + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable); +} + +/* + operators used in the rhythm sounds generation process: + + Envelope Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal + 6 / 0 12 50 70 90 f0 + + 6 / 1 15 53 73 93 f3 + + 7 / 0 13 51 71 91 f1 + + 7 / 1 16 54 74 94 f4 + + 8 / 0 14 52 72 92 f2 + + 8 / 1 17 55 75 95 f5 + + + Phase Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number MULTIPLE Drum Hat Drum Tom Cymbal + 6 / 0 12 30 + + 6 / 1 15 33 + + 7 / 0 13 31 + + + + 7 / 1 16 34 ----- n o t u s e d ----- + 8 / 0 14 32 + + 8 / 1 17 35 + + + +channel operator register number Bass High Snare Tom Top +number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal + 6 12,15 B6 A6 + + + 7 13,16 B7 A7 + + + + + 8 14,17 B8 A8 + + + + +*/ + +/* calculate rhythm */ + +INLINE void OPL_CALC_RH( FM_OPL *OPL, OPL_CH *CH, unsigned int noise ) +{ + OPL_SLOT *SLOT; + signed int out; + unsigned int env; + + + /* Bass Drum (verified on real YM3812): + - depends on the channel 6 'connect' register: + when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) + when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored + - output sample always is multiplied by 2 + */ + + OPL->phase_modulation = 0; + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + if (!SLOT->CON) + OPL->phase_modulation = SLOT->op1_out[0]; + /* else ignore output of operator 1 */ + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable) * 2; + + + /* Phase generation is based on: */ + /* HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) */ + /* SD (16) channel 7->slot 1 */ + /* TOM (14) channel 8->slot 1 */ + /* TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ + + /* Envelope generation based on: */ + /* HH channel 7->slot1 */ + /* SD channel 7->slot2 */ + /* TOM channel 8->slot1 */ + /* TOP channel 8->slot2 */ + + + /* The following formulas can be well optimized. + I leave them in direct form for now (in case I've missed something). + */ + + /* High Hat (verified on real YM3812) */ + env = volume_calc(OPL->SLOT7_1); + if( env < ENV_QUIET ) + { + + /* high hat phase generation: + phase = d0 or 234 (based on frequency only) + phase = 34 or 2d0 (based on noise) + */ + + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0xd0; */ + /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ + UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((OPL->SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((OPL->SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ + if (res2) + phase = (0x200|(0xd0>>2)); + + + /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ + /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ + if (phase&0x200) + { + if (noise) + phase = 0x200|0xd0; + } + else + /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ + /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ + { + if (noise) + phase = 0xd0>>2; + } + + OPL->output[0] += op_calc(phase<SLOT7_1->wavetable) * 2; + } + + /* Snare Drum (verified on real YM3812) */ + env = volume_calc(OPL->SLOT7_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit8 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>8)&1; + + /* when bit8 = 0 phase = 0x100; */ + /* when bit8 = 1 phase = 0x200; */ + UINT32 phase = bit8 ? 0x200 : 0x100; + + /* Noise bit XOR'es phase by 0x100 */ + /* when noisebit = 0 pass the phase from calculation above */ + /* when noisebit = 1 phase ^= 0x100; */ + /* in other words: phase ^= (noisebit<<8); */ + if (noise) + phase ^= 0x100; + + OPL->output[0] += op_calc(phase<SLOT7_2->wavetable) * 2; + } + + /* Tom Tom (verified on real YM3812) */ + env = volume_calc(OPL->SLOT8_1); + if( env < ENV_QUIET ) + OPL->output[0] += op_calc(OPL->SLOT8_1->Cnt, env, 0, OPL->SLOT8_1->wavetable) * 2; + + /* Top Cymbal (verified on real YM3812) */ + env = volume_calc(OPL->SLOT8_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((OPL->SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0x100; */ + /* when res1 = 1 phase = 0x200 | 0x100; */ + UINT32 phase = res1 ? 0x300 : 0x100; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((OPL->SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((OPL->SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | 0x100; */ + if (res2) + phase = 0x300; + + OPL->output[0] += op_calc(phase<SLOT8_2->wavetable) * 2; + } + +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 1; /* 12 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<12; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<12; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); + logerror("\n"); + #endif + } + /*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + + /*logerror("FMOPL.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ + } + + for (i=0; i>1) ]; + + /* waveform 3: _ _ _ _ */ + /* / |_/ |_/ |_/ |_*/ + /* abs(output only first quarter of the sinus waveform) */ + + if (i & (1<<(SIN_BITS-2)) ) + sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; + + /*logerror("FMOPL.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); + logerror("FMOPL.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); + logerror("FMOPL.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );*/ + } + /*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ + + +#ifdef SAVE_SAMPLE + sample[0]=fopen("sampsum.pcm","wb"); +#endif + + return 1; +} + +static void OPLCloseTable( void ) +{ +#ifdef SAVE_SAMPLE + fclose(sample[0]); +#endif +} + + + +static void OPL_initalize(FM_OPL *OPL) +{ + int i; + + /* frequency base */ + OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate : 0; +#if 0 + OPL->rate = (double)OPL->clock / 72.0; + OPL->freqbase = 1.0; +#endif + + /*logerror("freqbase=%f\n", OPL->freqbase);*/ + + /* Timer base time */ + //OPL->TimerBase = attotime_mul(ATTOTIME_IN_HZ(OPL->clock), 72); + + /* make fnumber -> increment counter table */ + for( i=0 ; i < 1024 ; i++ ) + { + /* opn phase increment counter = 20bit */ + OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("FMOPL.C: fn_tab[%4i] = %08x (dec=%8i)\n", + i, OPL->fn_tab[i]>>6, OPL->fn_tab[i]>>6 ); +#endif + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("FMOPL.C: sl_tab[%i] = %08x\n", + i, sl_tab[i] ); + } + for( i=0 ; i < 8 ; i++ ) + { + int j; + logerror("FMOPL.C: ksl_tab[oct=%2i] =",i); + for (j=0; j<16; j++) + { + logerror("%08x ", ksl_tab[i*16+j] ); + } + logerror("\n"); + } +#endif + + + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ + OPL->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + OPL->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; + + /*logerror ("OPL->lfo_am_inc = %8x ; OPL->lfo_pm_inc = %8x\n", OPL->lfo_am_inc, OPL->lfo_pm_inc);*/ + + /* Noise generator: a step takes 1 sample */ + OPL->noise_f = (1.0 / 1.0) * (1<freqbase; + + OPL->eg_timer_add = (1<freqbase; + OPL->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, OPL->eg_timer_overflow);*/ + +} + +INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) +{ + if( !SLOT->key ) + { + /* restart Phase Generator */ + SLOT->Cnt = 0; + /* phase -> Attack */ + SLOT->state = EG_ATT; + } + SLOT->key |= key_set; +} + +INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) +{ + if( SLOT->key ) + { + SLOT->key &= key_clr; + + if( !SLOT->key ) + { + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } + } +} + +/* update phase increment counter of operator (also update the EG rates if necessary) */ +INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) +{ + int ksr; + + /* (frequency) phase increment counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + } +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = mul_tab[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_type = (v&0x20); + SLOT->vib = (v&0x40); + SLOT->AMmask = (v&0x80) ? ~0 : 0; + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl & tl */ +INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ + + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; + + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->sl = sl_tab[ v>>4 ]; + + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +} + + +/* write a value v to register r on OPL chip */ +static void OPLWriteReg(FM_OPL *OPL, int r, int v) +{ + OPL_CH *CH; + int slot; + UINT32 block_fnum; + + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + + /*if (LOG_CYM_FILE && (cymfile) && (r!=0) ) + { + fputc( (unsigned char)r, cymfile ); + fputc( (unsigned char)v, cymfile ); + }*/ + + + switch(r&0xe0) + { + case 0x00: /* 00-1f:control */ + switch(r&0x1f) + { + case 0x01: /* waveform select enable */ + if(OPL->type&OPL_TYPE_WAVESEL) + { + OPL->wavesel = v&0x20; + /* do not change the waveform previously selected */ + } + break; + case 0x02: /* Timer 1 */ + OPL->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + OPL->T[1] = (256-v)*16; + break; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flag clear */ + OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */ + } + else + { /* set IRQ mask ,timer enable*/ + /*UINT8 st1 = v&1; + UINT8 st2 = (v>>1)&1;*/ + + /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ + OPL_STATUS_RESET(OPL, v & (0x78-0x08) ); + OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); + + /* timer 2 */ + /*if(OPL->st[1] != st2) + { + attotime period = st2 ? attotime_mul(OPL->TimerBase, OPL->T[1]) : attotime_zero; + OPL->st[1] = st2; + if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,1,period); + }*/ + /* timer 1 */ + /*if(OPL->st[0] != st1) + { + attotime period = st1 ? attotime_mul(OPL->TimerBase, OPL->T[0]) : attotime_zero; + OPL->st[0] = st1; + if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,0,period); + }*/ + } + break; +#if BUILD_Y8950 + case 0x06: /* Key Board OUT */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_w) + OPL->keyboardhandler_w(OPL->keyboard_param,v); + /*else + logerror("Y8950: write unmapped KEYBOARD port\n");*/ + } + break; + case 0x07: /* DELTA-T control 1 : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; +#endif + case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ + OPL->mode = v; +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v&0x0f); /* mask 4 LSBs in register 08 for DELTA-T unit */ +#endif + break; + +#if BUILD_Y8950 + case 0x09: /* START ADD */ + case 0x0a: + case 0x0b: /* STOP ADD */ + case 0x0c: + case 0x0d: /* PRESCALE */ + case 0x0e: + case 0x0f: /* ADPCM data write */ + case 0x10: /* DELTA-N */ + case 0x11: /* DELTA-N */ + case 0x12: /* ADPCM volume */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; + + case 0x15: /* DAC data high 8 bits (F7,F6...F2) */ + case 0x16: /* DAC data low 2 bits (F1, F0 in bits 7,6) */ + case 0x17: /* DAC data shift (S2,S1,S0 in bits 2,1,0) */ + /*logerror("FMOPL.C: DAC data register written, but not implemented reg=%02x val=%02x\n",r,v);*/ + break; + + case 0x18: /* I/O CTRL (Direction) */ + if(OPL->type&OPL_TYPE_IO) + OPL->portDirection = v&0x0f; + break; + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + OPL->portLatch = v; + if(OPL->porthandler_w) + OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); + } + break; +#endif + default: + /*logerror("FMOPL.C: write to unknown register: %02x\n",r);*/ + break; + } + break; + case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_mul(OPL,slot,v); + break; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ksl_tl(OPL,slot,v); + break; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ar_dr(OPL,slot,v); + break; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_sl_rr(OPL,slot,v); + break; + case 0xa0: + if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ + { + OPL->lfo_am_depth = v & 0x80; + OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; + + OPL->rhythm = v&0x3f; + + if(OPL->rhythm&0x20) + { + /* BD key on/off */ + if(v&0x10) + { + FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2); + FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2); + } + else + { + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); + } + /* HH key on/off */ + if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2); + else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); + /* SD key on/off */ + if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2); + else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); + /* TOM key on/off */ + if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2); + else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY key on/off */ + if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2); + else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); + } + else + { + /* BD key off */ + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); + /* HH key off */ + FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); + /* SD key off */ + FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); + /* TOM key off */ + FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY off */ + FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); + } + return; + } + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block = block_fnum >> 10; + + CH->block_fnum = block_fnum; + + CH->ksl_base = ksl_tab[block_fnum>>6]; + CH->fc = OPL->fn_tab[block_fnum&0x03ff] >> (7-block); + + /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ + CH->kcode = (CH->block_fnum&0x1c00)>>9; + + /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ + /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ + /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ + if (OPL->mode&0x40) + CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ + else + CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ + + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + case 0xc0: + /* FB,C */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; + CH->SLOT[SLOT1].CON = v&1; + CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &OPL->output[0] : &OPL->phase_modulation; + break; + case 0xe0: /* waveform select */ + /* simply ignore write to the waveform select register if selecting not enabled in test register */ + if(OPL->wavesel) + { + slot = slot_array[r&0x1f]; + if(slot < 0) return; + CH = &OPL->P_CH[slot/2]; + + CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; + } + break; + } +} + +/*static TIMER_CALLBACK( cymfile_callback ) +{ + if (cymfile) + { + fputc( (unsigned char)0, cymfile ); + } +}*/ + +/* lock/unlock for common table */ +#if 0 +static int OPL_LockTable(/*const device_config *device*/) +{ + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + cur_chip = NULL; + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + num_lock--; + return -1; + } + +#if 0 + if (LOG_CYM_FILE) + { + cymfile = fopen("3812_.cym","wb"); + if (cymfile) + timer_pulse ( device->machine, ATTOTIME_IN_HZ(110), NULL, 0, cymfile_callback); /*110 Hz pulse timer*/ + else + logerror("Could not create file 3812_.cym\n"); + } +#endif + + return 0; +} + +static void OPL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + + cur_chip = NULL; + OPLCloseTable(); + + /*if (cymfile) + fclose (cymfile); + cymfile = NULL;*/ +} +#endif + +static void OPLResetChip(FM_OPL *OPL) +{ + int c,s; + int i; + + OPL->eg_timer = 0; + OPL->eg_cnt = 0; + + OPL->noise_rng = 1; /* noise shift register */ + OPL->mode = 0; /* normal mode */ + OPL_STATUS_RESET(OPL,0x7f); + + /* reset with register write */ + OPLWriteReg(OPL,0x01,0); /* wavesel disable */ + OPLWriteReg(OPL,0x02,0); /* Timer1 */ + OPLWriteReg(OPL,0x03,0); /* Timer2 */ + OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + + /* reset operator parameters */ + for( c = 0 ; c < 9 ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = 0; + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = &OPL->output_deltat[0]; + DELTAT->portshift = 5; + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,0,YM_DELTAT_EMULATION_MODE_NORMAL); + } +#endif +} + + +#if 0 +static STATE_POSTLOAD( OPL_postload ) +{ + FM_OPL *OPL = (FM_OPL *)param; + int slot, ch; + + for( ch=0 ; ch < 9 ; ch++ ) + { + OPL_CH *CH = &OPL->P_CH[ch]; + + /* Look up key scale level */ + UINT32 block_fnum = CH->block_fnum; + CH->ksl_base = ksl_tab[block_fnum >> 6]; + CH->fc = OPL->fn_tab[block_fnum & 0x03ff] >> (7 - (block_fnum >> 10)); + + for( slot=0 ; slot < 2 ; slot++ ) + { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + /* Calculate key scale rate */ + SLOT->ksr = CH->kcode >> SLOT->KSR; + + /* Calculate attack, decay and release rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + + /* Calculate phase increment */ + SLOT->Incr = CH->fc * SLOT->mul; + + /* Total level */ + SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl); + + /* Connect output */ + SLOT->connect1 = SLOT->CON ? &OPL->output[0] : &OPL->phase_modulation; + } + } +#if BUILD_Y8950 + if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) + { + // We really should call the postlod function for the YM_DELTAT, but it's hard without registers + // (see the way the YM2610 does it) + //YM_DELTAT_postload(OPL->deltat, REGS); + } +#endif +} + + +static void OPLsave_state_channel(const device_config *device, OPL_CH *CH) +{ + int slot, ch; + + for( ch=0 ; ch < 9 ; ch++, CH++ ) + { + /* channel */ + state_save_register_device_item(device, ch, CH->block_fnum); + state_save_register_device_item(device, ch, CH->kcode); + /* slots */ + for( slot=0 ; slot < 2 ; slot++ ) + { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + state_save_register_device_item(device, ch * 2 + slot, SLOT->ar); + state_save_register_device_item(device, ch * 2 + slot, SLOT->dr); + state_save_register_device_item(device, ch * 2 + slot, SLOT->rr); + state_save_register_device_item(device, ch * 2 + slot, SLOT->KSR); + state_save_register_device_item(device, ch * 2 + slot, SLOT->ksl); + state_save_register_device_item(device, ch * 2 + slot, SLOT->mul); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->Cnt); + state_save_register_device_item(device, ch * 2 + slot, SLOT->FB); + state_save_register_device_item_array(device, ch * 2 + slot, SLOT->op1_out); + state_save_register_device_item(device, ch * 2 + slot, SLOT->CON); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->eg_type); + state_save_register_device_item(device, ch * 2 + slot, SLOT->state); + state_save_register_device_item(device, ch * 2 + slot, SLOT->TL); + state_save_register_device_item(device, ch * 2 + slot, SLOT->volume); + state_save_register_device_item(device, ch * 2 + slot, SLOT->sl); + state_save_register_device_item(device, ch * 2 + slot, SLOT->key); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->AMmask); + state_save_register_device_item(device, ch * 2 + slot, SLOT->vib); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->wavetable); + } + } +} + + +/* Register savestate for a virtual YM3812/YM3526Y8950 */ + +static void OPL_save_state(FM_OPL *OPL, const device_config *device) +{ + OPLsave_state_channel(device, OPL->P_CH); + + state_save_register_device_item(device, 0, OPL->eg_cnt); + state_save_register_device_item(device, 0, OPL->eg_timer); + + state_save_register_device_item(device, 0, OPL->rhythm); + + state_save_register_device_item(device, 0, OPL->lfo_am_depth); + state_save_register_device_item(device, 0, OPL->lfo_pm_depth_range); + state_save_register_device_item(device, 0, OPL->lfo_am_cnt); + state_save_register_device_item(device, 0, OPL->lfo_pm_cnt); + + state_save_register_device_item(device, 0, OPL->noise_rng); + state_save_register_device_item(device, 0, OPL->noise_p); + + if( OPL->type & OPL_TYPE_WAVESEL ) + { + state_save_register_device_item(device, 0, OPL->wavesel); + } + + state_save_register_device_item_array(device, 0, OPL->T); + state_save_register_device_item_array(device, 0, OPL->st); + +#if BUILD_Y8950 + if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) + { + YM_DELTAT_savestate(device, OPL->deltat); + } + + if ( OPL->type & OPL_TYPE_IO ) + { + state_save_register_device_item(device, 0, OPL->portDirection); + state_save_register_device_item(device, 0, OPL->portLatch); + } +#endif + + state_save_register_device_item(device, 0, OPL->address); + state_save_register_device_item(device, 0, OPL->status); + state_save_register_device_item(device, 0, OPL->statusmask); + state_save_register_device_item(device, 0, OPL->mode); + + state_save_register_postload(device->machine, OPL_postload, OPL); +} +#endif + + +/* Create one of virtual YM3812/YM3526/Y8950 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static FM_OPL *OPLCreate(UINT32 clock, UINT32 rate, int type) +{ + char *ptr; + FM_OPL *OPL; + int state_size; + + //if (OPL_LockTable(device) == -1) return NULL; + init_tables(); + + /* calculate OPL state size */ + state_size = sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); +#endif + + /* allocate memory block */ + ptr = (char *)malloc(state_size); + + if (ptr==NULL) + return 0; + + /* clear */ + memset(ptr,0,state_size); + + OPL = (FM_OPL *)ptr; + + ptr += sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) + { + OPL->deltat = (YM_DELTAT *)ptr; + } + ptr += sizeof(YM_DELTAT); +#endif + + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + + /* init global tables */ + OPL_initalize(OPL); + + return OPL; +} + +/* Destroy one of virtual YM3812 */ +static void OPLDestroy(FM_OPL *OPL) +{ + //OPL_UnLockTable(); + free(OPL); +} + +/* Optional handlers */ + +/*static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER timer_handler,void *param) +{ + OPL->timer_handler = timer_handler; + OPL->TimerParam = param; +}*/ +static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,void *param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} + +static int OPLWrite(FM_OPL *OPL,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + OPL->address = v & 0xff; + } + else + { /* data port */ + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + OPLWriteReg(OPL,OPL->address,v); + } + return OPL->status>>7; +} + +static unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { + /* status port */ + + #if BUILD_Y8950 + + if(OPL->type&OPL_TYPE_ADPCM) /* Y8950 */ + { + return (OPL->status & (OPL->statusmask|0x80)) | (OPL->deltat->PCM_BSY&1); + } + + #endif + + /* OPL and OPL2 */ + return OPL->status & (OPL->statusmask|0x80); + } + +#if BUILD_Y8950 + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); + /*else + logerror("Y8950: read unmapped KEYBOARD port\n");*/ + } + return 0; + + case 0x0f: /* ADPCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + UINT8 val; + + val = YM_DELTAT_ADPCM_Read(OPL->deltat); + /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/ + return val; + } + return 0; + + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); + /*else + logerror("Y8950:read unmapped I/O port\n");*/ + } + return 0; + case 0x1a: /* PCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + /*logerror("Y8950 A/D convertion is accessed but not implemented !\n");*/ + return 0x80; /* 2's complement PCM data - result from A/D convertion */ + } + return 0; + } +#endif + + return 0xff; +} + +/* CSM Key Controll */ +INLINE void CSMKeyControll(OPL_CH *CH) +{ + FM_KEYON (&CH->SLOT[SLOT1], 4); + FM_KEYON (&CH->SLOT[SLOT2], 4); + + /* The key off should happen exactly one sample later - not implemented correctly yet */ + + FM_KEYOFF(&CH->SLOT[SLOT1], ~4); + FM_KEYOFF(&CH->SLOT[SLOT2], ~4); +} + + +static int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + else + { /* Timer A */ + OPL_STATUS_SET(OPL,0x40); + /* CSM mode key,TL controll */ + if( OPL->mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + for(ch=0; ch<9; ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ + //if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,c,attotime_mul(OPL->TimerBase, OPL->T[c])); + return OPL->status>>7; +} + + +#define MAX_OPL_CHIPS 2 + + +#if (BUILD_YM3812) + +void * ym3812_init(UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *YM3812 = OPLCreate(clock,rate,OPL_TYPE_YM3812); + if (YM3812) + { + //OPL_save_state(YM3812); + ym3812_reset_chip(YM3812); + } + return YM3812; +} + +void ym3812_shutdown(void *chip) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + + /* emulator shutdown */ + OPLDestroy(YM3812); +} +void ym3812_reset_chip(void *chip) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLResetChip(YM3812); +} + +int ym3812_write(void *chip, int a, int v) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + return OPLWrite(YM3812, a, v); +} + +unsigned char ym3812_read(void *chip, int a) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + /* YM3812 always returns bit2 and bit1 in HIGH state */ + return OPLRead(YM3812, a) | 0x06 ; +} +int ym3812_timer_over(void *chip, int c) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + return OPLTimerOver(YM3812, c); +} + +/*void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetTimerHandler(YM3812, timer_handler, param); +}*/ +void ym3812_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetIRQHandler(YM3812, IRQHandler, param); +} +void ym3812_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetUpdateHandler(YM3812, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3812's +** +** 'which' is the virtual YM3812 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + /* rhythm slots */ + OPL->SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + OPL->SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + OPL->SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + OPL->SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3812 */ + + + +#if (BUILD_YM3526) + +void *ym3526_init(UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *YM3526 = OPLCreate(clock,rate,OPL_TYPE_YM3526); + if (YM3526) + { + /*OPL_save_state(YM3526);*/ + ym3526_reset_chip(YM3526); + } + return YM3526; +} + +void ym3526_shutdown(void *chip) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + /* emulator shutdown */ + OPLDestroy(YM3526); +} +void ym3526_reset_chip(void *chip) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLResetChip(YM3526); +} + +int ym3526_write(void *chip, int a, int v) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + return OPLWrite(YM3526, a, v); +} + +unsigned char ym3526_read(void *chip, int a) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + /* YM3526 always returns bit2 and bit1 in HIGH state */ + return OPLRead(YM3526, a) | 0x06 ; +} +int ym3526_timer_over(void *chip, int c) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + return OPLTimerOver(YM3526, c); +} + +/*void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetTimerHandler(YM3526, timer_handler, param); +}*/ +void ym3526_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetIRQHandler(YM3526, IRQHandler, param); +} +void ym3526_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetUpdateHandler(YM3526, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + /* rhythm slots */ + OPL->SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + OPL->SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + OPL->SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + OPL->SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3526 */ + + + + +#if BUILD_Y8950 + +static void Y8950_deltat_status_set(void *chip, UINT8 changebits) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPL_STATUS_SET(Y8950, changebits); +} +static void Y8950_deltat_status_reset(void *chip, UINT8 changebits) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPL_STATUS_RESET(Y8950, changebits); +} + +void *y8950_init(UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *Y8950 = OPLCreate(clock,rate,OPL_TYPE_Y8950); + if (Y8950) + { + Y8950->deltat->status_set_handler = Y8950_deltat_status_set; + Y8950->deltat->status_reset_handler = Y8950_deltat_status_reset; + Y8950->deltat->status_change_which_chip = Y8950; + Y8950->deltat->status_change_EOS_bit = 0x10; /* status flag: set bit4 on End Of Sample */ + Y8950->deltat->status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY (End Of: ADPCM analysis/synthesis, memory reading/writing) */ + + /*Y8950->deltat->write_time = 10.0 / clock;*/ /* a single byte write takes 10 cycles of main clock */ + /*Y8950->deltat->read_time = 8.0 / clock;*/ /* a single byte read takes 8 cycles of main clock */ + /* reset */ + /*OPL_save_state(Y8950);*/ + y8950_reset_chip(Y8950); + } + + return Y8950; +} + +void y8950_shutdown(void *chip) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + /* emulator shutdown */ + OPLDestroy(Y8950); +} +void y8950_reset_chip(void *chip) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLResetChip(Y8950); +} + +int y8950_write(void *chip, int a, int v) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLWrite(Y8950, a, v); +} + +unsigned char y8950_read(void *chip, int a) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLRead(Y8950, a); +} +int y8950_timer_over(void *chip, int c) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLTimerOver(Y8950, c); +} + +/*void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetTimerHandler(Y8950, timer_handler, param); +}*/ +void y8950_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetIRQHandler(Y8950, IRQHandler, param); +} +void y8950_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetUpdateHandler(Y8950, UpdateHandler, param); +} + +void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->deltat->memory = (UINT8 *)(deltat_mem_ptr); + OPL->deltat->memory_size = deltat_mem_size; +} + +/* +** Generate samples for one of the Y8950's +** +** 'which' is the virtual Y8950 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + int i; + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + YM_DELTAT *DELTAT = OPL->deltat; + OPLSAMPLE *buf = buffer; + + /* rhythm slots */ + OPL->SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + OPL->SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + OPL->SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + OPL->SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + OPL->output_deltat[0] = 0; + + advance_lfo(OPL); + + /* deltaT ADPCM */ + if( DELTAT->portstate&0x80 ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0] + (OPL->output_deltat[0]>>11); + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} + +void y8950_set_port_handler(void *chip,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,void * param) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->porthandler_w = PortHandler_w; + OPL->porthandler_r = PortHandler_r; + OPL->port_param = param; +} + +void y8950_set_keyboard_handler(void *chip,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,void * param) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->keyboardhandler_w = KeyboardHandler_w; + OPL->keyboardhandler_r = KeyboardHandler_r; + OPL->keyboard_param = param; +} + +#endif + diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/fmopl.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/fmopl.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/fmopl.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/fmopl.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,116 +1,116 @@ -#pragma once - -#ifndef __FMOPL_H__ -#define __FMOPL_H__ - -/* --- select emulation chips --- */ -#define BUILD_YM3812 (1) -#define BUILD_YM3526 (1) -#define BUILD_Y8950 (1) - -/* select output bits size of output : 8 or 16 */ -#define OPL_SAMPLE_BITS 16 - -/* compiler dependence */ -#ifndef __OSDCOMM_H__ -#define __OSDCOMM_H__ -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ - -typedef INT32 stream_sample_t; - -#endif /* __OSDCOMM_H__ */ - -typedef stream_sample_t OPLSAMPLE; -/* -#if (OPL_SAMPLE_BITS==16) -typedef INT16 OPLSAMPLE; -#endif -#if (OPL_SAMPLE_BITS==8) -typedef INT8 OPLSAMPLE; -#endif -*/ - -//typedef void (*OPL_TIMERHANDLER)(void *param,int timer,attotime period); -typedef void (*OPL_IRQHANDLER)(void *param,int irq); -typedef void (*OPL_UPDATEHANDLER)(void *param,int min_interval_us); -typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data); -typedef unsigned char (*OPL_PORTHANDLER_R)(void *param); - - -#if BUILD_YM3812 - -void *ym3812_init(UINT32 clock, UINT32 rate); -void ym3812_shutdown(void *chip); -void ym3812_reset_chip(void *chip); -int ym3812_write(void *chip, int a, int v); -unsigned char ym3812_read(void *chip, int a); -int ym3812_timer_over(void *chip, int c); -void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length); - -//void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); -void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); -void ym3812_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); - -#endif /* BUILD_YM3812 */ - - -#if BUILD_YM3526 - -/* -** Initialize YM3526 emulator(s). -** -** 'num' is the number of virtual YM3526's to allocate -** 'clock' is the chip clock in Hz -** 'rate' is sampling rate -*/ -void *ym3526_init(UINT32 clock, UINT32 rate); -/* shutdown the YM3526 emulators*/ -void ym3526_shutdown(void *chip); -void ym3526_reset_chip(void *chip); -int ym3526_write(void *chip, int a, int v); -unsigned char ym3526_read(void *chip, int a); -int ym3526_timer_over(void *chip, int c); -/* -** Generate samples for one of the YM3526's -** -** 'which' is the virtual YM3526 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length); - -//void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); -void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); -void ym3526_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); - -#endif /* BUILD_YM3526 */ - - -#if BUILD_Y8950 - -/* Y8950 port handlers */ -void y8950_set_port_handler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param); -void y8950_set_keyboard_handler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param); -void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ); - -void * y8950_init(UINT32 clock, UINT32 rate); -void y8950_shutdown(void *chip); -void y8950_reset_chip(void *chip); -int y8950_write(void *chip, int a, int v); -unsigned char y8950_read (void *chip, int a); -int y8950_timer_over(void *chip, int c); -void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length); - -//void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); -void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); -void y8950_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); - -#endif /* BUILD_Y8950 */ - - -#endif /* __FMOPL_H__ */ +#pragma once + +#ifndef __FMOPL_H__ +#define __FMOPL_H__ + +/* --- select emulation chips --- */ +#define BUILD_YM3812 (1) +#define BUILD_YM3526 (1) +#define BUILD_Y8950 (1) + +/* select output bits size of output : 8 or 16 */ +#define OPL_SAMPLE_BITS 16 + +/* compiler dependence */ +#ifndef __OSDCOMM_H__ +#define __OSDCOMM_H__ +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ + +typedef INT32 stream_sample_t; + +#endif /* __OSDCOMM_H__ */ + +typedef stream_sample_t OPLSAMPLE; +/* +#if (OPL_SAMPLE_BITS==16) +typedef INT16 OPLSAMPLE; +#endif +#if (OPL_SAMPLE_BITS==8) +typedef INT8 OPLSAMPLE; +#endif +*/ + +//typedef void (*OPL_TIMERHANDLER)(void *param,int timer,attotime period); +typedef void (*OPL_IRQHANDLER)(void *param,int irq); +typedef void (*OPL_UPDATEHANDLER)(void *param,int min_interval_us); +typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data); +typedef unsigned char (*OPL_PORTHANDLER_R)(void *param); + + +#if BUILD_YM3812 + +void *ym3812_init(UINT32 clock, UINT32 rate); +void ym3812_shutdown(void *chip); +void ym3812_reset_chip(void *chip); +int ym3812_write(void *chip, int a, int v); +unsigned char ym3812_read(void *chip, int a); +int ym3812_timer_over(void *chip, int c); +void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length); + +//void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void ym3812_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_YM3812 */ + + +#if BUILD_YM3526 + +/* +** Initialize YM3526 emulator(s). +** +** 'num' is the number of virtual YM3526's to allocate +** 'clock' is the chip clock in Hz +** 'rate' is sampling rate +*/ +void *ym3526_init(UINT32 clock, UINT32 rate); +/* shutdown the YM3526 emulators*/ +void ym3526_shutdown(void *chip); +void ym3526_reset_chip(void *chip); +int ym3526_write(void *chip, int a, int v); +unsigned char ym3526_read(void *chip, int a); +int ym3526_timer_over(void *chip, int c); +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length); + +//void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void ym3526_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_YM3526 */ + + +#if BUILD_Y8950 + +/* Y8950 port handlers */ +void y8950_set_port_handler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param); +void y8950_set_keyboard_handler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param); +void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ); + +void * y8950_init(UINT32 clock, UINT32 rate); +void y8950_shutdown(void *chip); +void y8950_reset_chip(void *chip); +int y8950_write(void *chip, int a, int v); +unsigned char y8950_read (void *chip, int a); +int y8950_timer_over(void *chip, int c); +void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length); + +//void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void y8950_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_Y8950 */ + + +#endif /* __FMOPL_H__ */ diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gb_Apu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gb_Apu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gb_Apu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gb_Apu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,414 +1,407 @@ -// Gb_Snd_Emu $vers. http://www.slack.net/~ant/ - -#include "Gb_Apu.h" - -//#include "gb_apu_logger.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const vol_reg = 0xFF24; -int const stereo_reg = 0xFF25; -int const status_reg = 0xFF26; -int const wave_ram = 0xFF30; - -int const power_mask = 0x80; - -void Gb_Apu::treble_eq( blip_eq_t const& eq ) -{ - norm_synth.treble_eq( eq ); - fast_synth.treble_eq( eq ); -} - -inline int Gb_Apu::calc_output( int osc ) const -{ - int bits = regs [stereo_reg - io_addr] >> osc; - return (bits >> 3 & 2) | (bits & 1); -} - -void Gb_Apu::set_output( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL) - require( !center || (center && !left && !right) || (center && left && right) ); - require( (unsigned) i < osc_count ); // fails if you pass invalid osc index - - if ( !center || !left || !right ) - { - left = center; - right = center; - } - - Gb_Osc& o = *oscs [i]; - o.outputs [1] = right; - o.outputs [2] = left; - o.outputs [3] = center; - o.output = o.outputs [calc_output( i )]; -} - -void Gb_Apu::synth_volume( int iv ) -{ - double v = volume_ * 0.60 / osc_count / 15 /*steps*/ / 8 /*master vol range*/ * iv; - norm_synth.volume( v ); - fast_synth.volume( v ); -} - -void Gb_Apu::apply_volume() -{ - // TODO: Doesn't handle differing left and right volumes (panning). - // Not worth the complexity. - int data = regs [vol_reg - io_addr]; - int left = data >> 4 & 7; - int right = data & 7; - //if ( data & 0x88 ) dprintf( "Vin: %02X\n", data & 0x88 ); - //if ( left != right ) dprintf( "l: %d r: %d\n", left, right ); - synth_volume( max( left, right ) + 1 ); -} - -void Gb_Apu::volume( double v ) -{ - if ( volume_ != v ) - { - volume_ = v; - apply_volume(); - } -} - -void Gb_Apu::reset_regs() -{ - for ( int i = 0; i < 0x20; i++ ) - regs [i] = 0; - - square1.reset(); - square2.reset(); - wave .reset(); - noise .reset(); - - apply_volume(); -} - -void Gb_Apu::reset_lengths() -{ - square1.length_ctr = 64; - square2.length_ctr = 64; - wave .length_ctr = 256; - noise .length_ctr = 64; -} - -void Gb_Apu::reduce_clicks( bool reduce ) -{ - reduce_clicks_ = reduce; - - // Click reduction makes DAC off generate same output as volume 0 - int dac_off_amp = 0; - if ( reduce && wave.mode != mode_agb ) // AGB already eliminates clicks - dac_off_amp = -Gb_Osc::dac_bias; - - for ( int i = 0; i < osc_count; i++ ) - oscs [i]->dac_off_amp = dac_off_amp; - - // AGB always eliminates clicks on wave channel using same method - if ( wave.mode == mode_agb ) - wave.dac_off_amp = -Gb_Osc::dac_bias; -} - -void Gb_Apu::reset( mode_t mode, bool agb_wave ) -{ - // Hardware mode - if ( agb_wave ) - mode = mode_agb; // using AGB wave features implies AGB hardware - wave.agb_mask = agb_wave ? 0xFF : 0; - for ( int i = 0; i < osc_count; i++ ) - oscs [i]->mode = mode; - reduce_clicks( reduce_clicks_ ); - - // Reset state - frame_time = 0; - last_time = 0; - frame_phase = 0; - - reset_regs(); - reset_lengths(); - - // Load initial wave RAM - static byte const initial_wave [2] [16] = { - {0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C,0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA}, - {0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF}, - }; - for ( int b = 2; --b >= 0; ) - { - // Init both banks (does nothing if not in AGB mode) - // TODO: verify that this works - write_register( 0, 0xFF1A, b * 0x40 ); - for ( unsigned i = 0; i < sizeof initial_wave [0]; i++ ) - write_register( 0, i + wave_ram, initial_wave [(mode != mode_dmg)] [i] ); - } -} - -void Gb_Apu::set_tempo( double t ) -{ - frame_period = 4194304 / 512; // 512 Hz - if ( t != 1.0 ) - frame_period = t ? blip_time_t (frame_period / t) : blip_time_t(0); -} - -void Gb_Apu::set_hacks( unsigned int mask ) -{ - wave.set_volume_hack((mask & 1) != 0); - noise.set_volume_hack((mask & 2) == 0); -} - -Gb_Apu::Gb_Apu() -{ - wave.wave_ram = ®s [wave_ram - io_addr]; - - oscs [0] = &square1; - oscs [1] = &square2; - oscs [2] = &wave; - oscs [3] = &noise; - - for ( int i = osc_count; --i >= 0; ) - { - Gb_Osc& o = *oscs [i]; - o.regs = ®s [i * 5]; - o.output = NULL; - o.outputs [0] = NULL; - o.outputs [1] = NULL; - o.outputs [2] = NULL; - o.outputs [3] = NULL; - o.norm_synth = &norm_synth; - o.fast_synth = &fast_synth; - } - - reduce_clicks_ = false; - set_tempo( 1.0 ); - volume_ = 1.0; - reset(); - set_hacks(4); -} - -void Gb_Apu::run_until_( blip_time_t end_time ) -{ - if ( !frame_period ) - frame_time += end_time - last_time; - - while ( true ) - { - // run oscillators - blip_time_t time = end_time; - if ( time > frame_time ) - time = frame_time; - - square1.run( last_time, time ); - square2.run( last_time, time ); - wave .run( last_time, time ); - noise .run( last_time, time ); - last_time = time; - - if ( time == end_time ) - break; - - // run frame sequencer - assert( frame_period ); - frame_time += frame_period * Gb_Osc::clk_mul; - switch ( frame_phase++ ) - { - case 2: - case 6: - // 128 Hz - square1.clock_sweep(); - case 0: - case 4: - // 256 Hz - square1.clock_length(); - square2.clock_length(); - wave .clock_length(); - noise .clock_length(); - break; - - case 7: - // 64 Hz - frame_phase = 0; - square1.clock_envelope(); - square2.clock_envelope(); - noise .clock_envelope(); - } - } -} - -inline void Gb_Apu::run_until( blip_time_t time ) -{ - require( time >= last_time ); // end_time must not be before previous time - if ( time > last_time ) - run_until_( time ); -} - -void Gb_Apu::end_frame( blip_time_t end_time ) -{ - #ifdef LOG_FRAME - LOG_FRAME( end_time ); - #endif - - if ( end_time > last_time ) - run_until( end_time ); - - frame_time -= end_time; - assert( frame_time >= 0 ); - - last_time -= end_time; - assert( last_time >= 0 ); -} - -void Gb_Apu::silence_osc( Gb_Osc& o ) -{ - int delta = -o.last_amp; - if ( reduce_clicks_ ) - delta += o.dac_off_amp; - - if ( delta ) - { - o.last_amp = o.dac_off_amp; - if ( o.output ) - { - o.output->set_modified(); - fast_synth.offset( last_time, delta, o.output ); - } - } -} - -void Gb_Apu::apply_stereo() -{ - for ( int i = osc_count; --i >= 0; ) - { - Gb_Osc& o = *oscs [i]; - Blip_Buffer* out = o.outputs [calc_output( i )]; - if ( o.output != out ) - { - silence_osc( o ); - o.output = out; - } - } -} - -void Gb_Apu::write_register( blip_time_t time, int addr, int data ) -{ - require( (unsigned) data < 0x100 ); - - int reg = addr - io_addr; - if ( (unsigned) reg >= io_size ) - { - require( false ); - return; - } - - #ifdef LOG_WRITE - LOG_WRITE( time, addr, data ); - #endif - - if ( addr < status_reg && !(regs [status_reg - io_addr] & power_mask) ) - { - // Power is off - - // length counters can only be written in DMG mode - if ( wave.mode != mode_dmg || (reg != 1 && reg != 5+1 && reg != 10+1 && reg != 15+1) ) - return; - - if ( reg < 10 ) - data &= 0x3F; // clear square duty - } - - run_until( time ); - - if ( addr >= wave_ram ) - { - wave.write( addr, data ); - } - else - { - int old_data = regs [reg]; - regs [reg] = data; - - if ( addr < vol_reg ) - { - // Oscillator - write_osc( reg, old_data, data ); - } - else if ( addr == vol_reg && data != old_data ) - { - // Master volume - for ( int i = osc_count; --i >= 0; ) - silence_osc( *oscs [i] ); - - apply_volume(); - } - else if ( addr == stereo_reg ) - { - // Stereo panning - apply_stereo(); - } - else if ( addr == status_reg && (data ^ old_data) & power_mask ) - { - // Power control - frame_phase = 0; - for ( int i = osc_count; --i >= 0; ) - silence_osc( *oscs [i] ); - - reset_regs(); - if ( wave.mode != mode_dmg ) - reset_lengths(); - - regs [status_reg - io_addr] = data; - } - } -} - -int Gb_Apu::read_register( blip_time_t time, int addr ) -{ - if ( addr >= status_reg ) - run_until( time ); - - int reg = addr - io_addr; - if ( (unsigned) reg >= io_size ) - { - require( false ); - return 0; - } - - if ( addr >= wave_ram ) - return wave.read( addr ); - - // Value read back has some bits always set - static byte const masks [] = { - 0x80,0x3F,0x00,0xFF,0xBF, - 0xFF,0x3F,0x00,0xFF,0xBF, - 0x7F,0xFF,0x9F,0xFF,0xBF, - 0xFF,0xFF,0x00,0x00,0xBF, - 0x00,0x00,0x70, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF - }; - int mask = masks [reg]; - if ( wave.agb_mask && (reg == 10 || reg == 12) ) - mask = 0x1F; // extra implemented bits in wave regs on AGB - int data = regs [reg] | mask; - - // Status register - if ( addr == status_reg ) - { - data &= 0xF0; - data |= (int) square1.enabled << 0; - data |= (int) square2.enabled << 1; - data |= (int) wave .enabled << 2; - data |= (int) noise .enabled << 3; - } - - return data; -} +// Gb_Snd_Emu $vers. http://www.slack.net/~ant/ + +#include "Gb_Apu.h" + +//#include "gb_apu_logger.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const vol_reg = 0xFF24; +int const stereo_reg = 0xFF25; +int const status_reg = 0xFF26; +int const wave_ram = 0xFF30; + +int const power_mask = 0x80; + +void Gb_Apu::treble_eq( blip_eq_t const& eq ) +{ + norm_synth.treble_eq( eq ); + fast_synth.treble_eq( eq ); +} + +inline int Gb_Apu::calc_output( int osc ) const +{ + int bits = regs [stereo_reg - io_addr] >> osc; + return (bits >> 3 & 2) | (bits & 1); +} + +void Gb_Apu::set_output( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) +{ + // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL) + require( !center || (center && !left && !right) || (center && left && right) ); + require( (unsigned) i < osc_count ); // fails if you pass invalid osc index + + if ( !center || !left || !right ) + { + left = center; + right = center; + } + + Gb_Osc& o = *oscs [i]; + o.outputs [1] = right; + o.outputs [2] = left; + o.outputs [3] = center; + o.output = o.outputs [calc_output( i )]; +} + +void Gb_Apu::synth_volume( int iv ) +{ + double v = volume_ * 0.60 / osc_count / 15 /*steps*/ / 8 /*master vol range*/ * iv; + norm_synth.volume( v ); + fast_synth.volume( v ); +} + +void Gb_Apu::apply_volume() +{ + // TODO: Doesn't handle differing left and right volumes (panning). + // Not worth the complexity. + int data = regs [vol_reg - io_addr]; + int left = data >> 4 & 7; + int right = data & 7; + //if ( data & 0x88 ) dprintf( "Vin: %02X\n", data & 0x88 ); + //if ( left != right ) dprintf( "l: %d r: %d\n", left, right ); + synth_volume( max( left, right ) + 1 ); +} + +void Gb_Apu::volume( double v ) +{ + if ( volume_ != v ) + { + volume_ = v; + apply_volume(); + } +} + +void Gb_Apu::reset_regs() +{ + for ( int i = 0; i < 0x20; i++ ) + regs [i] = 0; + + square1.reset(); + square2.reset(); + wave .reset(); + noise .reset(); + + apply_volume(); +} + +void Gb_Apu::reset_lengths() +{ + square1.length_ctr = 64; + square2.length_ctr = 64; + wave .length_ctr = 256; + noise .length_ctr = 64; +} + +void Gb_Apu::reduce_clicks( bool reduce ) +{ + reduce_clicks_ = reduce; + + // Click reduction makes DAC off generate same output as volume 0 + int dac_off_amp = 0; + if ( reduce && wave.mode != mode_agb ) // AGB already eliminates clicks + dac_off_amp = -Gb_Osc::dac_bias; + + for ( int i = 0; i < osc_count; i++ ) + oscs [i]->dac_off_amp = dac_off_amp; + + // AGB always eliminates clicks on wave channel using same method + if ( wave.mode == mode_agb ) + wave.dac_off_amp = -Gb_Osc::dac_bias; +} + +void Gb_Apu::reset( mode_t mode, bool agb_wave ) +{ + // Hardware mode + if ( agb_wave ) + mode = mode_agb; // using AGB wave features implies AGB hardware + wave.agb_mask = agb_wave ? 0xFF : 0; + for ( int i = 0; i < osc_count; i++ ) + oscs [i]->mode = mode; + reduce_clicks( reduce_clicks_ ); + + // Reset state + frame_time = 0; + last_time = 0; + frame_phase = 0; + + reset_regs(); + reset_lengths(); + + // Load initial wave RAM + static byte const initial_wave [2] [16] = { + {0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C,0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA}, + {0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF}, + }; + for ( int b = 2; --b >= 0; ) + { + // Init both banks (does nothing if not in AGB mode) + // TODO: verify that this works + write_register( 0, 0xFF1A, b * 0x40 ); + for ( unsigned i = 0; i < sizeof initial_wave [0]; i++ ) + write_register( 0, i + wave_ram, initial_wave [(mode != mode_dmg)] [i] ); + } +} + +void Gb_Apu::set_tempo( double t ) +{ + frame_period = 4194304 / 512; // 512 Hz + if ( t != 1.0 ) + frame_period = t ? blip_time_t (frame_period / t) : blip_time_t(0); +} + +Gb_Apu::Gb_Apu() +{ + wave.wave_ram = ®s [wave_ram - io_addr]; + + oscs [0] = &square1; + oscs [1] = &square2; + oscs [2] = &wave; + oscs [3] = &noise; + + for ( int i = osc_count; --i >= 0; ) + { + Gb_Osc& o = *oscs [i]; + o.regs = ®s [i * 5]; + o.output = NULL; + o.outputs [0] = NULL; + o.outputs [1] = NULL; + o.outputs [2] = NULL; + o.outputs [3] = NULL; + o.norm_synth = &norm_synth; + o.fast_synth = &fast_synth; + } + + reduce_clicks_ = false; + set_tempo( 1.0 ); + volume_ = 1.0; + reset(); +} + +void Gb_Apu::run_until_( blip_time_t end_time ) +{ + if ( !frame_period ) + frame_time += end_time - last_time; + + while ( true ) + { + // run oscillators + blip_time_t time = end_time; + if ( time > frame_time ) + time = frame_time; + + square1.run( last_time, time ); + square2.run( last_time, time ); + wave .run( last_time, time ); + noise .run( last_time, time ); + last_time = time; + + if ( time == end_time ) + break; + + // run frame sequencer + assert( frame_period ); + frame_time += frame_period * Gb_Osc::clk_mul; + switch ( frame_phase++ ) + { + case 2: + case 6: + // 128 Hz + square1.clock_sweep(); + case 0: + case 4: + // 256 Hz + square1.clock_length(); + square2.clock_length(); + wave .clock_length(); + noise .clock_length(); + break; + + case 7: + // 64 Hz + frame_phase = 0; + square1.clock_envelope(); + square2.clock_envelope(); + noise .clock_envelope(); + } + } +} + +inline void Gb_Apu::run_until( blip_time_t time ) +{ + require( time >= last_time ); // end_time must not be before previous time + if ( time > last_time ) + run_until_( time ); +} + +void Gb_Apu::end_frame( blip_time_t end_time ) +{ + #ifdef LOG_FRAME + LOG_FRAME( end_time ); + #endif + + if ( end_time > last_time ) + run_until( end_time ); + + frame_time -= end_time; + assert( frame_time >= 0 ); + + last_time -= end_time; + assert( last_time >= 0 ); +} + +void Gb_Apu::silence_osc( Gb_Osc& o ) +{ + int delta = -o.last_amp; + if ( reduce_clicks_ ) + delta += o.dac_off_amp; + + if ( delta ) + { + o.last_amp = o.dac_off_amp; + if ( o.output ) + { + o.output->set_modified(); + fast_synth.offset( last_time, delta, o.output ); + } + } +} + +void Gb_Apu::apply_stereo() +{ + for ( int i = osc_count; --i >= 0; ) + { + Gb_Osc& o = *oscs [i]; + Blip_Buffer* out = o.outputs [calc_output( i )]; + if ( o.output != out ) + { + silence_osc( o ); + o.output = out; + } + } +} + +void Gb_Apu::write_register( blip_time_t time, int addr, int data ) +{ + require( (unsigned) data < 0x100 ); + + int reg = addr - io_addr; + if ( (unsigned) reg >= io_size ) + { + require( false ); + return; + } + + #ifdef LOG_WRITE + LOG_WRITE( time, addr, data ); + #endif + + if ( addr < status_reg && !(regs [status_reg - io_addr] & power_mask) ) + { + // Power is off + + // length counters can only be written in DMG mode + if ( wave.mode != mode_dmg || (reg != 1 && reg != 5+1 && reg != 10+1 && reg != 15+1) ) + return; + + if ( reg < 10 ) + data &= 0x3F; // clear square duty + } + + run_until( time ); + + if ( addr >= wave_ram ) + { + wave.write( addr, data ); + } + else + { + int old_data = regs [reg]; + regs [reg] = data; + + if ( addr < vol_reg ) + { + // Oscillator + write_osc( reg, old_data, data ); + } + else if ( addr == vol_reg && data != old_data ) + { + // Master volume + for ( int i = osc_count; --i >= 0; ) + silence_osc( *oscs [i] ); + + apply_volume(); + } + else if ( addr == stereo_reg ) + { + // Stereo panning + apply_stereo(); + } + else if ( addr == status_reg && (data ^ old_data) & power_mask ) + { + // Power control + frame_phase = 0; + for ( int i = osc_count; --i >= 0; ) + silence_osc( *oscs [i] ); + + reset_regs(); + if ( wave.mode != mode_dmg ) + reset_lengths(); + + regs [status_reg - io_addr] = data; + } + } +} + +int Gb_Apu::read_register( blip_time_t time, int addr ) +{ + if ( addr >= status_reg ) + run_until( time ); + + int reg = addr - io_addr; + if ( (unsigned) reg >= io_size ) + { + require( false ); + return 0; + } + + if ( addr >= wave_ram ) + return wave.read( addr ); + + // Value read back has some bits always set + static byte const masks [] = { + 0x80,0x3F,0x00,0xFF,0xBF, + 0xFF,0x3F,0x00,0xFF,0xBF, + 0x7F,0xFF,0x9F,0xFF,0xBF, + 0xFF,0xFF,0x00,0x00,0xBF, + 0x00,0x00,0x70, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF + }; + int mask = masks [reg]; + if ( wave.agb_mask && (reg == 10 || reg == 12) ) + mask = 0x1F; // extra implemented bits in wave regs on AGB + int data = regs [reg] | mask; + + // Status register + if ( addr == status_reg ) + { + data &= 0xF0; + data |= (int) square1.enabled << 0; + data |= (int) square2.enabled << 1; + data |= (int) wave .enabled << 2; + data |= (int) noise .enabled << 3; + } + + return data; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gb_Apu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gb_Apu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gb_Apu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gb_Apu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,198 +1,193 @@ -// Nintendo Game Boy sound hardware emulator with save state support - -// Gb_Snd_Emu $vers -#ifndef GB_APU_H -#define GB_APU_H - -#include "Gb_Oscs.h" - -struct gb_apu_state_t; - -class Gb_Apu { -public: -// Basics - - // Sets buffer(s) to generate sound into, or NULL to mute. If only center is not NULL, - // output is mono. - void set_output( Blip_Buffer* center, Blip_Buffer* left = NULL, Blip_Buffer* right = NULL ); - - // Emulates to time t, then writes data to addr - void write_register( blip_time_t t, int addr, int data ); - - // Emulates to time t, then subtracts t from the current time. - // OK if previous write call had time slightly after t. - void end_frame( blip_time_t t ); - -// More features - - // Clock rate sound hardware runs at - enum { clock_rate = 4194304 * GB_APU_OVERCLOCK }; - - // Registers are at io_addr to io_addr+io_size-1 - enum { io_addr = 0xFF10 }; - enum { io_size = 0x30 }; - - // Emulates to time t, then reads from addr - int read_register( blip_time_t t, int addr ); - - // Resets hardware to state after power, BEFORE boot ROM runs. Mode selects - // sound hardware. If agb_wave is true, enables AGB's extra wave features. - enum mode_t { - mode_dmg, // Game Boy monochrome - mode_cgb, // Game Boy Color - mode_agb // Game Boy Advance - }; - void reset( mode_t mode = mode_cgb, bool agb_wave = false ); - - // Same as set_output(), but for a particular channel - // 0: Square 1, 1: Square 2, 2: Wave, 3: Noise - enum { osc_count = 4 }; // 0 <= chan < osc_count - void set_output( int chan, Blip_Buffer* center, - Blip_Buffer* left = NULL, Blip_Buffer* right = NULL ); - - // Sets overall volume, where 1.0 is normal - void volume( double ); - - // Sets treble equalization - void treble_eq( blip_eq_t const& ); - - // Treble and bass values for various hardware. - enum { - speaker_treble = -47, // speaker on system - speaker_bass = 2000, - dmg_treble = 0, // headphones on each system - dmg_bass = 30, - cgb_treble = 0, - cgb_bass = 300, // CGB has much less bass - agb_treble = 0, - agb_bass = 30 - }; - - // If true, reduces clicking by disabling DAC biasing. Note that this reduces - // emulation accuracy, since the clicks are authentic. - void reduce_clicks( bool reduce = true ); - - // Sets frame sequencer rate, where 1.0 is normal. Meant for adjusting the - // tempo in a music player. - void set_tempo( double ); - - // Saves full emulation state to state_out. Data format is portable and - // includes some extra space to avoid expansion in case more state needs - // to be stored in the future. - void save_state( gb_apu_state_t* state_out ); - - // Loads state. You should call reset() BEFORE this. - blargg_err_t load_state( gb_apu_state_t const& in ); - - // Enable hacks (bitmask): - // 0x01 = Double wave channel volume - // 0x02 = Low noise channel volume (disable doubling it) - void set_hacks( unsigned int mask ); - -private: - // noncopyable - Gb_Apu( const Gb_Apu& ); - Gb_Apu& operator = ( const Gb_Apu& ); - -// Implementation -public: - Gb_Apu(); - - // Use set_output() in place of these - BLARGG_DEPRECATED( void output ( Blip_Buffer* c ); ) - BLARGG_DEPRECATED( void output ( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ); ) - BLARGG_DEPRECATED( void osc_output( int i, Blip_Buffer* c ) { set_output( i, c, c, c ); } ) - BLARGG_DEPRECATED( void osc_output( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( i, c, l, r ); } ) - - BLARGG_DEPRECATED_TEXT( enum { start_addr = 0xFF10 }; ) - BLARGG_DEPRECATED_TEXT( enum { end_addr = 0xFF3F }; ) - BLARGG_DEPRECATED_TEXT( enum { register_count = end_addr - start_addr + 1 }; ) - -private: - Gb_Osc* oscs [osc_count]; - blip_time_t last_time; // time sound emulator has been run to - blip_time_t frame_period; // clocks between each frame sequencer step - double volume_; - bool reduce_clicks_; - - Gb_Sweep_Square square1; - Gb_Square square2; - Gb_Wave wave; - Gb_Noise noise; - blip_time_t frame_time; // time of next frame sequencer action - int frame_phase; // phase of next frame sequencer step - enum { regs_size = io_size + 0x10 }; - BOOST::uint8_t regs [regs_size];// last values written to registers - - // large objects after everything else - Blip_Synth_Norm norm_synth; - Blip_Synth_Fast fast_synth; - - void reset_lengths(); - void reset_regs(); - int calc_output( int osc ) const; - void apply_stereo(); - void apply_volume(); - void synth_volume( int ); - void run_until_( blip_time_t ); - void run_until( blip_time_t ); - void silence_osc( Gb_Osc& ); - void write_osc( int reg, int old_data, int data ); - const char* save_load( gb_apu_state_t*, bool save ); - void save_load2( gb_apu_state_t*, bool save ); - friend class Gb_Apu2; -}; - -// Format of save state. Should be stable across versions of the library, -// with earlier versions properly opening later save states. Includes some -// room for expansion so the state size shouldn't increase. -struct gb_apu_state_t -{ -#if GB_APU_CUSTOM_STATE - // Values stored as plain int so your code can read/write them easily. - // Structure can NOT be written to disk, since format is not portable. - typedef int val_t; -#else - // Values written in portable little-endian format, allowing structure - // to be written directly to disk. - typedef unsigned char val_t [4]; -#endif - - enum { format0 = 0x50414247 }; // 'GBAP' - - val_t format; // format of all following data - val_t version; // later versions just add fields to end - - unsigned char regs [0x40]; - val_t frame_time; - val_t frame_phase; - - val_t sweep_freq; - val_t sweep_delay; - val_t sweep_enabled; - val_t sweep_neg; - val_t noise_divider; - val_t wave_buf; - - val_t delay [4]; - val_t length_ctr [4]; - val_t phase [4]; - val_t enabled [4]; - - val_t env_delay [3]; - val_t env_volume [3]; - val_t env_enabled [3]; - - val_t unused [13]; // for future expansion -}; - -inline void Gb_Apu::set_output( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) -{ - for ( int i = osc_count; --i >= 0; ) - set_output( i, c, l, r ); -} - -BLARGG_DEPRECATED_TEXT( inline void Gb_Apu::output( Blip_Buffer* c ) { set_output( c, c, c ); } ) -BLARGG_DEPRECATED_TEXT( inline void Gb_Apu::output( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( c, l, r ); } ) - -#endif +// Nintendo Game Boy sound hardware emulator with save state support + +// Gb_Snd_Emu $vers +#ifndef GB_APU_H +#define GB_APU_H + +#include "Gb_Oscs.h" + +struct gb_apu_state_t; + +class Gb_Apu { +public: +// Basics + + // Sets buffer(s) to generate sound into, or NULL to mute. If only center is not NULL, + // output is mono. + void set_output( Blip_Buffer* center, Blip_Buffer* left = NULL, Blip_Buffer* right = NULL ); + + // Emulates to time t, then writes data to addr + void write_register( blip_time_t t, int addr, int data ); + + // Emulates to time t, then subtracts t from the current time. + // OK if previous write call had time slightly after t. + void end_frame( blip_time_t t ); + +// More features + + // Clock rate sound hardware runs at + enum { clock_rate = 4194304 * GB_APU_OVERCLOCK }; + + // Registers are at io_addr to io_addr+io_size-1 + enum { io_addr = 0xFF10 }; + enum { io_size = 0x30 }; + + // Emulates to time t, then reads from addr + int read_register( blip_time_t t, int addr ); + + // Resets hardware to state after power, BEFORE boot ROM runs. Mode selects + // sound hardware. If agb_wave is true, enables AGB's extra wave features. + enum mode_t { + mode_dmg, // Game Boy monochrome + mode_cgb, // Game Boy Color + mode_agb // Game Boy Advance + }; + void reset( mode_t mode = mode_cgb, bool agb_wave = false ); + + // Same as set_output(), but for a particular channel + // 0: Square 1, 1: Square 2, 2: Wave, 3: Noise + enum { osc_count = 4 }; // 0 <= chan < osc_count + void set_output( int chan, Blip_Buffer* center, + Blip_Buffer* left = NULL, Blip_Buffer* right = NULL ); + + // Sets overall volume, where 1.0 is normal + void volume( double ); + + // Sets treble equalization + void treble_eq( blip_eq_t const& ); + + // Treble and bass values for various hardware. + enum { + speaker_treble = -47, // speaker on system + speaker_bass = 2000, + dmg_treble = 0, // headphones on each system + dmg_bass = 30, + cgb_treble = 0, + cgb_bass = 300, // CGB has much less bass + agb_treble = 0, + agb_bass = 30 + }; + + // If true, reduces clicking by disabling DAC biasing. Note that this reduces + // emulation accuracy, since the clicks are authentic. + void reduce_clicks( bool reduce = true ); + + // Sets frame sequencer rate, where 1.0 is normal. Meant for adjusting the + // tempo in a music player. + void set_tempo( double ); + + // Saves full emulation state to state_out. Data format is portable and + // includes some extra space to avoid expansion in case more state needs + // to be stored in the future. + void save_state( gb_apu_state_t* state_out ); + + // Loads state. You should call reset() BEFORE this. + blargg_err_t load_state( gb_apu_state_t const& in ); + +private: + // noncopyable + Gb_Apu( const Gb_Apu& ); + Gb_Apu& operator = ( const Gb_Apu& ); + +// Implementation +public: + Gb_Apu(); + + // Use set_output() in place of these + BLARGG_DEPRECATED( void output ( Blip_Buffer* c ); ) + BLARGG_DEPRECATED( void output ( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ); ) + BLARGG_DEPRECATED( void osc_output( int i, Blip_Buffer* c ) { set_output( i, c, c, c ); } ) + BLARGG_DEPRECATED( void osc_output( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( i, c, l, r ); } ) + + BLARGG_DEPRECATED_TEXT( enum { start_addr = 0xFF10 }; ) + BLARGG_DEPRECATED_TEXT( enum { end_addr = 0xFF3F }; ) + BLARGG_DEPRECATED_TEXT( enum { register_count = end_addr - start_addr + 1 }; ) + +private: + Gb_Osc* oscs [osc_count]; + blip_time_t last_time; // time sound emulator has been run to + blip_time_t frame_period; // clocks between each frame sequencer step + double volume_; + bool reduce_clicks_; + + Gb_Sweep_Square square1; + Gb_Square square2; + Gb_Wave wave; + Gb_Noise noise; + blip_time_t frame_time; // time of next frame sequencer action + int frame_phase; // phase of next frame sequencer step + enum { regs_size = io_size + 0x10 }; + BOOST::uint8_t regs [regs_size];// last values written to registers + + // large objects after everything else + Blip_Synth_Norm norm_synth; + Blip_Synth_Fast fast_synth; + + void reset_lengths(); + void reset_regs(); + int calc_output( int osc ) const; + void apply_stereo(); + void apply_volume(); + void synth_volume( int ); + void run_until_( blip_time_t ); + void run_until( blip_time_t ); + void silence_osc( Gb_Osc& ); + void write_osc( int reg, int old_data, int data ); + const char* save_load( gb_apu_state_t*, bool save ); + void save_load2( gb_apu_state_t*, bool save ); + friend class Gb_Apu2; +}; + +// Format of save state. Should be stable across versions of the library, +// with earlier versions properly opening later save states. Includes some +// room for expansion so the state size shouldn't increase. +struct gb_apu_state_t +{ +#if GB_APU_CUSTOM_STATE + // Values stored as plain int so your code can read/write them easily. + // Structure can NOT be written to disk, since format is not portable. + typedef int val_t; +#else + // Values written in portable little-endian format, allowing structure + // to be written directly to disk. + typedef unsigned char val_t [4]; +#endif + + enum { format0 = 0x50414247 }; // 'GBAP' + + val_t format; // format of all following data + val_t version; // later versions just add fields to end + + unsigned char regs [0x40]; + val_t frame_time; + val_t frame_phase; + + val_t sweep_freq; + val_t sweep_delay; + val_t sweep_enabled; + val_t sweep_neg; + val_t noise_divider; + val_t wave_buf; + + val_t delay [4]; + val_t length_ctr [4]; + val_t phase [4]; + val_t enabled [4]; + + val_t env_delay [3]; + val_t env_volume [3]; + val_t env_enabled [3]; + + val_t unused [13]; // for future expansion +}; + +inline void Gb_Apu::set_output( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) +{ + for ( int i = osc_count; --i >= 0; ) + set_output( i, c, l, r ); +} + +BLARGG_DEPRECATED_TEXT( inline void Gb_Apu::output( Blip_Buffer* c ) { set_output( c, c, c ); } ) +BLARGG_DEPRECATED_TEXT( inline void Gb_Apu::output( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( c, l, r ); } ) + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gb_Oscs.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gb_Oscs.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gb_Oscs.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gb_Oscs.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,720 +1,719 @@ -// Gb_Snd_Emu $vers. http://www.slack.net/~ant/ - -#include "Gb_Apu.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -bool const cgb_02 = false; // enables bug in early CGB units that causes problems in some games -bool const cgb_05 = false; // enables CGB-05 zombie behavior - -int const trigger_mask = 0x80; -int const length_enabled = 0x40; - -void Gb_Osc::reset() -{ - output = NULL; - last_amp = 0; - delay = 0; - phase = 0; - enabled = false; -} - -inline void Gb_Osc::update_amp( blip_time_t time, int new_amp ) -{ - output->set_modified(); - int delta = new_amp - last_amp; - if ( delta ) - { - last_amp = new_amp; - fast_synth->offset( time, delta, output ); - } -} - -// Units - -void Gb_Osc::clock_length() -{ - if ( (regs [4] & length_enabled) && length_ctr ) - { - if ( --length_ctr <= 0 ) - enabled = false; - } -} - -inline int Gb_Env::reload_env_timer() -{ - int raw = regs [2] & 7; - env_delay = (raw ? raw : 8); - return raw; -} - -void Gb_Env::clock_envelope() -{ - if ( env_enabled && --env_delay <= 0 && reload_env_timer() ) - { - int v = volume + (regs [2] & 0x08 ? +1 : -1); - if ( 0 <= v && v <= 15 ) - volume = v; - else - env_enabled = false; - } -} - -inline void Gb_Sweep_Square::reload_sweep_timer() -{ - sweep_delay = (regs [0] & period_mask) >> 4; - if ( !sweep_delay ) - sweep_delay = 8; -} - -void Gb_Sweep_Square::calc_sweep( bool update ) -{ - int const shift = regs [0] & shift_mask; - int const delta = sweep_freq >> shift; - sweep_neg = (regs [0] & 0x08) != 0; - int const freq = sweep_freq + (sweep_neg ? -delta : delta); - - if ( freq > 0x7FF ) - { - enabled = false; - } - else if ( shift && update ) - { - sweep_freq = freq; - - regs [3] = freq & 0xFF; - regs [4] = (regs [4] & ~0x07) | (freq >> 8 & 0x07); - } -} - -void Gb_Sweep_Square::clock_sweep() -{ - if ( --sweep_delay <= 0 ) - { - reload_sweep_timer(); - if ( sweep_enabled && (regs [0] & period_mask) ) - { - calc_sweep( true ); - calc_sweep( false ); - } - } -} - -int Gb_Wave::access( int addr ) const -{ - if ( enabled ) - { - addr = phase & (bank_size - 1); - if ( mode == Gb_Apu::mode_dmg ) - { - addr++; - if ( delay > clk_mul ) - return -1; // can only access within narrow time window while playing - } - addr >>= 1; - } - return addr & 0x0F; -} - -// write_register - -int Gb_Osc::write_trig( int frame_phase, int max_len, int old_data ) -{ - int data = regs [4]; - - if ( (frame_phase & 1) && !(old_data & length_enabled) && length_ctr ) - { - if ( (data & length_enabled) || cgb_02 ) - length_ctr--; - } - - if ( data & trigger_mask ) - { - enabled = true; - if ( !length_ctr ) - { - length_ctr = max_len; - if ( (frame_phase & 1) && (data & length_enabled) ) - length_ctr--; - } - } - - if ( !length_ctr ) - enabled = false; - - return data & trigger_mask; -} - -inline void Gb_Env::zombie_volume( int old, int data ) -{ - int v = volume; - if ( mode == Gb_Apu::mode_agb || cgb_05 ) - { - // CGB-05 behavior, very close to AGB behavior as well - if ( (old ^ data) & 8 ) - { - if ( !(old & 8) ) - { - v++; - if ( old & 7 ) - v++; - } - - v = 16 - v; - } - else if ( (old & 0x0F) == 8 ) - { - v++; - } - } - else - { - // CGB-04&02 behavior, very close to MGB behavior as well - if ( !(old & 7) && env_enabled ) - v++; - else if ( !(old & 8) ) - v += 2; - - if ( (old ^ data) & 8 ) - v = 16 - v; - } - volume = v & 0x0F; -} - -bool Gb_Env::write_register( int frame_phase, int reg, int old, int data ) -{ - int const max_len = 64; - - switch ( reg ) - { - case 1: - length_ctr = max_len - (data & (max_len - 1)); - break; - - case 2: - if ( !dac_enabled() ) - enabled = false; - - zombie_volume( old, data ); - - if ( (data & 7) && env_delay == 8 ) - { - env_delay = 1; - clock_envelope(); // TODO: really happens at next length clock - } - break; - - case 4: - if ( write_trig( frame_phase, max_len, old ) ) - { - volume = regs [2] >> 4; - reload_env_timer(); - env_enabled = true; - if ( frame_phase == 7 ) - env_delay++; - if ( !dac_enabled() ) - enabled = false; - return true; - } - } - return false; -} - -bool Gb_Square::write_register( int frame_phase, int reg, int old_data, int data ) -{ - bool result = Gb_Env::write_register( frame_phase, reg, old_data, data ); - if ( result ) - delay = (delay & (4 * clk_mul - 1)) + period(); - return result; -} - -inline void Gb_Noise::write_register( int frame_phase, int reg, int old_data, int data ) -{ - if ( Gb_Env::write_register( frame_phase, reg, old_data, data ) ) - { - phase = 0x7FFF; - delay += 8 * clk_mul; - } -} - -inline void Gb_Sweep_Square::write_register( int frame_phase, int reg, int old_data, int data ) -{ - if ( reg == 0 && sweep_enabled && sweep_neg && !(data & 0x08) ) - enabled = false; // sweep negate disabled after used - - if ( Gb_Square::write_register( frame_phase, reg, old_data, data ) ) - { - sweep_freq = frequency(); - sweep_neg = false; - reload_sweep_timer(); - sweep_enabled = (regs [0] & (period_mask | shift_mask)) != 0; - if ( regs [0] & shift_mask ) - calc_sweep( false ); - } -} - -void Gb_Wave::corrupt_wave() -{ - int pos = ((phase + 1) & (bank_size - 1)) >> 1; - if ( pos < 4 ) - wave_ram [0] = wave_ram [pos]; - else - for ( int i = 4; --i >= 0; ) - wave_ram [i] = wave_ram [(pos & ~3) + i]; -} - -inline void Gb_Wave::write_register( int frame_phase, int reg, int old_data, int data ) -{ - int const max_len = 256; - - switch ( reg ) - { - case 0: - if ( !dac_enabled() ) - enabled = false; - break; - - case 1: - length_ctr = max_len - data; - break; - - case 4: - bool was_enabled = enabled; - if ( write_trig( frame_phase, max_len, old_data ) ) - { - if ( !dac_enabled() ) - enabled = false; - else if ( mode == Gb_Apu::mode_dmg && was_enabled && - (unsigned) (delay - 2 * clk_mul) < 2 * clk_mul ) - corrupt_wave(); - - phase = 0; - delay = period() + 6 * clk_mul; - } - } -} - -void Gb_Apu::write_osc( int reg, int old_data, int data ) -{ - int index = (reg * 3 + 3) >> 4; // avoids divide - assert( index == reg / 5 ); - reg -= index * 5; - switch ( index ) - { - case 0: square1.write_register( frame_phase, reg, old_data, data ); break; - case 1: square2.write_register( frame_phase, reg, old_data, data ); break; - case 2: wave .write_register( frame_phase, reg, old_data, data ); break; - case 3: noise .write_register( frame_phase, reg, old_data, data ); break; - } -} - -// Synthesis - -void Gb_Square::run( blip_time_t time, blip_time_t end_time ) -{ - // Calc duty and phase - static byte const duty_offsets [4] = { 1, 1, 3, 7 }; - static byte const duties [4] = { 1, 2, 4, 6 }; - int const duty_code = regs [1] >> 6; - int duty_offset = duty_offsets [duty_code]; - int duty = duties [duty_code]; - if ( mode == Gb_Apu::mode_agb ) - { - // AGB uses inverted duty - duty_offset -= duty; - duty = 8 - duty; - } - int ph = (this->phase + duty_offset) & 7; - - // Determine what will be generated - int vol = 0; - Blip_Buffer* const out = this->output; - if ( out ) - { - int amp = dac_off_amp; - if ( dac_enabled() ) - { - if ( enabled ) - vol = this->volume; - - amp = -dac_bias; - if ( mode == Gb_Apu::mode_agb ) - amp = -(vol >> 1); - - // Play inaudible frequencies as constant amplitude - if ( frequency() >= 0x7FA && delay < 32 * clk_mul ) - { - amp += (vol * duty) >> 3; - vol = 0; - } - - if ( ph < duty ) - { - amp += vol; - vol = -vol; - } - } - update_amp( time, amp ); - } - - // Generate wave - time += delay; - if ( time < end_time ) - { - int const per = this->period(); - if ( !vol ) - { - #if GB_APU_FAST - time = end_time; - #else - // Maintain phase when not playing - int count = (end_time - time + per - 1) / per; - ph += count; // will be masked below - time += (blip_time_t) count * per; - #endif - } - else - { - // Output amplitude transitions - int delta = vol; - do - { - ph = (ph + 1) & 7; - if ( ph == 0 || ph == duty ) - { - norm_synth->offset_inline( time, delta, out ); - delta = -delta; - } - time += per; - } - while ( time < end_time ); - - if ( delta != vol ) - last_amp -= delta; - } - this->phase = (ph - duty_offset) & 7; - } - delay = time - end_time; -} - -#if !GB_APU_FAST -// Quickly runs LFSR for a large number of clocks. For use when noise is generating -// no sound. -static unsigned run_lfsr( unsigned s, unsigned mask, int count ) -{ - bool const optimized = true; // set to false to use only unoptimized loop in middle - - // optimization used in several places: - // ((s & (1 << b)) << n) ^ ((s & (1 << b)) << (n + 1)) = (s & (1 << b)) * (3 << n) - - if ( mask == 0x4000 && optimized ) - { - if ( count >= 32767 ) - count %= 32767; - - // Convert from Fibonacci to Galois configuration, - // shifted left 1 bit - s ^= (s & 1) * 0x8000; - - // Each iteration is equivalent to clocking LFSR 255 times - while ( (count -= 255) > 0 ) - s ^= ((s & 0xE) << 12) ^ ((s & 0xE) << 11) ^ (s >> 3); - count += 255; - - // Each iteration is equivalent to clocking LFSR 15 times - // (interesting similarity to single clocking below) - while ( (count -= 15) > 0 ) - s ^= ((s & 2) * (3 << 13)) ^ (s >> 1); - count += 15; - - // Remaining singles - while ( --count >= 0 ) - s = ((s & 2) * (3 << 13)) ^ (s >> 1); - - // Convert back to Fibonacci configuration - s &= 0x7FFF; - } - else if ( count < 8 || !optimized ) - { - // won't fully replace upper 8 bits, so have to do the unoptimized way - while ( --count >= 0 ) -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4146) -#endif - s = (s >> 1 | mask) ^ (mask & -((s - 1) & 2)); -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - } - else - { - if ( count > 127 ) - { - count %= 127; - if ( !count ) - count = 127; // must run at least once - } - - // Need to keep one extra bit of history - s = s << 1 & 0xFF; - - // Convert from Fibonacci to Galois configuration, - // shifted left 2 bits - s ^= (s & 2) * 0x80; - - // Each iteration is equivalent to clocking LFSR 7 times - // (interesting similarity to single clocking below) - while ( (count -= 7) > 0 ) - s ^= ((s & 4) * (3 << 5)) ^ (s >> 1); - count += 7; - - // Remaining singles - while ( --count >= 0 ) - s = ((s & 4) * (3 << 5)) ^ (s >> 1); - - // Convert back to Fibonacci configuration and - // repeat last 8 bits above significant 7 - s = (s << 7 & 0x7F80) | (s >> 1 & 0x7F); - } - - return s; -} -#endif - -void Gb_Noise::run( blip_time_t time, blip_time_t end_time ) -{ - // Determine what will be generated - int vol = 0; - Blip_Buffer* const out = this->output; - if ( out ) - { - int amp = dac_off_amp; - if ( dac_enabled() ) - { - if ( enabled ) - vol = this->volume; - - amp = -dac_bias; - if ( mode == Gb_Apu::mode_agb ) - amp = -(vol >> 1); - - if ( !(phase & 1) ) - { - amp += vol; - vol = -vol; - } - } - - // AGB negates final output - if ( mode == Gb_Apu::mode_agb ) - { - vol = -vol; - amp = -amp; - } - - update_amp( time, amp ); - } - - // Run timer and calculate time of next LFSR clock - static byte const period1s [8] = { 1, 2, 4, 6, 8, 10, 12, 14 }; - int const period1 = period1s [regs [3] & 7] * clk_mul; - - #if GB_APU_FAST - time += delay; - #else - { - int extra = (end_time - time) - delay; - int const per2 = this->period2(); - time += delay + ((divider ^ (per2 >> 1)) & (per2 - 1)) * period1; - - int count = (extra < 0 ? 0 : (extra + period1 - 1) / period1); - divider = (divider - count) & period2_mask; - delay = count * period1 - extra; - } - #endif - - // Generate wave - if ( time < end_time ) - { - unsigned const mask = this->lfsr_mask(); - unsigned bits = this->phase; - - int per = period2( period1 * 8 ); - #if GB_APU_FAST - // Noise can be THE biggest time hog; adjust as necessary - int const min_period = 24; - if ( per < min_period ) - per = min_period; - #endif - if ( period2_index() >= 0xE ) - { - time = end_time; - } - else if ( !vol ) - { - #if GB_APU_FAST - time = end_time; - #else - // Maintain phase when not playing - int count = (end_time - time + per - 1) / per; - time += (blip_time_t) count * per; - bits = run_lfsr( bits, ~mask, count ); - #endif - } - else - { - Blip_Synth_Fast const* const synth = fast_synth; // cache - - // Output amplitude transitions - if (volume_hack) vol <<= 1; - int delta = -vol; - do - { - unsigned changed = bits + 1; - bits = bits >> 1 & mask; - if ( changed & 2 ) - { - bits |= ~mask; - delta = -delta; - synth->offset_inline( time, delta, out ); - } - time += per; - } - while ( time < end_time ); - - if ( delta == vol ) - last_amp += delta; - } - this->phase = bits; - } - - #if GB_APU_FAST - delay = time - end_time; - #endif -} - -void Gb_Wave::run( blip_time_t time, blip_time_t end_time ) -{ - // Calc volume -#if GB_APU_NO_AGB - static byte const shifts [4] = { 4+4, 0+4, 1+4, 2+4 }; - int const volume_idx = regs [2] >> 5 & 3; - int const volume_shift = shifts [volume_idx] - (volume_hack ? 1 : 0); - int const volume_mul = 1; -#else - static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 }; - int const volume_shift = 2 + 4 - (volume_hack ? 1 : 0); - int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB - int const volume_mul = volumes [volume_idx]; -#endif - - // Determine what will be generated - int playing = false; - Blip_Buffer* const out = this->output; - if ( out ) - { - int amp = dac_off_amp; - if ( dac_enabled() ) - { - // Play inaudible frequencies as constant amplitude - amp = 8 << 4; // really depends on average of all samples in wave - - // if delay is larger, constant amplitude won't start yet - if ( frequency() <= 0x7FB || delay > 15 * clk_mul ) - { - if ( volume_mul && volume_shift != 4+4 ) - playing = (int) enabled; - - amp = (sample_buf << (phase << 2 & 4) & 0xF0) * playing; - } - - amp = ((amp * volume_mul) >> volume_shift) - dac_bias; - } - update_amp( time, amp ); - } - - // Generate wave - time += delay; - if ( time < end_time ) - { - byte const* wave = this->wave_ram; - - // wave size and bank - #if GB_APU_NO_AGB - int const wave_mask = 0x1F; - int const swap_banks = 0; - #else - int const size20_mask = 0x20; - int const flags = regs [0] & agb_mask; - int const wave_mask = (flags & size20_mask) | 0x1F; - int swap_banks = 0; - if ( flags & bank40_mask ) - { - swap_banks = flags & size20_mask; - wave += bank_size/2 - (swap_banks >> 1); - } - #endif - - int ph = this->phase ^ swap_banks; - ph = (ph + 1) & wave_mask; // pre-advance - - int const per = this->period(); - if ( !playing ) - { - #if GB_APU_FAST - time = end_time; - #else - // Maintain phase when not playing - int count = (end_time - time + per - 1) / per; - ph += count; // will be masked below - time += (blip_time_t) count * per; - #endif - } - else - { - Blip_Synth_Fast const* const synth = fast_synth; // cache - - // Output amplitude transitions - int lamp = this->last_amp + dac_bias; - do - { - // Extract nibble - int nibble = wave [ph >> 1] << (ph << 2 & 4) & 0xF0; - ph = (ph + 1) & wave_mask; - - // Scale by volume - int amp = (nibble * volume_mul) >> volume_shift; - - int delta = amp - lamp; - if ( delta ) - { - lamp = amp; - synth->offset_inline( time, delta, out ); - } - time += per; - } - while ( time < end_time ); - this->last_amp = lamp - dac_bias; - } - ph = (ph - 1) & wave_mask; // undo pre-advance and mask position - - // Keep track of last byte read - if ( enabled ) - sample_buf = wave [ph >> 1]; - - this->phase = ph ^ swap_banks; // undo swapped banks - } - delay = time - end_time; -} +// Gb_Snd_Emu $vers. http://www.slack.net/~ant/ + +#include "Gb_Apu.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +bool const cgb_02 = false; // enables bug in early CGB units that causes problems in some games +bool const cgb_05 = false; // enables CGB-05 zombie behavior + +int const trigger_mask = 0x80; +int const length_enabled = 0x40; + +void Gb_Osc::reset() +{ + output = NULL; + last_amp = 0; + delay = 0; + phase = 0; + enabled = false; +} + +inline void Gb_Osc::update_amp( blip_time_t time, int new_amp ) +{ + output->set_modified(); + int delta = new_amp - last_amp; + if ( delta ) + { + last_amp = new_amp; + fast_synth->offset( time, delta, output ); + } +} + +// Units + +void Gb_Osc::clock_length() +{ + if ( (regs [4] & length_enabled) && length_ctr ) + { + if ( --length_ctr <= 0 ) + enabled = false; + } +} + +inline int Gb_Env::reload_env_timer() +{ + int raw = regs [2] & 7; + env_delay = (raw ? raw : 8); + return raw; +} + +void Gb_Env::clock_envelope() +{ + if ( env_enabled && --env_delay <= 0 && reload_env_timer() ) + { + int v = volume + (regs [2] & 0x08 ? +1 : -1); + if ( 0 <= v && v <= 15 ) + volume = v; + else + env_enabled = false; + } +} + +inline void Gb_Sweep_Square::reload_sweep_timer() +{ + sweep_delay = (regs [0] & period_mask) >> 4; + if ( !sweep_delay ) + sweep_delay = 8; +} + +void Gb_Sweep_Square::calc_sweep( bool update ) +{ + int const shift = regs [0] & shift_mask; + int const delta = sweep_freq >> shift; + sweep_neg = (regs [0] & 0x08) != 0; + int const freq = sweep_freq + (sweep_neg ? -delta : delta); + + if ( freq > 0x7FF ) + { + enabled = false; + } + else if ( shift && update ) + { + sweep_freq = freq; + + regs [3] = freq & 0xFF; + regs [4] = (regs [4] & ~0x07) | (freq >> 8 & 0x07); + } +} + +void Gb_Sweep_Square::clock_sweep() +{ + if ( --sweep_delay <= 0 ) + { + reload_sweep_timer(); + if ( sweep_enabled && (regs [0] & period_mask) ) + { + calc_sweep( true ); + calc_sweep( false ); + } + } +} + +int Gb_Wave::access( int addr ) const +{ + if ( enabled ) + { + addr = phase & (bank_size - 1); + if ( mode == Gb_Apu::mode_dmg ) + { + addr++; + if ( delay > clk_mul ) + return -1; // can only access within narrow time window while playing + } + addr >>= 1; + } + return addr & 0x0F; +} + +// write_register + +int Gb_Osc::write_trig( int frame_phase, int max_len, int old_data ) +{ + int data = regs [4]; + + if ( (frame_phase & 1) && !(old_data & length_enabled) && length_ctr ) + { + if ( (data & length_enabled) || cgb_02 ) + length_ctr--; + } + + if ( data & trigger_mask ) + { + enabled = true; + if ( !length_ctr ) + { + length_ctr = max_len; + if ( (frame_phase & 1) && (data & length_enabled) ) + length_ctr--; + } + } + + if ( !length_ctr ) + enabled = false; + + return data & trigger_mask; +} + +inline void Gb_Env::zombie_volume( int old, int data ) +{ + int v = volume; + if ( mode == Gb_Apu::mode_agb || cgb_05 ) + { + // CGB-05 behavior, very close to AGB behavior as well + if ( (old ^ data) & 8 ) + { + if ( !(old & 8) ) + { + v++; + if ( old & 7 ) + v++; + } + + v = 16 - v; + } + else if ( (old & 0x0F) == 8 ) + { + v++; + } + } + else + { + // CGB-04&02 behavior, very close to MGB behavior as well + if ( !(old & 7) && env_enabled ) + v++; + else if ( !(old & 8) ) + v += 2; + + if ( (old ^ data) & 8 ) + v = 16 - v; + } + volume = v & 0x0F; +} + +bool Gb_Env::write_register( int frame_phase, int reg, int old, int data ) +{ + int const max_len = 64; + + switch ( reg ) + { + case 1: + length_ctr = max_len - (data & (max_len - 1)); + break; + + case 2: + if ( !dac_enabled() ) + enabled = false; + + zombie_volume( old, data ); + + if ( (data & 7) && env_delay == 8 ) + { + env_delay = 1; + clock_envelope(); // TODO: really happens at next length clock + } + break; + + case 4: + if ( write_trig( frame_phase, max_len, old ) ) + { + volume = regs [2] >> 4; + reload_env_timer(); + env_enabled = true; + if ( frame_phase == 7 ) + env_delay++; + if ( !dac_enabled() ) + enabled = false; + return true; + } + } + return false; +} + +bool Gb_Square::write_register( int frame_phase, int reg, int old_data, int data ) +{ + bool result = Gb_Env::write_register( frame_phase, reg, old_data, data ); + if ( result ) + delay = (delay & (4 * clk_mul - 1)) + period(); + return result; +} + +inline void Gb_Noise::write_register( int frame_phase, int reg, int old_data, int data ) +{ + if ( Gb_Env::write_register( frame_phase, reg, old_data, data ) ) + { + phase = 0x7FFF; + delay += 8 * clk_mul; + } +} + +inline void Gb_Sweep_Square::write_register( int frame_phase, int reg, int old_data, int data ) +{ + if ( reg == 0 && sweep_enabled && sweep_neg && !(data & 0x08) ) + enabled = false; // sweep negate disabled after used + + if ( Gb_Square::write_register( frame_phase, reg, old_data, data ) ) + { + sweep_freq = frequency(); + sweep_neg = false; + reload_sweep_timer(); + sweep_enabled = (regs [0] & (period_mask | shift_mask)) != 0; + if ( regs [0] & shift_mask ) + calc_sweep( false ); + } +} + +void Gb_Wave::corrupt_wave() +{ + int pos = ((phase + 1) & (bank_size - 1)) >> 1; + if ( pos < 4 ) + wave_ram [0] = wave_ram [pos]; + else + for ( int i = 4; --i >= 0; ) + wave_ram [i] = wave_ram [(pos & ~3) + i]; +} + +inline void Gb_Wave::write_register( int frame_phase, int reg, int old_data, int data ) +{ + int const max_len = 256; + + switch ( reg ) + { + case 0: + if ( !dac_enabled() ) + enabled = false; + break; + + case 1: + length_ctr = max_len - data; + break; + + case 4: + bool was_enabled = enabled; + if ( write_trig( frame_phase, max_len, old_data ) ) + { + if ( !dac_enabled() ) + enabled = false; + else if ( mode == Gb_Apu::mode_dmg && was_enabled && + (unsigned) (delay - 2 * clk_mul) < 2 * clk_mul ) + corrupt_wave(); + + phase = 0; + delay = period() + 6 * clk_mul; + } + } +} + +void Gb_Apu::write_osc( int reg, int old_data, int data ) +{ + int index = (reg * 3 + 3) >> 4; // avoids divide + assert( index == reg / 5 ); + reg -= index * 5; + switch ( index ) + { + case 0: square1.write_register( frame_phase, reg, old_data, data ); break; + case 1: square2.write_register( frame_phase, reg, old_data, data ); break; + case 2: wave .write_register( frame_phase, reg, old_data, data ); break; + case 3: noise .write_register( frame_phase, reg, old_data, data ); break; + } +} + +// Synthesis + +void Gb_Square::run( blip_time_t time, blip_time_t end_time ) +{ + // Calc duty and phase + static byte const duty_offsets [4] = { 1, 1, 3, 7 }; + static byte const duties [4] = { 1, 2, 4, 6 }; + int const duty_code = regs [1] >> 6; + int duty_offset = duty_offsets [duty_code]; + int duty = duties [duty_code]; + if ( mode == Gb_Apu::mode_agb ) + { + // AGB uses inverted duty + duty_offset -= duty; + duty = 8 - duty; + } + int ph = (this->phase + duty_offset) & 7; + + // Determine what will be generated + int vol = 0; + Blip_Buffer* const out = this->output; + if ( out ) + { + int amp = dac_off_amp; + if ( dac_enabled() ) + { + if ( enabled ) + vol = this->volume; + + amp = -dac_bias; + if ( mode == Gb_Apu::mode_agb ) + amp = -(vol >> 1); + + // Play inaudible frequencies as constant amplitude + if ( frequency() >= 0x7FA && delay < 32 * clk_mul ) + { + amp += (vol * duty) >> 3; + vol = 0; + } + + if ( ph < duty ) + { + amp += vol; + vol = -vol; + } + } + update_amp( time, amp ); + } + + // Generate wave + time += delay; + if ( time < end_time ) + { + int const per = this->period(); + if ( !vol ) + { + #if GB_APU_FAST + time = end_time; + #else + // Maintain phase when not playing + int count = (end_time - time + per - 1) / per; + ph += count; // will be masked below + time += (blip_time_t) count * per; + #endif + } + else + { + // Output amplitude transitions + int delta = vol; + do + { + ph = (ph + 1) & 7; + if ( ph == 0 || ph == duty ) + { + norm_synth->offset_inline( time, delta, out ); + delta = -delta; + } + time += per; + } + while ( time < end_time ); + + if ( delta != vol ) + last_amp -= delta; + } + this->phase = (ph - duty_offset) & 7; + } + delay = time - end_time; +} + +#if !GB_APU_FAST +// Quickly runs LFSR for a large number of clocks. For use when noise is generating +// no sound. +static unsigned run_lfsr( unsigned s, unsigned mask, int count ) +{ + bool const optimized = true; // set to false to use only unoptimized loop in middle + + // optimization used in several places: + // ((s & (1 << b)) << n) ^ ((s & (1 << b)) << (n + 1)) = (s & (1 << b)) * (3 << n) + + if ( mask == 0x4000 && optimized ) + { + if ( count >= 32767 ) + count %= 32767; + + // Convert from Fibonacci to Galois configuration, + // shifted left 1 bit + s ^= (s & 1) * 0x8000; + + // Each iteration is equivalent to clocking LFSR 255 times + while ( (count -= 255) > 0 ) + s ^= ((s & 0xE) << 12) ^ ((s & 0xE) << 11) ^ (s >> 3); + count += 255; + + // Each iteration is equivalent to clocking LFSR 15 times + // (interesting similarity to single clocking below) + while ( (count -= 15) > 0 ) + s ^= ((s & 2) * (3 << 13)) ^ (s >> 1); + count += 15; + + // Remaining singles + while ( --count >= 0 ) + s = ((s & 2) * (3 << 13)) ^ (s >> 1); + + // Convert back to Fibonacci configuration + s &= 0x7FFF; + } + else if ( count < 8 || !optimized ) + { + // won't fully replace upper 8 bits, so have to do the unoptimized way + while ( --count >= 0 ) +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4146) +#endif + s = (s >> 1 | mask) ^ (mask & -((s - 1) & 2)); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + } + else + { + if ( count > 127 ) + { + count %= 127; + if ( !count ) + count = 127; // must run at least once + } + + // Need to keep one extra bit of history + s = s << 1 & 0xFF; + + // Convert from Fibonacci to Galois configuration, + // shifted left 2 bits + s ^= (s & 2) * 0x80; + + // Each iteration is equivalent to clocking LFSR 7 times + // (interesting similarity to single clocking below) + while ( (count -= 7) > 0 ) + s ^= ((s & 4) * (3 << 5)) ^ (s >> 1); + count += 7; + + // Remaining singles + while ( --count >= 0 ) + s = ((s & 4) * (3 << 5)) ^ (s >> 1); + + // Convert back to Fibonacci configuration and + // repeat last 8 bits above significant 7 + s = (s << 7 & 0x7F80) | (s >> 1 & 0x7F); + } + + return s; +} +#endif + +void Gb_Noise::run( blip_time_t time, blip_time_t end_time ) +{ + // Determine what will be generated + int vol = 0; + Blip_Buffer* const out = this->output; + if ( out ) + { + int amp = dac_off_amp; + if ( dac_enabled() ) + { + if ( enabled ) + vol = this->volume; + + amp = -dac_bias; + if ( mode == Gb_Apu::mode_agb ) + amp = -(vol >> 1); + + if ( !(phase & 1) ) + { + amp += vol; + vol = -vol; + } + } + + // AGB negates final output + if ( mode == Gb_Apu::mode_agb ) + { + vol = -vol; + amp = -amp; + } + + update_amp( time, amp ); + } + + // Run timer and calculate time of next LFSR clock + static byte const period1s [8] = { 1, 2, 4, 6, 8, 10, 12, 14 }; + int const period1 = period1s [regs [3] & 7] * clk_mul; + + #if GB_APU_FAST + time += delay; + #else + { + int extra = (end_time - time) - delay; + int const per2 = this->period2(); + time += delay + ((divider ^ (per2 >> 1)) & (per2 - 1)) * period1; + + int count = (extra < 0 ? 0 : (extra + period1 - 1) / period1); + divider = (divider - count) & period2_mask; + delay = count * period1 - extra; + } + #endif + + // Generate wave + if ( time < end_time ) + { + unsigned const mask = this->lfsr_mask(); + unsigned bits = this->phase; + + int per = period2( period1 * 8 ); + #if GB_APU_FAST + // Noise can be THE biggest time hog; adjust as necessary + int const min_period = 24; + if ( per < min_period ) + per = min_period; + #endif + if ( period2_index() >= 0xE ) + { + time = end_time; + } + else if ( !vol ) + { + #if GB_APU_FAST + time = end_time; + #else + // Maintain phase when not playing + int count = (end_time - time + per - 1) / per; + time += (blip_time_t) count * per; + bits = run_lfsr( bits, ~mask, count ); + #endif + } + else + { + Blip_Synth_Fast const* const synth = fast_synth; // cache + + // Output amplitude transitions + int delta = -vol; + do + { + unsigned changed = bits + 1; + bits = bits >> 1 & mask; + if ( changed & 2 ) + { + bits |= ~mask; + delta = -delta; + synth->offset_inline( time, delta, out ); + } + time += per; + } + while ( time < end_time ); + + if ( delta == vol ) + last_amp += delta; + } + this->phase = bits; + } + + #if GB_APU_FAST + delay = time - end_time; + #endif +} + +void Gb_Wave::run( blip_time_t time, blip_time_t end_time ) +{ + // Calc volume +#if GB_APU_NO_AGB + static byte const shifts [4] = { 4+4, 0+4, 1+4, 2+4 }; + int const volume_idx = regs [2] >> 5 & 3; + int const volume_shift = shifts [volume_idx]; + int const volume_mul = 1; +#else + static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 }; + int const volume_shift = 2 + 4; + int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB + int const volume_mul = volumes [volume_idx]; +#endif + + // Determine what will be generated + int playing = false; + Blip_Buffer* const out = this->output; + if ( out ) + { + int amp = dac_off_amp; + if ( dac_enabled() ) + { + // Play inaudible frequencies as constant amplitude + amp = 8 << 4; // really depends on average of all samples in wave + + // if delay is larger, constant amplitude won't start yet + if ( frequency() <= 0x7FB || delay > 15 * clk_mul ) + { + if ( volume_mul && volume_shift != 4+4 ) + playing = (int) enabled; + + amp = (sample_buf << (phase << 2 & 4) & 0xF0) * playing; + } + + amp = ((amp * volume_mul) >> volume_shift) - dac_bias; + } + update_amp( time, amp ); + } + + // Generate wave + time += delay; + if ( time < end_time ) + { + byte const* wave = this->wave_ram; + + // wave size and bank + #if GB_APU_NO_AGB + int const wave_mask = 0x1F; + int const swap_banks = 0; + #else + int const size20_mask = 0x20; + int const flags = regs [0] & agb_mask; + int const wave_mask = (flags & size20_mask) | 0x1F; + int swap_banks = 0; + if ( flags & bank40_mask ) + { + swap_banks = flags & size20_mask; + wave += bank_size/2 - (swap_banks >> 1); + } + #endif + + int ph = this->phase ^ swap_banks; + ph = (ph + 1) & wave_mask; // pre-advance + + int const per = this->period(); + if ( !playing ) + { + #if GB_APU_FAST + time = end_time; + #else + // Maintain phase when not playing + int count = (end_time - time + per - 1) / per; + ph += count; // will be masked below + time += (blip_time_t) count * per; + #endif + } + else + { + Blip_Synth_Fast const* const synth = fast_synth; // cache + + // Output amplitude transitions + int lamp = this->last_amp + dac_bias; + do + { + // Extract nibble + int nibble = wave [ph >> 1] << (ph << 2 & 4) & 0xF0; + ph = (ph + 1) & wave_mask; + + // Scale by volume + int amp = (nibble * volume_mul) >> volume_shift; + + int delta = amp - lamp; + if ( delta ) + { + lamp = amp; + synth->offset_inline( time, delta, out ); + } + time += per; + } + while ( time < end_time ); + this->last_amp = lamp - dac_bias; + } + ph = (ph - 1) & wave_mask; // undo pre-advance and mask position + + // Keep track of last byte read + if ( enabled ) + sample_buf = wave [ph >> 1]; + + this->phase = ph ^ swap_banks; // undo swapped banks + } + delay = time - end_time; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gb_Oscs.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gb_Oscs.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gb_Oscs.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gb_Oscs.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,203 +1,188 @@ -// Private oscillators used by Gb_Apu - -// Gb_Snd_Emu $vers -#ifndef GB_OSCS_H -#define GB_OSCS_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -#ifndef GB_APU_OVERCLOCK - #define GB_APU_OVERCLOCK 1 -#endif - -#if GB_APU_OVERCLOCK & (GB_APU_OVERCLOCK - 1) - #error "GB_APU_OVERCLOCK must be a power of 2" -#endif - -class Gb_Osc { -protected: - - // 11-bit frequency in NRx3 and NRx4 - int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; } - - void update_amp( blip_time_t, int new_amp ); - int write_trig( int frame_phase, int max_len, int old_data ); -public: - - enum { clk_mul = GB_APU_OVERCLOCK }; - enum { dac_bias = 7 }; - - Blip_Buffer* outputs [4];// NULL, right, left, center - Blip_Buffer* output; // where to output sound - BOOST::uint8_t* regs; // osc's 5 registers - int mode; // mode_dmg, mode_cgb, mode_agb - int dac_off_amp;// amplitude when DAC is off - int last_amp; // current amplitude in Blip_Buffer - Blip_Synth_Norm const* norm_synth; - Blip_Synth_Fast const* fast_synth; - - int delay; // clocks until frequency timer expires - int length_ctr; // length counter - unsigned phase; // waveform phase (or equivalent) - bool enabled; // internal enabled flag - - void clock_length(); - void reset(); -}; - -class Gb_Env : public Gb_Osc { -public: - int env_delay; - int volume; - bool env_enabled; - - void clock_envelope(); - bool write_register( int frame_phase, int reg, int old_data, int data ); - - void reset() - { - env_delay = 0; - volume = 0; - Gb_Osc::reset(); - } -protected: - // Non-zero if DAC is enabled - int dac_enabled() const { return regs [2] & 0xF8; } -private: - void zombie_volume( int old, int data ); - int reload_env_timer(); -}; - -class Gb_Square : public Gb_Env { -public: - bool write_register( int frame_phase, int reg, int old_data, int data ); - void run( blip_time_t, blip_time_t ); - - void reset() - { - Gb_Env::reset(); - delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) - } -private: - // Frequency timer period - int period() const { return (2048 - frequency()) * (4 * clk_mul); } -}; - -class Gb_Sweep_Square : public Gb_Square { -public: - int sweep_freq; - int sweep_delay; - bool sweep_enabled; - bool sweep_neg; - - void clock_sweep(); - void write_register( int frame_phase, int reg, int old_data, int data ); - - void reset() - { - sweep_freq = 0; - sweep_delay = 0; - sweep_enabled = false; - sweep_neg = false; - Gb_Square::reset(); - } -private: - enum { period_mask = 0x70 }; - enum { shift_mask = 0x07 }; - - void calc_sweep( bool update ); - void reload_sweep_timer(); -}; - -class Gb_Noise : public Gb_Env { -public: - - int divider; // noise has more complex frequency divider setup - - bool volume_hack; - - void run( blip_time_t, blip_time_t ); - void write_register( int frame_phase, int reg, int old_data, int data ); - - void reset() - { - divider = 0; - Gb_Env::reset(); - delay = 4 * clk_mul; // TODO: remove? - volume_hack = true; - } - - void set_volume_hack( bool enable ); - -private: - enum { period2_mask = 0x1FFFF }; - - int period2_index() const { return regs [3] >> 4; } - int period2( int base = 8 ) const { return base << period2_index(); } - unsigned lfsr_mask() const { return (regs [3] & 0x08) ? ~0x4040 : ~0x4000; } -}; - -inline void Gb_Noise::set_volume_hack( bool enable ) { volume_hack = enable; } - -class Gb_Wave : public Gb_Osc { -public: - int sample_buf; // last wave RAM byte read (hardware has this as well) - - bool volume_hack; - - void write_register( int frame_phase, int reg, int old_data, int data ); - void run( blip_time_t, blip_time_t ); - - // Reads/writes wave RAM - int read( int addr ) const; - void write( int addr, int data ); - - void reset() - { - sample_buf = 0; - Gb_Osc::reset(); - volume_hack = false; - } - -private: - enum { bank40_mask = 0x40 }; - enum { bank_size = 32 }; - - int agb_mask; // 0xFF if AGB features enabled, 0 otherwise - BOOST::uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU - - friend class Gb_Apu; - - // Frequency timer period - int period() const { return (2048 - frequency()) * (2 * clk_mul); } - - // Non-zero if DAC is enabled - int dac_enabled() const { return regs [0] & 0x80; } - - void corrupt_wave(); - - void set_volume_hack( bool enable ); - - BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; } - - // Wave index that would be accessed, or -1 if no access would occur - int access( int addr ) const; -}; - -inline void Gb_Wave::set_volume_hack( bool enable ) { volume_hack = enable; } - -inline int Gb_Wave::read( int addr ) const -{ - int index = access( addr ); - return (index < 0 ? 0xFF : wave_bank() [index]); -} - -inline void Gb_Wave::write( int addr, int data ) -{ - int index = access( addr ); - if ( index >= 0 ) - wave_bank() [index] = data;; -} - -#endif +// Private oscillators used by Gb_Apu + +// Gb_Snd_Emu $vers +#ifndef GB_OSCS_H +#define GB_OSCS_H + +#include "blargg_common.h" +#include "Blip_Buffer.h" + +#ifndef GB_APU_OVERCLOCK + #define GB_APU_OVERCLOCK 1 +#endif + +#if GB_APU_OVERCLOCK & (GB_APU_OVERCLOCK - 1) + #error "GB_APU_OVERCLOCK must be a power of 2" +#endif + +class Gb_Osc { +protected: + + // 11-bit frequency in NRx3 and NRx4 + int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; } + + void update_amp( blip_time_t, int new_amp ); + int write_trig( int frame_phase, int max_len, int old_data ); +public: + + enum { clk_mul = GB_APU_OVERCLOCK }; + enum { dac_bias = 7 }; + + Blip_Buffer* outputs [4];// NULL, right, left, center + Blip_Buffer* output; // where to output sound + BOOST::uint8_t* regs; // osc's 5 registers + int mode; // mode_dmg, mode_cgb, mode_agb + int dac_off_amp;// amplitude when DAC is off + int last_amp; // current amplitude in Blip_Buffer + Blip_Synth_Norm const* norm_synth; + Blip_Synth_Fast const* fast_synth; + + int delay; // clocks until frequency timer expires + int length_ctr; // length counter + unsigned phase; // waveform phase (or equivalent) + bool enabled; // internal enabled flag + + void clock_length(); + void reset(); +}; + +class Gb_Env : public Gb_Osc { +public: + int env_delay; + int volume; + bool env_enabled; + + void clock_envelope(); + bool write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + env_delay = 0; + volume = 0; + Gb_Osc::reset(); + } +protected: + // Non-zero if DAC is enabled + int dac_enabled() const { return regs [2] & 0xF8; } +private: + void zombie_volume( int old, int data ); + int reload_env_timer(); +}; + +class Gb_Square : public Gb_Env { +public: + bool write_register( int frame_phase, int reg, int old_data, int data ); + void run( blip_time_t, blip_time_t ); + + void reset() + { + Gb_Env::reset(); + delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) + } +private: + // Frequency timer period + int period() const { return (2048 - frequency()) * (4 * clk_mul); } +}; + +class Gb_Sweep_Square : public Gb_Square { +public: + int sweep_freq; + int sweep_delay; + bool sweep_enabled; + bool sweep_neg; + + void clock_sweep(); + void write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + sweep_freq = 0; + sweep_delay = 0; + sweep_enabled = false; + sweep_neg = false; + Gb_Square::reset(); + } +private: + enum { period_mask = 0x70 }; + enum { shift_mask = 0x07 }; + + void calc_sweep( bool update ); + void reload_sweep_timer(); +}; + +class Gb_Noise : public Gb_Env { +public: + int divider; // noise has more complex frequency divider setup + + void run( blip_time_t, blip_time_t ); + void write_register( int frame_phase, int reg, int old_data, int data ); + + void reset() + { + divider = 0; + Gb_Env::reset(); + delay = 4 * clk_mul; // TODO: remove? + } + +private: + enum { period2_mask = 0x1FFFF }; + + int period2_index() const { return regs [3] >> 4; } + int period2( int base = 8 ) const { return base << period2_index(); } + unsigned lfsr_mask() const { return (regs [3] & 0x08) ? ~0x4040 : ~0x4000; } +}; + +class Gb_Wave : public Gb_Osc { +public: + int sample_buf; // last wave RAM byte read (hardware has this as well) + + void write_register( int frame_phase, int reg, int old_data, int data ); + void run( blip_time_t, blip_time_t ); + + // Reads/writes wave RAM + int read( int addr ) const; + void write( int addr, int data ); + + void reset() + { + sample_buf = 0; + Gb_Osc::reset(); + } + +private: + enum { bank40_mask = 0x40 }; + enum { bank_size = 32 }; + + int agb_mask; // 0xFF if AGB features enabled, 0 otherwise + BOOST::uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU + + friend class Gb_Apu; + + // Frequency timer period + int period() const { return (2048 - frequency()) * (2 * clk_mul); } + + // Non-zero if DAC is enabled + int dac_enabled() const { return regs [0] & 0x80; } + + void corrupt_wave(); + + BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; } + + // Wave index that would be accessed, or -1 if no access would occur + int access( int addr ) const; +}; + +inline int Gb_Wave::read( int addr ) const +{ + int index = access( addr ); + return (index < 0 ? 0xFF : wave_bank() [index]); +} + +inline void Gb_Wave::write( int addr, int data ) +{ + int index = access( addr ); + if ( index >= 0 ) + wave_bank() [index] = data;; +} + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gbs_Core.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gbs_Core.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gbs_Core.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gbs_Core.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -48,7 +48,7 @@ if ( !header_.valid_tag() ) return blargg_err_file_type; - if ( header_.vers != 1 ) + if ( header_.vers < 1 || header_.vers > 2 ) set_warning( "Unknown file version" ); if ( header_.timer_mode & 0x78 ) diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gbs_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gbs_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gbs_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gbs_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,167 +1,167 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Gbs_Emu.h" - -/* Copyright (C) 2003-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq = { -47.0, 2000, 0,0,0,0,0,0,0,0 }; -Gbs_Emu::equalizer_t const Gbs_Emu::cgb_eq = { 0.0, 300, 0,0,0,0,0,0,0,0 }; -Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = { 0.0, 30, 0,0,0,0,0,0,0,0 }; // DMG - -Gbs_Emu::Gbs_Emu() -{ - sound_hardware = sound_gbs; - enable_clicking( false ); - set_type( gme_gbs_type ); - set_silence_lookahead( 6 ); - set_max_initial_silence( 21 ); - set_gain( 1.2 ); - - // kind of midway between headphones and speaker - static equalizer_t const eq = { -1.0, 120, 0,0,0,0,0,0,0,0 }; - set_equalizer( eq ); -} - -Gbs_Emu::~Gbs_Emu() { } - -void Gbs_Emu::unload() -{ - core_.unload(); - Music_Emu::unload(); -} - -// Track info - -static void copy_gbs_fields( Gbs_Emu::header_t const& h, track_info_t* out ) -{ - GME_COPY_FIELD( h, out, game ); - GME_COPY_FIELD( h, out, author ); - GME_COPY_FIELD( h, out, copyright ); -} - -static void hash_gbs_file( Gbs_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( &h.vers, sizeof(h.vers) ); - out.hash_( &h.track_count, sizeof(h.track_count) ); - out.hash_( &h.first_track, sizeof(h.first_track) ); - out.hash_( &h.load_addr[0], sizeof(h.load_addr) ); - out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); - out.hash_( &h.play_addr[0], sizeof(h.play_addr) ); - out.hash_( &h.stack_ptr[0], sizeof(h.stack_ptr) ); - out.hash_( &h.timer_modulo, sizeof(h.timer_modulo) ); - out.hash_( &h.timer_mode, sizeof(h.timer_mode) ); - out.hash_( data, data_size ); -} - -blargg_err_t Gbs_Emu::track_info_( track_info_t* out, int ) const -{ - copy_gbs_fields( header(), out ); - return blargg_ok; -} - -struct Gbs_File : Gme_Info_ -{ - Gbs_Emu::header_t const* h; - - Gbs_File() { set_type( gme_gbs_type ); } - - blargg_err_t load_mem_( byte const begin [], int size ) - { - h = ( Gbs_Emu::header_t * ) begin; - - set_track_count( h->track_count ); - if ( !h->valid_tag() ) - return blargg_err_file_type; - - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_gbs_fields( Gbs_Emu::header_t( *h ), out ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_gbs_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out ); - return blargg_ok; - } -}; - -static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; } -static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; } - -gme_type_t_ const gme_gbs_type [1] = {{ "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 }}; - -// Setup - -blargg_err_t Gbs_Emu::load_( Data_Reader& in ) -{ - RETURN_ERR( core_.load( in ) ); - set_warning( core_.warning() ); - set_track_count( header().track_count ); - set_voice_count( Gb_Apu::osc_count ); - core_.apu().volume( gain() ); - - static const char* const names [Gb_Apu::osc_count] = { - "Square 1", "Square 2", "Wave", "Noise" - }; - set_voice_names( names ); - - static int const types [Gb_Apu::osc_count] = { - wave_type+1, wave_type+2, wave_type+3, mixed_type+1 - }; - set_voice_types( types ); - - return setup_buffer( 4194304 ); -} - -void Gbs_Emu::update_eq( blip_eq_t const& eq ) -{ - core_.apu().treble_eq( eq ); -} - -void Gbs_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) -{ - core_.apu().set_output( i, c, l, r ); -} - -void Gbs_Emu::set_tempo_( double t ) -{ - core_.set_tempo( t ); -} - -blargg_err_t Gbs_Emu::start_track_( int track ) -{ - sound_t mode = sound_hardware; - if ( mode == sound_gbs ) - mode = (header().timer_mode & 0x80) ? sound_cgb : sound_dmg; - - RETURN_ERR( core_.start_track( track, (Gb_Apu::mode_t) mode ) ); - - // clear buffer AFTER track is started, eliminating initial click - return Classic_Emu::start_track_( track ); -} - -blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int ) -{ - return core_.end_frame( duration ); -} - -blargg_err_t Gbs_Emu::hash_( Hash_Function& out ) const -{ - hash_gbs_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out ); - return blargg_ok; +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Gbs_Emu.h" + +/* Copyright (C) 2003-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq = { -47.0, 2000, 0,0,0,0,0,0,0,0 }; +Gbs_Emu::equalizer_t const Gbs_Emu::cgb_eq = { 0.0, 300, 0,0,0,0,0,0,0,0 }; +Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = { 0.0, 30, 0,0,0,0,0,0,0,0 }; // DMG + +Gbs_Emu::Gbs_Emu() +{ + sound_hardware = sound_gbs; + enable_clicking( false ); + set_type( gme_gbs_type ); + set_silence_lookahead( 6 ); + set_max_initial_silence( 21 ); + set_gain( 1.2 ); + + // kind of midway between headphones and speaker + static equalizer_t const eq = { -1.0, 120, 0,0,0,0,0,0,0,0 }; + set_equalizer( eq ); +} + +Gbs_Emu::~Gbs_Emu() { } + +void Gbs_Emu::unload() +{ + core_.unload(); + Music_Emu::unload(); +} + +// Track info + +static void copy_gbs_fields( Gbs_Emu::header_t const& h, track_info_t* out ) +{ + GME_COPY_FIELD( h, out, game ); + GME_COPY_FIELD( h, out, author ); + GME_COPY_FIELD( h, out, copyright ); +} + +static void hash_gbs_file( Gbs_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( &h.vers, sizeof(h.vers) ); + out.hash_( &h.track_count, sizeof(h.track_count) ); + out.hash_( &h.first_track, sizeof(h.first_track) ); + out.hash_( &h.load_addr[0], sizeof(h.load_addr) ); + out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); + out.hash_( &h.play_addr[0], sizeof(h.play_addr) ); + out.hash_( &h.stack_ptr[0], sizeof(h.stack_ptr) ); + out.hash_( &h.timer_modulo, sizeof(h.timer_modulo) ); + out.hash_( &h.timer_mode, sizeof(h.timer_mode) ); + out.hash_( data, data_size ); +} + +blargg_err_t Gbs_Emu::track_info_( track_info_t* out, int ) const +{ + copy_gbs_fields( header(), out ); + return blargg_ok; +} + +struct Gbs_File : Gme_Info_ +{ + Gbs_Emu::header_t const* h; + + Gbs_File() { set_type( gme_gbs_type ); } + + blargg_err_t load_mem_( byte const begin [], int size ) + { + h = ( Gbs_Emu::header_t * ) begin; + + set_track_count( h->track_count ); + if ( !h->valid_tag() ) + return blargg_err_file_type; + + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + copy_gbs_fields( Gbs_Emu::header_t( *h ), out ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_gbs_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out ); + return blargg_ok; + } +}; + +static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; } +static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; } + +gme_type_t_ const gme_gbs_type [1] = {{ "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 }}; + +// Setup + +blargg_err_t Gbs_Emu::load_( Data_Reader& in ) +{ + RETURN_ERR( core_.load( in ) ); + set_warning( core_.warning() ); + set_track_count( header().track_count ); + set_voice_count( Gb_Apu::osc_count ); + core_.apu().volume( gain() ); + + static const char* const names [Gb_Apu::osc_count] = { + "Square 1", "Square 2", "Wave", "Noise" + }; + set_voice_names( names ); + + static int const types [Gb_Apu::osc_count] = { + wave_type+1, wave_type+2, wave_type+3, mixed_type+1 + }; + set_voice_types( types ); + + return setup_buffer( 4194304 ); +} + +void Gbs_Emu::update_eq( blip_eq_t const& eq ) +{ + core_.apu().treble_eq( eq ); +} + +void Gbs_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) +{ + core_.apu().set_output( i, c, l, r ); +} + +void Gbs_Emu::set_tempo_( double t ) +{ + core_.set_tempo( t ); +} + +blargg_err_t Gbs_Emu::start_track_( int track ) +{ + sound_t mode = sound_hardware; + if ( mode == sound_gbs ) + mode = (header().timer_mode & 0x80) ? sound_cgb : sound_dmg; + + RETURN_ERR( core_.start_track( track, (Gb_Apu::mode_t) mode ) ); + + // clear buffer AFTER track is started, eliminating initial click + return Classic_Emu::start_track_( track ); +} + +blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int ) +{ + return core_.end_frame( duration ); +} + +blargg_err_t Gbs_Emu::hash_( Hash_Function& out ) const +{ + hash_gbs_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out ); + return blargg_ok; } \ No newline at end of file diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,468 +1,469 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Music_Emu.h" - -#if !GME_DISABLE_EFFECTS -#include "Effects_Buffer.h" -#endif -#include "blargg_endian.h" -#include -#include - -/* Copyright (C) 2003-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#ifndef GME_TYPE_LIST - -// Default list of all supported game music types (copy this to blargg_config.h -// if you want to modify it) -#define GME_TYPE_LIST \ - gme_ay_type,\ - gme_gbs_type,\ - gme_gym_type,\ - gme_hes_type,\ - gme_kss_type,\ - gme_nsf_type,\ - gme_nsfe_type,\ - gme_sap_type,\ - gme_sfm_type,\ - gme_sgc_type,\ - gme_spc_type,\ - gme_vgm_type,\ - gme_vgz_type - -#endif - -static gme_type_t const gme_type_list_ [] = { GME_TYPE_LIST, 0 }; - -gme_type_t const* gme_type_list() -{ - return gme_type_list_; -} - -const char* gme_identify_header( void const* header ) -{ - switch ( get_be32( header ) ) - { - case BLARGG_4CHAR('Z','X','A','Y'): return "AY"; - case BLARGG_4CHAR('G','B','S',0x01): return "GBS"; - case BLARGG_4CHAR('G','Y','M','X'): return "GYM"; - case BLARGG_4CHAR('H','E','S','M'): return "HES"; - case BLARGG_4CHAR('K','S','C','C'): - case BLARGG_4CHAR('K','S','S','X'): return "KSS"; - case BLARGG_4CHAR('N','E','S','M'): return "NSF"; - case BLARGG_4CHAR('N','S','F','E'): return "NSFE"; - case BLARGG_4CHAR('S','A','P',0x0D): return "SAP"; - case BLARGG_4CHAR('S','F','M','1'): return "SFM"; - case BLARGG_4CHAR('S','G','C',0x1A): return "SGC"; - case BLARGG_4CHAR('S','N','E','S'): return "SPC"; - case BLARGG_4CHAR('V','g','m',' '): return "VGM"; - } - return ""; -} - -static void to_uppercase( const char in [], int len, char out [] ) -{ - for ( int i = 0; i < len; i++ ) - { - if ( !(out [i] = toupper( in [i] )) ) - return; - } - *out = 0; // extension too long -} - -gme_type_t gme_identify_extension( const char extension_ [] ) -{ - char const* end = strrchr( extension_, '.' ); - if ( end ) - extension_ = end + 1; - - char extension [6]; - to_uppercase( extension_, sizeof extension, extension ); - - gme_type_t const* types = gme_type_list_; - for ( ; *types; types++ ) - if ( !strcmp( extension, (*types)->extension_ ) ) - break; - return *types; -} - -gme_err_t gme_identify_file( const char path [], gme_type_t* type_out ) -{ - *type_out = gme_identify_extension( path ); - // TODO: don't examine header if file has extension? - if ( !*type_out ) - { - char header [4]; - GME_FILE_READER in; - RETURN_ERR( in.open( path ) ); - RETURN_ERR( in.read( header, sizeof header ) ); - *type_out = gme_identify_extension( gme_identify_header( header ) ); - } - return blargg_ok; -} - -gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate ) -{ - require( (data || !size) && out ); - *out = NULL; - - gme_type_t file_type = 0; - if ( size >= 4 ) - file_type = gme_identify_extension( gme_identify_header( data ) ); - if ( !file_type ) - return blargg_err_file_type; - - Music_Emu* emu = gme_new_emu( file_type, sample_rate ); - CHECK_ALLOC( emu ); - - gme_err_t err = gme_load_data( emu, data, size ); - - if ( err ) - delete emu; - else - *out = emu; - - return err; -} - -gme_err_t gme_open_file( const char path [], Music_Emu** out, int sample_rate ) -{ - require( path && out ); - *out = NULL; - - GME_FILE_READER in; - RETURN_ERR( in.open( path ) ); - - char header [4]; - int header_size = 0; - - gme_type_t file_type = gme_identify_extension( path ); - if ( !file_type ) - { - header_size = sizeof header; - RETURN_ERR( in.read( header, sizeof header ) ); - file_type = gme_identify_extension( gme_identify_header( header ) ); - } - if ( !file_type ) - return blargg_err_file_type; - - Music_Emu* emu = gme_new_emu( file_type, sample_rate ); - CHECK_ALLOC( emu ); - - // optimization: avoids seeking/re-reading header - Remaining_Reader rem( header, header_size, &in ); - gme_err_t err = emu->load( rem ); - in.close(); - - if ( err ) - delete emu; - else - *out = emu; - - return err; -} - -Music_Emu* gme_new_emu( gme_type_t type, int rate ) -{ - if ( type ) - { - if ( rate == gme_info_only ) - return type->new_info(); - - Music_Emu* gme = type->new_emu(); - if ( gme ) - { - #if !GME_DISABLE_EFFECTS - if ( type->flags_ & 1 ) - { - gme->effects_buffer_ = BLARGG_NEW Simple_Effects_Buffer; - if ( gme->effects_buffer_ ) - gme->set_buffer( gme->effects_buffer_ ); - } - - if ( !(type->flags_ & 1) || gme->effects_buffer_ ) - #endif - { - if ( !gme->set_sample_rate( rate ) ) - { - check( gme->type() == type ); - return gme; - } - } - delete gme; - } - } - return NULL; -} - -gme_err_t gme_load_file( Music_Emu* gme, const char path [] ) { return gme->load_file( path ); } - -gme_err_t gme_load_data( Music_Emu* gme, void const* data, long size ) -{ - Mem_File_Reader in( data, size ); - return gme->load( in ); -} - -gme_err_t gme_load_custom( Music_Emu* gme, gme_reader_t func, long size, void* data ) -{ - Callback_Reader in( func, size, data ); - return gme->load( in ); -} - -void gme_delete( Music_Emu* gme ) { delete gme; } - -gme_type_t gme_type( Music_Emu const* gme ) { return gme->type(); } - -const char* gme_type_system( gme_type_t_ const* type ) { return type->system; } - -const char* gme_warning( Music_Emu* gme ) { return gme->warning(); } - -int gme_track_count( Music_Emu const* gme ) { return gme->track_count(); } - -struct gme_info_t_ : gme_info_t -{ - track_info_t info; - - BLARGG_DISABLE_NOTHROW -}; - -gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track ) -{ - *out = NULL; - - gme_info_t_* info = BLARGG_NEW gme_info_t_; - CHECK_ALLOC( info ); - - gme_err_t err = me->track_info( &info->info, track ); - if ( err ) - { - gme_free_info( info ); - return err; - } - - #define COPY(name) info->name = info->info.name; - - COPY( length ); - COPY( intro_length ); - COPY( loop_length ); - - info->i4 = -1; - info->i5 = -1; - info->i6 = -1; - info->i7 = -1; - info->i8 = -1; - info->i9 = -1; - info->i10 = -1; - info->i11 = -1; - info->i12 = -1; - info->i13 = -1; - info->i14 = -1; - info->i15 = -1; - - info->s7 = ""; - info->s8 = ""; - info->s9 = ""; - info->s10 = ""; - info->s11 = ""; - info->s12 = ""; - info->s13 = ""; - info->s14 = ""; - info->s15 = ""; - - COPY( system ); - COPY( game ); - COPY( song ); - COPY( author ); - COPY( copyright ); - COPY( comment ); - COPY( dumper ); - - #undef COPY - - info->play_length = info->length; - if ( info->play_length <= 0 ) - { - info->play_length = info->intro_length + 2 * info->loop_length; // intro + 2 loops - if ( info->play_length <= 0 ) - info->play_length = 150 * 1000; // 2.5 minutes - } - - *out = info; - - return blargg_ok; -} - -gme_err_t gme_set_track_info( Music_Emu * me, gme_info_t* in, int track ) -{ - track_info_t* info = BLARGG_NEW track_info_t; - CHECK_ALLOC( info ); - -#define COPY(name) info->name = in->name; - - COPY( length ); - COPY( intro_length ); - COPY( loop_length ); - -#undef COPY -#define COPY(name) if ( in->name ) strncpy( info->name, in->name, sizeof(info->name) - 1 ), info->name[sizeof(info->name)-1] = '\0'; else info->name[0] = '\0'; - - COPY( system ); - COPY( game ); - COPY( song ); - COPY( author ); - COPY( copyright ); - COPY( comment ); - COPY( dumper ); - -#undef COPY - - blargg_err_t err = me->set_track_info( info, track ); - - delete info; - - return err; -} - -void gme_free_info( gme_info_t* info ) -{ - delete STATIC_CAST(gme_info_t_*,info); -} - -void* gme_user_data ( Music_Emu const* gme ) { return gme->user_data(); } -void gme_set_user_data ( Music_Emu* gme, void* new_user_data ) { gme->set_user_data( new_user_data ); } -void gme_set_user_cleanup(Music_Emu* gme, gme_user_cleanup_t func ){ gme->set_user_cleanup( func ); } - -gme_err_t gme_start_track ( Music_Emu* gme, int index ) { return gme->start_track( index ); } -gme_err_t gme_play ( Music_Emu* gme, int n, short p [] ) { return gme->play( n, p ); } -void gme_set_fade ( Music_Emu* gme, int start_msec, int length_msec ) { gme->set_fade( start_msec, length_msec ); } -gme_bool gme_track_ended ( Music_Emu const* gme ) { return gme->track_ended(); } -int gme_tell ( Music_Emu const* gme ) { return gme->tell(); } -gme_err_t gme_seek ( Music_Emu* gme, int msec ) { return gme->seek( msec ); } -gme_err_t gme_skip ( Music_Emu* gme, int samples ) { return gme->skip( samples ); } -int gme_voice_count ( Music_Emu const* gme ) { return gme->voice_count(); } -void gme_ignore_silence ( Music_Emu* gme, gme_bool disable ) { gme->ignore_silence( disable != 0 ); } -void gme_set_tempo ( Music_Emu* gme, double t ) { gme->set_tempo( t ); } -void gme_mute_voice ( Music_Emu* gme, int index, gme_bool mute ){ gme->mute_voice( index, mute != 0 ); } -void gme_mute_voices ( Music_Emu* gme, int mask ) { gme->mute_voices( mask ); } -void gme_set_equalizer ( Music_Emu* gme, gme_equalizer_t const* eq ) { gme->set_equalizer( *eq ); } -void gme_equalizer ( Music_Emu const* gme, gme_equalizer_t* o ) { *o = gme->equalizer(); } -const char* gme_voice_name ( Music_Emu const* gme, int i ) { return gme->voice_name( i ); } -gme_err_t gme_save ( Music_Emu const* gme, gme_writer_t writer, void* your_data ) { return gme->save( writer, your_data ); } - -void gme_effects( Music_Emu const* gme, gme_effects_t* out ) -{ - static gme_effects_t const zero = { 0, 0, 0,0,0,0,0,0, 0, 0, 0,0,0,0,0,0 }; - *out = zero; - - #if !GME_DISABLE_EFFECTS - { - Simple_Effects_Buffer* b = STATIC_CAST(Simple_Effects_Buffer*,gme->effects_buffer_); - if ( b ) - { - out->enabled = b->config().enabled; - out->echo = b->config().echo; - out->stereo = b->config().stereo; - out->surround = b->config().surround; - } - } - #endif -} - -void gme_set_effects( Music_Emu* gme, gme_effects_t const* in ) -{ - #if !GME_DISABLE_EFFECTS - { - Simple_Effects_Buffer* b = STATIC_CAST(Simple_Effects_Buffer*,gme->effects_buffer_); - if ( b ) - { - b->config().enabled = false; - if ( in ) - { - b->config().enabled = in->enabled; - b->config().echo = in->echo; - b->config().stereo = in->stereo; - b->config().surround = in->surround; - } - b->apply_config(); - } - } - #endif -} - -void gme_set_stereo_depth( Music_Emu* gme, double depth ) -{ - #if !GME_DISABLE_EFFECTS - { - if ( gme->effects_buffer_ ) - { - gme_effects_t cfg; - gme_effects( gme, &cfg ); - cfg.enabled = (depth > 0.0); - cfg.echo = depth; - cfg.stereo = depth; - cfg.surround = true; - gme_set_effects( gme, &cfg ); - } - } - #endif -} - -#define ENTRY( name ) { blargg_err_##name, gme_err_##name } -static blargg_err_to_code_t const gme_codes [] = -{ - ENTRY( generic ), - ENTRY( memory ), - ENTRY( caller ), - ENTRY( internal ), - ENTRY( limitation ), - - ENTRY( file_missing ), - ENTRY( file_read ), - ENTRY( file_io ), - ENTRY( file_eof ), - - ENTRY( file_type ), - ENTRY( file_feature ), - ENTRY( file_corrupt ), - - { 0, -1 } -}; -#undef ENTRY - -static int err_code( gme_err_t err ) -{ - return blargg_err_to_code( err, gme_codes ); -} - -int gme_err_code( gme_err_t err ) -{ - int code = err_code( err ); - return (code >= 0 ? code : gme_err_generic); -} - -gme_err_t gme_code_to_err( int code ) -{ - return blargg_code_to_err( code, gme_codes ); -} - -const char* gme_err_details( gme_err_t err ) -{ - // If we don't have error code assigned, return entire string - return (err_code( err ) >= 0 ? blargg_err_details( err ) : blargg_err_str( err )); -} - -const char* gme_err_str( gme_err_t err ) -{ - return blargg_err_str( err ); -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Music_Emu.h" + +#if !GME_DISABLE_EFFECTS +#include "Effects_Buffer.h" +#endif +#include "blargg_endian.h" +#include +#include + +/* Copyright (C) 2003-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#ifndef GME_TYPE_LIST + +// Default list of all supported game music types (copy this to blargg_config.h +// if you want to modify it) +#define GME_TYPE_LIST \ + gme_ay_type,\ + gme_gbs_type,\ + gme_gym_type,\ + gme_hes_type,\ + gme_kss_type,\ + gme_nsf_type,\ + gme_nsfe_type,\ + gme_sap_type,\ + gme_sfm_type,\ + gme_sgc_type,\ + gme_spc_type,\ + gme_vgm_type,\ + gme_vgz_type + +#endif + +static gme_type_t const gme_type_list_ [] = { GME_TYPE_LIST, 0 }; + +gme_type_t const* gme_type_list() +{ + return gme_type_list_; +} + +const char* gme_identify_header( void const* header ) +{ + switch ( get_be32( header ) ) + { + case BLARGG_4CHAR('Z','X','A','Y'): return "AY"; + case BLARGG_4CHAR('G','B','S',0x01): + case BLARGG_4CHAR('G','B','S',0x02): return "GBS"; + case BLARGG_4CHAR('G','Y','M','X'): return "GYM"; + case BLARGG_4CHAR('H','E','S','M'): return "HES"; + case BLARGG_4CHAR('K','S','C','C'): + case BLARGG_4CHAR('K','S','S','X'): return "KSS"; + case BLARGG_4CHAR('N','E','S','M'): return "NSF"; + case BLARGG_4CHAR('N','S','F','E'): return "NSFE"; + case BLARGG_4CHAR('S','A','P',0x0D): return "SAP"; + case BLARGG_4CHAR('S','F','M','1'): return "SFM"; + case BLARGG_4CHAR('S','G','C',0x1A): return "SGC"; + case BLARGG_4CHAR('S','N','E','S'): return "SPC"; + case BLARGG_4CHAR('V','g','m',' '): return "VGM"; + } + return ""; +} + +static void to_uppercase( const char in [], int len, char out [] ) +{ + for ( int i = 0; i < len; i++ ) + { + if ( !(out [i] = toupper( in [i] )) ) + return; + } + *out = 0; // extension too long +} + +gme_type_t gme_identify_extension( const char extension_ [] ) +{ + char const* end = strrchr( extension_, '.' ); + if ( end ) + extension_ = end + 1; + + char extension [6]; + to_uppercase( extension_, sizeof extension, extension ); + + gme_type_t const* types = gme_type_list_; + for ( ; *types; types++ ) + if ( !strcmp( extension, (*types)->extension_ ) ) + break; + return *types; +} + +gme_err_t gme_identify_file( const char path [], gme_type_t* type_out ) +{ + *type_out = gme_identify_extension( path ); + // TODO: don't examine header if file has extension? + if ( !*type_out ) + { + char header [4]; + GME_FILE_READER in; + RETURN_ERR( in.open( path ) ); + RETURN_ERR( in.read( header, sizeof header ) ); + *type_out = gme_identify_extension( gme_identify_header( header ) ); + } + return blargg_ok; +} + +gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate ) +{ + require( (data || !size) && out ); + *out = NULL; + + gme_type_t file_type = 0; + if ( size >= 4 ) + file_type = gme_identify_extension( gme_identify_header( data ) ); + if ( !file_type ) + return blargg_err_file_type; + + Music_Emu* emu = gme_new_emu( file_type, sample_rate ); + CHECK_ALLOC( emu ); + + gme_err_t err = gme_load_data( emu, data, size ); + + if ( err ) + delete emu; + else + *out = emu; + + return err; +} + +gme_err_t gme_open_file( const char path [], Music_Emu** out, int sample_rate ) +{ + require( path && out ); + *out = NULL; + + GME_FILE_READER in; + RETURN_ERR( in.open( path ) ); + + char header [4]; + int header_size = 0; + + gme_type_t file_type = gme_identify_extension( path ); + if ( !file_type ) + { + header_size = sizeof header; + RETURN_ERR( in.read( header, sizeof header ) ); + file_type = gme_identify_extension( gme_identify_header( header ) ); + } + if ( !file_type ) + return blargg_err_file_type; + + Music_Emu* emu = gme_new_emu( file_type, sample_rate ); + CHECK_ALLOC( emu ); + + // optimization: avoids seeking/re-reading header + Remaining_Reader rem( header, header_size, &in ); + gme_err_t err = emu->load( rem ); + in.close(); + + if ( err ) + delete emu; + else + *out = emu; + + return err; +} + +Music_Emu* gme_new_emu( gme_type_t type, int rate ) +{ + if ( type ) + { + if ( rate == gme_info_only ) + return type->new_info(); + + Music_Emu* gme = type->new_emu(); + if ( gme ) + { + #if !GME_DISABLE_EFFECTS + if ( type->flags_ & 1 ) + { + gme->effects_buffer_ = BLARGG_NEW Simple_Effects_Buffer; + if ( gme->effects_buffer_ ) + gme->set_buffer( gme->effects_buffer_ ); + } + + if ( !(type->flags_ & 1) || gme->effects_buffer_ ) + #endif + { + if ( !gme->set_sample_rate( rate ) ) + { + check( gme->type() == type ); + return gme; + } + } + delete gme; + } + } + return NULL; +} + +gme_err_t gme_load_file( Music_Emu* gme, const char path [] ) { return gme->load_file( path ); } + +gme_err_t gme_load_data( Music_Emu* gme, void const* data, long size ) +{ + Mem_File_Reader in( data, size ); + return gme->load( in ); +} + +gme_err_t gme_load_custom( Music_Emu* gme, gme_reader_t func, long size, void* data ) +{ + Callback_Reader in( func, size, data ); + return gme->load( in ); +} + +void gme_delete( Music_Emu* gme ) { delete gme; } + +gme_type_t gme_type( Music_Emu const* gme ) { return gme->type(); } + +const char* gme_type_system( gme_type_t_ const* type ) { return type->system; } + +const char* gme_warning( Music_Emu* gme ) { return gme->warning(); } + +int gme_track_count( Music_Emu const* gme ) { return gme->track_count(); } + +struct gme_info_t_ : gme_info_t +{ + track_info_t info; + + BLARGG_DISABLE_NOTHROW +}; + +gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track ) +{ + *out = NULL; + + gme_info_t_* info = BLARGG_NEW gme_info_t_; + CHECK_ALLOC( info ); + + gme_err_t err = me->track_info( &info->info, track ); + if ( err ) + { + gme_free_info( info ); + return err; + } + + #define COPY(name) info->name = info->info.name; + + COPY( length ); + COPY( intro_length ); + COPY( loop_length ); + + info->i4 = -1; + info->i5 = -1; + info->i6 = -1; + info->i7 = -1; + info->i8 = -1; + info->i9 = -1; + info->i10 = -1; + info->i11 = -1; + info->i12 = -1; + info->i13 = -1; + info->i14 = -1; + info->i15 = -1; + + info->s7 = ""; + info->s8 = ""; + info->s9 = ""; + info->s10 = ""; + info->s11 = ""; + info->s12 = ""; + info->s13 = ""; + info->s14 = ""; + info->s15 = ""; + + COPY( system ); + COPY( game ); + COPY( song ); + COPY( author ); + COPY( copyright ); + COPY( comment ); + COPY( dumper ); + + #undef COPY + + info->play_length = info->length; + if ( info->play_length <= 0 ) + { + info->play_length = info->intro_length + 2 * info->loop_length; // intro + 2 loops + if ( info->play_length <= 0 ) + info->play_length = 150 * 1000; // 2.5 minutes + } + + *out = info; + + return blargg_ok; +} + +gme_err_t gme_set_track_info( Music_Emu * me, gme_info_t* in, int track ) +{ + track_info_t* info = BLARGG_NEW track_info_t; + CHECK_ALLOC( info ); + +#define COPY(name) info->name = in->name; + + COPY( length ); + COPY( intro_length ); + COPY( loop_length ); + +#undef COPY +#define COPY(name) if ( in->name ) strncpy( info->name, in->name, sizeof(info->name) - 1 ), info->name[sizeof(info->name)-1] = '\0'; else info->name[0] = '\0'; + + COPY( system ); + COPY( game ); + COPY( song ); + COPY( author ); + COPY( copyright ); + COPY( comment ); + COPY( dumper ); + +#undef COPY + + blargg_err_t err = me->set_track_info( info, track ); + + delete info; + + return err; +} + +void gme_free_info( gme_info_t* info ) +{ + delete STATIC_CAST(gme_info_t_*,info); +} + +void* gme_user_data ( Music_Emu const* gme ) { return gme->user_data(); } +void gme_set_user_data ( Music_Emu* gme, void* new_user_data ) { gme->set_user_data( new_user_data ); } +void gme_set_user_cleanup(Music_Emu* gme, gme_user_cleanup_t func ){ gme->set_user_cleanup( func ); } + +gme_err_t gme_start_track ( Music_Emu* gme, int index ) { return gme->start_track( index ); } +gme_err_t gme_play ( Music_Emu* gme, int n, short p [] ) { return gme->play( n, p ); } +void gme_set_fade ( Music_Emu* gme, int start_msec, int length_msec ) { gme->set_fade( start_msec, length_msec ); } +gme_bool gme_track_ended ( Music_Emu const* gme ) { return gme->track_ended(); } +int gme_tell ( Music_Emu const* gme ) { return gme->tell(); } +gme_err_t gme_seek ( Music_Emu* gme, int msec ) { return gme->seek( msec ); } +gme_err_t gme_skip ( Music_Emu* gme, int samples ) { return gme->skip( samples ); } +int gme_voice_count ( Music_Emu const* gme ) { return gme->voice_count(); } +void gme_ignore_silence ( Music_Emu* gme, gme_bool disable ) { gme->ignore_silence( disable != 0 ); } +void gme_set_tempo ( Music_Emu* gme, double t ) { gme->set_tempo( t ); } +void gme_mute_voice ( Music_Emu* gme, int index, gme_bool mute ){ gme->mute_voice( index, mute != 0 ); } +void gme_mute_voices ( Music_Emu* gme, int mask ) { gme->mute_voices( mask ); } +void gme_set_equalizer ( Music_Emu* gme, gme_equalizer_t const* eq ) { gme->set_equalizer( *eq ); } +void gme_equalizer ( Music_Emu const* gme, gme_equalizer_t* o ) { *o = gme->equalizer(); } +const char* gme_voice_name ( Music_Emu const* gme, int i ) { return gme->voice_name( i ); } +gme_err_t gme_save ( Music_Emu const* gme, gme_writer_t writer, void* your_data ) { return gme->save( writer, your_data ); } + +void gme_effects( Music_Emu const* gme, gme_effects_t* out ) +{ + static gme_effects_t const zero = { 0, 0, 0,0,0,0,0,0, 0, 0, 0,0,0,0,0,0 }; + *out = zero; + + #if !GME_DISABLE_EFFECTS + { + Simple_Effects_Buffer* b = STATIC_CAST(Simple_Effects_Buffer*,gme->effects_buffer_); + if ( b ) + { + out->enabled = b->config().enabled; + out->echo = b->config().echo; + out->stereo = b->config().stereo; + out->surround = b->config().surround; + } + } + #endif +} + +void gme_set_effects( Music_Emu* gme, gme_effects_t const* in ) +{ + #if !GME_DISABLE_EFFECTS + { + Simple_Effects_Buffer* b = STATIC_CAST(Simple_Effects_Buffer*,gme->effects_buffer_); + if ( b ) + { + b->config().enabled = false; + if ( in ) + { + b->config().enabled = in->enabled; + b->config().echo = in->echo; + b->config().stereo = in->stereo; + b->config().surround = in->surround; + } + b->apply_config(); + } + } + #endif +} + +void gme_set_stereo_depth( Music_Emu* gme, double depth ) +{ + #if !GME_DISABLE_EFFECTS + { + if ( gme->effects_buffer_ ) + { + gme_effects_t cfg; + gme_effects( gme, &cfg ); + cfg.enabled = (depth > 0.0); + cfg.echo = depth; + cfg.stereo = depth; + cfg.surround = true; + gme_set_effects( gme, &cfg ); + } + } + #endif +} + +#define ENTRY( name ) { blargg_err_##name, gme_err_##name } +static blargg_err_to_code_t const gme_codes [] = +{ + ENTRY( generic ), + ENTRY( memory ), + ENTRY( caller ), + ENTRY( internal ), + ENTRY( limitation ), + + ENTRY( file_missing ), + ENTRY( file_read ), + ENTRY( file_io ), + ENTRY( file_eof ), + + ENTRY( file_type ), + ENTRY( file_feature ), + ENTRY( file_corrupt ), + + { 0, -1 } +}; +#undef ENTRY + +static int err_code( gme_err_t err ) +{ + return blargg_err_to_code( err, gme_codes ); +} + +int gme_err_code( gme_err_t err ) +{ + int code = err_code( err ); + return (code >= 0 ? code : gme_err_generic); +} + +gme_err_t gme_code_to_err( int code ) +{ + return blargg_code_to_err( code, gme_codes ); +} + +const char* gme_err_details( gme_err_t err ) +{ + // If we don't have error code assigned, return entire string + return (err_code( err ) >= 0 ? blargg_err_details( err ) : blargg_err_str( err )); +} + +const char* gme_err_str( gme_err_t err ) +{ + return blargg_err_str( err ); +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme_custom_dprintf.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme_custom_dprintf.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme_custom_dprintf.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme_custom_dprintf.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,4 +1,4 @@ -#include "gme_custom_dprintf.h" - - -gme_custom_dprintf_callback gme_custom_dprintf = 0; +#include "gme_custom_dprintf.h" + + +gme_custom_dprintf_callback gme_custom_dprintf = 0; diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme_custom_dprintf.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme_custom_dprintf.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme_custom_dprintf.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme_custom_dprintf.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,28 +1,28 @@ -#ifndef GME_CUSTOM_DPRINTF_H -#define GME_CUSTOM_DPRINTF_H - - -#ifdef CUSTOM_DPRINTF_FUNCTION - - -#include - - -#ifdef _cplusplus -extern "C" { -#endif - - -typedef void (*gme_custom_dprintf_callback)( const char * fmt, va_list vl ); -extern gme_custom_dprintf_callback gme_custom_dprintf; - - -#ifdef _cplusplus -} -#endif - - -#endif - - -#endif +#ifndef GME_CUSTOM_DPRINTF_H +#define GME_CUSTOM_DPRINTF_H + + +#ifdef CUSTOM_DPRINTF_FUNCTION + + +#include + + +#ifdef _cplusplus +extern "C" { +#endif + + +typedef void (*gme_custom_dprintf_callback)( const char * fmt, va_list vl ); +extern gme_custom_dprintf_callback gme_custom_dprintf; + + +#ifdef _cplusplus +} +#endif + + +#endif + + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gme_File.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gme_File.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gme_File.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gme_File.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,183 +1,183 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Gme_File.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -void Gme_File::unload() -{ - clear_playlist(); // BEFORE clearing track count - track_count_ = 0; - raw_track_count_ = 0; - Gme_Loader::unload(); -} - -Gme_File::Gme_File() -{ - type_ = NULL; - user_data_ = NULL; - user_cleanup_ = NULL; - Gme_File::unload(); // clears fields -} - -Gme_File::~Gme_File() -{ - if ( user_cleanup_ ) - user_cleanup_( user_data_ ); -} - -blargg_err_t Gme_File::post_load() -{ - if ( !track_count() ) - set_track_count( type()->track_count ); - return Gme_Loader::post_load(); -} - -void Gme_File::clear_playlist() -{ - playlist.clear(); - clear_playlist_(); - track_count_ = raw_track_count_; -} - -void Gme_File::copy_field_( char out [], const char* in, int in_size ) -{ - if ( !in || !*in ) - return; - - // remove spaces/junk from beginning - while ( in_size && unsigned (*in - 1) <= ' ' - 1 ) - { - in++; - in_size--; - } - - // truncate - if ( in_size > max_field_ ) - in_size = max_field_; - - // find terminator - int len = 0; - while ( len < in_size && in [len] ) - len++; - - // remove spaces/junk from end - while ( len && unsigned (in [len - 1]) <= ' ' ) - len--; - - // copy - out [len] = 0; - memcpy( out, in, len ); - - // strip out stupid fields that should have been left blank - if ( !strcmp( out, "?" ) || !strcmp( out, "" ) || !strcmp( out, "< ? >" ) ) - out [0] = 0; -} - -void Gme_File::copy_field_( char out [], const char* in ) -{ - copy_field_( out, in, max_field_ ); -} - -blargg_err_t Gme_File::remap_track_( int* track_io ) const -{ - if ( (unsigned) *track_io >= (unsigned) track_count() ) - return BLARGG_ERR( BLARGG_ERR_CALLER, "invalid track" ); - - if ( (unsigned) *track_io < (unsigned) playlist.size() ) - { - M3u_Playlist::entry_t const& e = playlist [*track_io]; - *track_io = 0; - if ( e.track >= 0 ) - { - *track_io = e.track; - // TODO: really needs to be removed? - //if ( !(type_->flags_ & 0x02) ) - // *track_io -= e.decimal_track; - } - if ( *track_io >= raw_track_count_ ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "invalid track in m3u playlist" ); - } - else - { - check( !playlist.size() ); - } - return blargg_ok; -} - -blargg_err_t Gme_File::track_info( track_info_t* out, int track ) const -{ - out->track_count = track_count(); - out->length = -1; - out->loop_length = -1; - out->intro_length = -1; - out->fade_length = -1; - out->play_length = -1; - out->repeat_count = -1; - out->song [0] = 0; - out->game [0] = 0; - out->author [0] = 0; - out->composer [0] = 0; - out->engineer [0] = 0; - out->sequencer [0] = 0; - out->tagger [0] = 0; - out->copyright [0] = 0; - out->date [0] = 0; - out->comment [0] = 0; - out->dumper [0] = 0; - out->system [0] = 0; - out->disc [0] = 0; - out->track [0] = 0; - out->ost [0] = 0; - - copy_field_( out->system, type()->system ); - - int remapped = track; - RETURN_ERR( remap_track_( &remapped ) ); - RETURN_ERR( track_info_( out, remapped ) ); - - // override with m3u info - if ( playlist.size() ) - { - M3u_Playlist::info_t const& i = playlist.info(); - copy_field_( out->game , i.title ); - copy_field_( out->author , i.artist ); - copy_field_( out->engineer , i.engineer ); - copy_field_( out->composer , i.composer ); - copy_field_( out->sequencer, i.sequencer ); - copy_field_( out->copyright, i.copyright ); - copy_field_( out->dumper , i.ripping ); - copy_field_( out->tagger , i.tagging ); - copy_field_( out->date , i.date ); - - M3u_Playlist::entry_t const& e = playlist [track]; - if ( e.length >= 0 ) out->length = e.length; - if ( e.intro >= 0 ) out->intro_length = e.intro; - if ( e.loop >= 0 ) out->loop_length = e.loop; - if ( e.fade >= 0 ) out->fade_length = e.fade; - if ( e.repeat >= 0 ) out->repeat_count = e.repeat; - copy_field_( out->song, e.name ); - } - - // play_length - out->play_length = out->length; - if ( out->play_length <= 0 ) - { - out->play_length = out->intro_length + 2 * out->loop_length; // intro + 2 loops - if ( out->play_length <= 0 ) - out->play_length = 150 * 1000; // 2.5 minutes - } - - return blargg_ok; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Gme_File.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +void Gme_File::unload() +{ + clear_playlist(); // BEFORE clearing track count + track_count_ = 0; + raw_track_count_ = 0; + Gme_Loader::unload(); +} + +Gme_File::Gme_File() +{ + type_ = NULL; + user_data_ = NULL; + user_cleanup_ = NULL; + Gme_File::unload(); // clears fields +} + +Gme_File::~Gme_File() +{ + if ( user_cleanup_ ) + user_cleanup_( user_data_ ); +} + +blargg_err_t Gme_File::post_load() +{ + if ( !track_count() ) + set_track_count( type()->track_count ); + return Gme_Loader::post_load(); +} + +void Gme_File::clear_playlist() +{ + playlist.clear(); + clear_playlist_(); + track_count_ = raw_track_count_; +} + +void Gme_File::copy_field_( char out [], const char* in, int in_size ) +{ + if ( !in || !*in ) + return; + + // remove spaces/junk from beginning + while ( in_size && unsigned (*in - 1) <= ' ' - 1 ) + { + in++; + in_size--; + } + + // truncate + if ( in_size > max_field_ ) + in_size = max_field_; + + // find terminator + int len = 0; + while ( len < in_size && in [len] ) + len++; + + // remove spaces/junk from end + while ( len && unsigned (in [len - 1]) <= ' ' ) + len--; + + // copy + out [len] = 0; + memcpy( out, in, len ); + + // strip out stupid fields that should have been left blank + if ( !strcmp( out, "?" ) || !strcmp( out, "" ) || !strcmp( out, "< ? >" ) ) + out [0] = 0; +} + +void Gme_File::copy_field_( char out [], const char* in ) +{ + copy_field_( out, in, max_field_ ); +} + +blargg_err_t Gme_File::remap_track_( int* track_io ) const +{ + if ( (unsigned) *track_io >= (unsigned) track_count() ) + return BLARGG_ERR( BLARGG_ERR_CALLER, "invalid track" ); + + if ( (unsigned) *track_io < (unsigned) playlist.size() ) + { + M3u_Playlist::entry_t const& e = playlist [*track_io]; + *track_io = 0; + if ( e.track >= 0 ) + { + *track_io = e.track; + // TODO: really needs to be removed? + //if ( !(type_->flags_ & 0x02) ) + // *track_io -= e.decimal_track; + } + if ( *track_io >= raw_track_count_ ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "invalid track in m3u playlist" ); + } + else + { + check( !playlist.size() ); + } + return blargg_ok; +} + +blargg_err_t Gme_File::track_info( track_info_t* out, int track ) const +{ + out->track_count = track_count(); + out->length = -1; + out->loop_length = -1; + out->intro_length = -1; + out->fade_length = -1; + out->play_length = -1; + out->repeat_count = -1; + out->song [0] = 0; + out->game [0] = 0; + out->author [0] = 0; + out->composer [0] = 0; + out->engineer [0] = 0; + out->sequencer [0] = 0; + out->tagger [0] = 0; + out->copyright [0] = 0; + out->date [0] = 0; + out->comment [0] = 0; + out->dumper [0] = 0; + out->system [0] = 0; + out->disc [0] = 0; + out->track [0] = 0; + out->ost [0] = 0; + + copy_field_( out->system, type()->system ); + + int remapped = track; + RETURN_ERR( remap_track_( &remapped ) ); + RETURN_ERR( track_info_( out, remapped ) ); + + // override with m3u info + if ( playlist.size() ) + { + M3u_Playlist::info_t const& i = playlist.info(); + copy_field_( out->game , i.title ); + copy_field_( out->author , i.artist ); + copy_field_( out->engineer , i.engineer ); + copy_field_( out->composer , i.composer ); + copy_field_( out->sequencer, i.sequencer ); + copy_field_( out->copyright, i.copyright ); + copy_field_( out->dumper , i.ripping ); + copy_field_( out->tagger , i.tagging ); + copy_field_( out->date , i.date ); + + M3u_Playlist::entry_t const& e = playlist [track]; + if ( e.length >= 0 ) out->length = e.length; + if ( e.intro >= 0 ) out->intro_length = e.intro; + if ( e.loop >= 0 ) out->loop_length = e.loop; + if ( e.fade >= 0 ) out->fade_length = e.fade; + if ( e.repeat >= 0 ) out->repeat_count = e.repeat; + copy_field_( out->song, e.name ); + } + + // play_length + out->play_length = out->length; + if ( out->play_length <= 0 ) + { + out->play_length = out->intro_length + 2 * out->loop_length; // intro + 2 loops + if ( out->play_length <= 0 ) + out->play_length = 150 * 1000; // 2.5 minutes + } + + return blargg_ok; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gme_File.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gme_File.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gme_File.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gme_File.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,153 +1,153 @@ -// Common interface for track information - -// Game_Music_Emu $vers -#ifndef GME_FILE_H -#define GME_FILE_H - -#include "gme.h" -#include "Gme_Loader.h" -#include "M3u_Playlist.h" - -struct track_info_t -{ - int track_count; - - /* times in milliseconds; -1 if unknown */ - int length; /* total length, if file specifies it */ - int intro_length; /* length of song up to looping section */ - int loop_length; /* length of looping section */ - int fade_length; - int repeat_count; - - /* Length if available, otherwise intro_length+loop_length*2 if available, - otherwise a default of 150000 (2.5 minutes). */ - int play_length; - - /* empty string if not available */ - char system [256]; - char game [256]; - char song [256]; - char author [256]; - char composer [256]; - char engineer [256]; - char sequencer [256]; - char tagger [256]; - char copyright [256]; - char date [256]; - char comment [256]; - char dumper [256]; - char disc [256]; - char track [256]; - char ost [256]; -}; -enum { gme_max_field = 255 }; - -class Gme_File : public Gme_Loader { -public: - // Type of emulator. For example if this returns gme_nsfe_type, this object - // is an NSFE emulator, and you can downcast to an Nsfe_Emu* if necessary. - gme_type_t type() const; - - // Loads an m3u playlist. Must be done AFTER loading main music file. - blargg_err_t load_m3u( const char path [] ); - blargg_err_t load_m3u( Data_Reader& in ); - - // Clears any loaded m3u playlist and any internal playlist that the music - // format supports (NSFE for example). - void clear_playlist(); - - // Number of tracks or 0 if no file has been loaded - int track_count() const; - - // Gets information for a track (length, name, author, etc.) - // See gme.h for definition of struct track_info_t. - blargg_err_t track_info( track_info_t* out, int track ) const; - -// User data/cleanup - - // Sets/gets pointer to data you want to associate with this emulator. - // You can use this for whatever you want. - void set_user_data( void* p ) { user_data_ = p; } - void* user_data() const { return user_data_; } - - // Registers cleanup function to be called when deleting emulator, or NULL to - // clear it. Passes user_data to cleanup function. - void set_user_cleanup( gme_user_cleanup_t func ) { user_cleanup_ = func; } - -public: - Gme_File(); - ~Gme_File(); - -protected: - // Services - void set_type( gme_type_t t ) { type_ = t; } - void set_track_count( int n ) { track_count_ = raw_track_count_ = n; } - - // Must be overridden - virtual blargg_err_t track_info_( track_info_t* out, int track ) const BLARGG_PURE( ; ) - - // Optionally overridden - virtual void clear_playlist_() { } - -protected: // Gme_Loader overrides - virtual void unload(); - virtual blargg_err_t post_load(); - -protected: - blargg_err_t remap_track_( int* track_io ) const; // need by Music_Emu -private: - gme_type_t type_; - void* user_data_; - gme_user_cleanup_t user_cleanup_; - int track_count_; - int raw_track_count_; - M3u_Playlist playlist; - char playlist_warning [64]; - - blargg_err_t load_m3u_( blargg_err_t ); - -public: - // track_info field copying - enum { max_field_ = 255 }; - static void copy_field_( char out [], const char* in ); - static void copy_field_( char out [], const char* in, int len ); -}; - -struct gme_type_t_ -{ - const char* system; /* name of system this music file type is generally for */ - int track_count; /* non-zero for formats with a fixed number of tracks */ - Music_Emu* (*new_emu)(); /* Create new emulator for this type (C++ only) */ - Music_Emu* (*new_info)();/* Create new info reader for this type (C++ only) */ - - /* internal */ - const char* extension_; - int flags_; -}; - -/* Emulator type constants for each supported file type */ -extern const gme_type_t_ - gme_ay_type [1], - gme_gbs_type [1], - gme_gym_type [1], - gme_hes_type [1], - gme_kss_type [1], - gme_nsf_type [1], - gme_nsfe_type [1], - gme_sap_type [1], - gme_sfm_type [1], - gme_sgc_type [1], - gme_spc_type [1], - gme_vgm_type [1], - gme_vgz_type [1]; - -#define GME_COPY_FIELD( in, out, name ) \ - { Gme_File::copy_field_( out->name, in.name, sizeof in.name ); } - -inline gme_type_t Gme_File::type() const { return type_; } - -inline int Gme_File::track_count() const { return track_count_; } - -inline blargg_err_t Gme_File::track_info_( track_info_t*, int ) const { return blargg_ok; } - -#endif +// Common interface for track information + +// Game_Music_Emu $vers +#ifndef GME_FILE_H +#define GME_FILE_H + +#include "gme.h" +#include "Gme_Loader.h" +#include "M3u_Playlist.h" + +struct track_info_t +{ + int track_count; + + /* times in milliseconds; -1 if unknown */ + int length; /* total length, if file specifies it */ + int intro_length; /* length of song up to looping section */ + int loop_length; /* length of looping section */ + int fade_length; + int repeat_count; + + /* Length if available, otherwise intro_length+loop_length*2 if available, + otherwise a default of 150000 (2.5 minutes). */ + int play_length; + + /* empty string if not available */ + char system [256]; + char game [256]; + char song [256]; + char author [256]; + char composer [256]; + char engineer [256]; + char sequencer [256]; + char tagger [256]; + char copyright [256]; + char date [256]; + char comment [256]; + char dumper [256]; + char disc [256]; + char track [256]; + char ost [256]; +}; +enum { gme_max_field = 255 }; + +class Gme_File : public Gme_Loader { +public: + // Type of emulator. For example if this returns gme_nsfe_type, this object + // is an NSFE emulator, and you can downcast to an Nsfe_Emu* if necessary. + gme_type_t type() const; + + // Loads an m3u playlist. Must be done AFTER loading main music file. + blargg_err_t load_m3u( const char path [] ); + blargg_err_t load_m3u( Data_Reader& in ); + + // Clears any loaded m3u playlist and any internal playlist that the music + // format supports (NSFE for example). + void clear_playlist(); + + // Number of tracks or 0 if no file has been loaded + int track_count() const; + + // Gets information for a track (length, name, author, etc.) + // See gme.h for definition of struct track_info_t. + blargg_err_t track_info( track_info_t* out, int track ) const; + +// User data/cleanup + + // Sets/gets pointer to data you want to associate with this emulator. + // You can use this for whatever you want. + void set_user_data( void* p ) { user_data_ = p; } + void* user_data() const { return user_data_; } + + // Registers cleanup function to be called when deleting emulator, or NULL to + // clear it. Passes user_data to cleanup function. + void set_user_cleanup( gme_user_cleanup_t func ) { user_cleanup_ = func; } + +public: + Gme_File(); + ~Gme_File(); + +protected: + // Services + void set_type( gme_type_t t ) { type_ = t; } + void set_track_count( int n ) { track_count_ = raw_track_count_ = n; } + + // Must be overridden + virtual blargg_err_t track_info_( track_info_t* out, int track ) const BLARGG_PURE( ; ) + + // Optionally overridden + virtual void clear_playlist_() { } + +protected: // Gme_Loader overrides + virtual void unload(); + virtual blargg_err_t post_load(); + +protected: + blargg_err_t remap_track_( int* track_io ) const; // need by Music_Emu +private: + gme_type_t type_; + void* user_data_; + gme_user_cleanup_t user_cleanup_; + int track_count_; + int raw_track_count_; + M3u_Playlist playlist; + char playlist_warning [64]; + + blargg_err_t load_m3u_( blargg_err_t ); + +public: + // track_info field copying + enum { max_field_ = 255 }; + static void copy_field_( char out [], const char* in ); + static void copy_field_( char out [], const char* in, int len ); +}; + +struct gme_type_t_ +{ + const char* system; /* name of system this music file type is generally for */ + int track_count; /* non-zero for formats with a fixed number of tracks */ + Music_Emu* (*new_emu)(); /* Create new emulator for this type (C++ only) */ + Music_Emu* (*new_info)();/* Create new info reader for this type (C++ only) */ + + /* internal */ + const char* extension_; + int flags_; +}; + +/* Emulator type constants for each supported file type */ +extern const gme_type_t_ + gme_ay_type [1], + gme_gbs_type [1], + gme_gym_type [1], + gme_hes_type [1], + gme_kss_type [1], + gme_nsf_type [1], + gme_nsfe_type [1], + gme_sap_type [1], + gme_sfm_type [1], + gme_sgc_type [1], + gme_spc_type [1], + gme_vgm_type [1], + gme_vgz_type [1]; + +#define GME_COPY_FIELD( in, out, name ) \ + { Gme_File::copy_field_( out->name, in.name, sizeof in.name ); } + +inline gme_type_t Gme_File::type() const { return type_; } + +inline int Gme_File::track_count() const { return track_count_; } + +inline blargg_err_t Gme_File::track_info_( track_info_t*, int ) const { return blargg_ok; } + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,307 +1,307 @@ -/* Loads and plays video game music files into sample buffer */ - -/* Game_Music_Emu $vers */ -#ifndef GME_H -#define GME_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Pointer to error, or NULL if function was successful. See Errors below. */ -#ifndef gme_err_t /* (#ifndef allows better testing of library) */ - typedef const char* gme_err_t; -#endif - -/* First parameter of most functions is gme_t*, or const gme_t* if nothing is -changed. */ -typedef struct gme_t gme_t; - -/* Boolean; false = 0, true = 1 */ -typedef int gme_bool; - - -/******** Basic operations ********/ - -/* Opens game music file and points *out at it. If error, sets *out to NULL. */ -gme_err_t gme_open_file( const char path [], gme_t** out, int sample_rate ); - -/* Number of tracks */ -int gme_track_count( const gme_t* ); - -/* Starts a track, where 0 is the first track. Requires that 0 <= index < gme_track_count(). */ -gme_err_t gme_start_track( gme_t*, int index ); - -/* Generates 'count' 16-bit signed samples info 'out'. Output is in stereo, so count -must be even. */ -gme_err_t gme_play( gme_t*, int count, short out [] ); - -/* Closes file and frees memory. OK to pass NULL. */ -void gme_delete( gme_t* ); - - -/******** Track position/length ********/ - -/* Sets time to start fading track out. Once fade ends track_ended() returns true. -Fade time can be changed while track is playing. */ -void gme_set_fade( gme_t*, int start_msec, int length_msec ); - -/* True if a track has reached its end */ -gme_bool gme_track_ended( const gme_t* ); - -/* Number of milliseconds played since beginning of track (1000 = one second) */ -int gme_tell( const gme_t* ); - -/* Seeks to new time in track. Seeking backwards or far forward can take a while. */ -gme_err_t gme_seek( gme_t*, int msec ); - -/* Skips the specified number of samples. */ -gme_err_t gme_skip( gme_t*, int samples ); - - -/******** Informational ********/ - -/* Use in place of sample rate for open/load if you only need to get track -information from a music file */ -enum { gme_info_only = -1 }; - -/* Most recent warning string, or NULL if none. Clears current warning after returning. -Warning is also cleared when loading a file and starting a track. */ -const char* gme_warning( gme_t* ); - -/* Loads m3u playlist file (must be done after loading music) */ -gme_err_t gme_load_m3u( gme_t*, const char path [] ); - -/* Clears any loaded m3u playlist and any internal playlist that the music format -supports (NSFE for example). */ -void gme_clear_playlist( gme_t* ); - -/* Passes back pointer to information for a particular track (length, name, author, etc.). -Must be freed after use. */ -typedef struct gme_info_t gme_info_t; -gme_err_t gme_track_info( const gme_t*, gme_info_t** out, int track ); - -gme_err_t gme_set_track_info( gme_t*, const gme_info_t* in, int track ); - -/* Frees track information */ -void gme_free_info( gme_info_t* ); - -struct gme_info_t -{ - /* times in milliseconds; -1 if unknown */ - int length; /* total length, if file specifies it */ - int intro_length; /* length of song up to looping section */ - int loop_length; /* length of looping section */ - - /* Length if available, otherwise intro_length+loop_length*2 if available, - otherwise a default of 150000 (2.5 minutes). */ - int play_length; - - int i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15; /* reserved */ - - /* empty string ("") if not available */ - const char* system; - const char* game; - const char* song; - const char* author; - const char* copyright; - const char* comment; - const char* dumper; - - const char *s7,*s8,*s9,*s10,*s11,*s12,*s13,*s14,*s15; /* reserved */ -}; - - -/******** Advanced playback ********/ - -/* Disables automatic end-of-track detection and skipping of silence at beginning -if ignore is true */ -void gme_ignore_silence( gme_t*, gme_bool ignore ); - -/* Adjusts song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed, etc. -Track length as returned by track_info() ignores tempo (assumes it's 1.0). */ -void gme_set_tempo( gme_t*, double tempo ); - -/* Number of voices used by currently loaded file */ -int gme_voice_count( const gme_t* ); - -/* Name of voice i, from 0 to gme_voice_count() - 1 */ -const char* gme_voice_name( const gme_t*, int i ); - -/* Mutes/unmutes single voice i, where voice 0 is first voice */ -void gme_mute_voice( gme_t*, int index, gme_bool mute ); - -/* Sets muting state of ALL voices at once using a bit mask, where -1 mutes all -voices, 0 unmutes them all, 0x01 mutes just the first voice, etc. */ -void gme_mute_voices( gme_t*, int muting_mask ); - -/* Frequency equalizer parameters (see gme.txt) */ -typedef struct gme_equalizer_t -{ - double treble; /* -50.0 = muffled, 0 = flat, +5.0 = extra-crisp */ - double bass; /* 1 = full bass, 90 = average, 16000 = almost no bass */ - - double d2,d3,d4,d5,d6,d7,d8,d9; /* reserved */ -} gme_equalizer_t; - -/* Gets current frequency equalizer parameters */ -void gme_equalizer( const gme_t*, gme_equalizer_t* out ); - -/* Changes frequency equalizer parameters */ -void gme_set_equalizer( gme_t*, gme_equalizer_t const* eq ); - - - -/******** Effects processor ********/ - -/* Adds stereo surround and echo to music that's usually mono or has little -stereo. Has no effect on GYM, SPC, and Sega Genesis VGM music. */ - -/* Simplified control using a single value, where 0.0 = off and 1.0 = maximum */ -void gme_set_stereo_depth( gme_t*, double depth ); - -struct gme_effects_t -{ - double echo; /* Amount of echo, where 0.0 = none, 1.0 = lots */ - double stereo; /* Separation, where 0.0 = mono, 1.0 = hard left and right */ - - double d2,d3,d4,d5,d6,d7; /* reserved */ - - gme_bool enabled; /* If 0, no effects are added */ - gme_bool surround;/* If 1, some channels are put in "back", using phase inversion */ - - int i1,i3,i4,i5,i6,i7; /* reserved */ -}; -typedef struct gme_effects_t gme_effects_t; - -/* Sets effects configuration, or disables effects if NULL */ -void gme_set_effects( gme_t*, gme_effects_t const* ); - -/* Passes back current effects configuration */ -void gme_effects( const gme_t*, gme_effects_t* out ); - - -/******** Game music types ********/ - -/* Music file type identifier. Can also hold NULL. */ -typedef const struct gme_type_t_* gme_type_t; - -/* Type of this emulator */ -gme_type_t gme_type( const gme_t* ); - -/* Pointer to array of all music types, with NULL entry at end. Allows a player linked -to this library to support new music types without having to be updated. */ -gme_type_t const* gme_type_list(); - -/* Name of game system for this music file type */ -const char* gme_type_system( gme_type_t ); - -/* True if this music file type supports multiple tracks */ -gme_bool gme_type_multitrack( gme_type_t ); - - -/******** Advanced file loading ********/ - -/* Same as gme_open_file(), but uses file data already in memory. Makes copy of data. */ -gme_err_t gme_open_data( void const* data, long size, gme_t** emu_out, int sample_rate ); - -/* Determines likely game music type based on first four bytes of file. Returns -string containing proper file suffix ("NSF", "SPC", etc.) or "" if file header -is not recognized. */ -const char* gme_identify_header( void const* header ); - -/* Gets corresponding music type for file path or extension passed in. */ -gme_type_t gme_identify_extension( const char path_or_extension [] ); - -/* Determines file type based on file's extension or header (if extension isn't recognized). -Sets *type_out to type, or 0 if unrecognized or error. */ -gme_err_t gme_identify_file( const char path [], gme_type_t* type_out ); - -/* Creates new emulator and sets sample rate. Returns NULL if out of memory. If you only need -track information, pass gme_info_only for sample_rate. */ -gme_t* gme_new_emu( gme_type_t, int sample_rate ); - -/* Loads music file into emulator */ -gme_err_t gme_load_file( gme_t*, const char path [] ); - -/* Loads music file from memory into emulator. Makes a copy of data passed. */ -gme_err_t gme_load_data( gme_t*, void const* data, long size ); - -/* Loads music file using custom data reader function that will be called to -read file data. Most emulators load the entire file in one read call. */ -typedef gme_err_t (*gme_reader_t)( void* your_data, void* out, int count ); -gme_err_t gme_load_custom( gme_t*, gme_reader_t, long file_size, void* your_data ); - -/* Loads m3u playlist file from memory (must be done after loading music) */ -gme_err_t gme_load_m3u_data( gme_t*, void const* data, long size ); - - -/******** Saving ********/ -typedef gme_err_t (*gme_writer_t)( void* your_data, void const* in, long count ); -gme_err_t gme_save( gme_t const*, gme_writer_t, void* your_data ); - -/******** User data ********/ - -/* Sets/gets pointer to data you want to associate with this emulator. -You can use this for whatever you want. */ -void gme_set_user_data( gme_t*, void* new_user_data ); -void* gme_user_data( const gme_t* ); - -/* Registers cleanup function to be called when deleting emulator, or NULL to -clear it. Passes user_data when calling cleanup function. */ -typedef void (*gme_user_cleanup_t)( void* user_data ); -void gme_set_user_cleanup( gme_t*, gme_user_cleanup_t func ); - - -/******** Errors ********/ - -/* Internally, a gme_err_t is a const char* that points to a normal C string. -This means that other strings can be passed to the following functions. In the -descriptions below, these other strings are referred to as being not gme_err_t -strings. */ - -/* Error string associated with err. Returns "" if err is NULL. Returns err -unchanged if it isn't a gme_err_t string. */ -const char* gme_err_str( gme_err_t err ); - -/* Details of error beyond main cause, or "" if none or err is NULL. Returns -err unchanged if it isn't a gme_err_t string. */ -const char* gme_err_details( gme_err_t err ); - -/* Numeric code corresponding to err. Returns gme_ok if err is NULL. Returns -gme_err_generic if err isn't a gme_err_t string. */ -int gme_err_code( gme_err_t err ); - -enum { - gme_ok = 0,/* Successful call. Guaranteed to be zero. */ - gme_err_generic = 0x01,/* Error of unspecified type */ - gme_err_memory = 0x02,/* Out of memory */ - gme_err_caller = 0x03,/* Caller violated requirements of function */ - gme_err_internal = 0x04,/* Internal problem, corruption, etc. */ - gme_err_limitation = 0x05,/* Exceeded program limit */ - - gme_err_file_missing = 0x20,/* File not found at specified path */ - gme_err_file_read = 0x21,/* Couldn't open file for reading */ - gme_err_file_io = 0x23,/* Read/write error */ - gme_err_file_eof = 0x25,/* Tried to read past end of file */ - - gme_err_file_type = 0x30,/* File is of wrong type */ - gme_err_file_feature = 0x32,/* File requires unsupported feature */ - gme_err_file_corrupt = 0x33 /* File is corrupt */ -}; - -/* gme_err_t corresponding to numeric code. Note that this might not recover -the original gme_err_t before it was converted to a numeric code; in -particular, gme_err_details(gme_code_to_err(code)) will be "" in most cases. */ -gme_err_t gme_code_to_err( int code ); - - - -/* Deprecated */ -typedef gme_t Music_Emu; - -#ifdef __cplusplus - } -#endif - -#endif +/* Loads and plays video game music files into sample buffer */ + +/* Game_Music_Emu $vers */ +#ifndef GME_H +#define GME_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Pointer to error, or NULL if function was successful. See Errors below. */ +#ifndef gme_err_t /* (#ifndef allows better testing of library) */ + typedef const char* gme_err_t; +#endif + +/* First parameter of most functions is gme_t*, or const gme_t* if nothing is +changed. */ +typedef struct gme_t gme_t; + +/* Boolean; false = 0, true = 1 */ +typedef int gme_bool; + + +/******** Basic operations ********/ + +/* Opens game music file and points *out at it. If error, sets *out to NULL. */ +gme_err_t gme_open_file( const char path [], gme_t** out, int sample_rate ); + +/* Number of tracks */ +int gme_track_count( const gme_t* ); + +/* Starts a track, where 0 is the first track. Requires that 0 <= index < gme_track_count(). */ +gme_err_t gme_start_track( gme_t*, int index ); + +/* Generates 'count' 16-bit signed samples info 'out'. Output is in stereo, so count +must be even. */ +gme_err_t gme_play( gme_t*, int count, short out [] ); + +/* Closes file and frees memory. OK to pass NULL. */ +void gme_delete( gme_t* ); + + +/******** Track position/length ********/ + +/* Sets time to start fading track out. Once fade ends track_ended() returns true. +Fade time can be changed while track is playing. */ +void gme_set_fade( gme_t*, int start_msec, int length_msec ); + +/* True if a track has reached its end */ +gme_bool gme_track_ended( const gme_t* ); + +/* Number of milliseconds played since beginning of track (1000 = one second) */ +int gme_tell( const gme_t* ); + +/* Seeks to new time in track. Seeking backwards or far forward can take a while. */ +gme_err_t gme_seek( gme_t*, int msec ); + +/* Skips the specified number of samples. */ +gme_err_t gme_skip( gme_t*, int samples ); + + +/******** Informational ********/ + +/* Use in place of sample rate for open/load if you only need to get track +information from a music file */ +enum { gme_info_only = -1 }; + +/* Most recent warning string, or NULL if none. Clears current warning after returning. +Warning is also cleared when loading a file and starting a track. */ +const char* gme_warning( gme_t* ); + +/* Loads m3u playlist file (must be done after loading music) */ +gme_err_t gme_load_m3u( gme_t*, const char path [] ); + +/* Clears any loaded m3u playlist and any internal playlist that the music format +supports (NSFE for example). */ +void gme_clear_playlist( gme_t* ); + +/* Passes back pointer to information for a particular track (length, name, author, etc.). +Must be freed after use. */ +typedef struct gme_info_t gme_info_t; +gme_err_t gme_track_info( const gme_t*, gme_info_t** out, int track ); + +gme_err_t gme_set_track_info( gme_t*, const gme_info_t* in, int track ); + +/* Frees track information */ +void gme_free_info( gme_info_t* ); + +struct gme_info_t +{ + /* times in milliseconds; -1 if unknown */ + int length; /* total length, if file specifies it */ + int intro_length; /* length of song up to looping section */ + int loop_length; /* length of looping section */ + + /* Length if available, otherwise intro_length+loop_length*2 if available, + otherwise a default of 150000 (2.5 minutes). */ + int play_length; + + int i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15; /* reserved */ + + /* empty string ("") if not available */ + const char* system; + const char* game; + const char* song; + const char* author; + const char* copyright; + const char* comment; + const char* dumper; + + const char *s7,*s8,*s9,*s10,*s11,*s12,*s13,*s14,*s15; /* reserved */ +}; + + +/******** Advanced playback ********/ + +/* Disables automatic end-of-track detection and skipping of silence at beginning +if ignore is true */ +void gme_ignore_silence( gme_t*, gme_bool ignore ); + +/* Adjusts song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed, etc. +Track length as returned by track_info() ignores tempo (assumes it's 1.0). */ +void gme_set_tempo( gme_t*, double tempo ); + +/* Number of voices used by currently loaded file */ +int gme_voice_count( const gme_t* ); + +/* Name of voice i, from 0 to gme_voice_count() - 1 */ +const char* gme_voice_name( const gme_t*, int i ); + +/* Mutes/unmutes single voice i, where voice 0 is first voice */ +void gme_mute_voice( gme_t*, int index, gme_bool mute ); + +/* Sets muting state of ALL voices at once using a bit mask, where -1 mutes all +voices, 0 unmutes them all, 0x01 mutes just the first voice, etc. */ +void gme_mute_voices( gme_t*, int muting_mask ); + +/* Frequency equalizer parameters (see gme.txt) */ +typedef struct gme_equalizer_t +{ + double treble; /* -50.0 = muffled, 0 = flat, +5.0 = extra-crisp */ + double bass; /* 1 = full bass, 90 = average, 16000 = almost no bass */ + + double d2,d3,d4,d5,d6,d7,d8,d9; /* reserved */ +} gme_equalizer_t; + +/* Gets current frequency equalizer parameters */ +void gme_equalizer( const gme_t*, gme_equalizer_t* out ); + +/* Changes frequency equalizer parameters */ +void gme_set_equalizer( gme_t*, gme_equalizer_t const* eq ); + + + +/******** Effects processor ********/ + +/* Adds stereo surround and echo to music that's usually mono or has little +stereo. Has no effect on GYM, SPC, and Sega Genesis VGM music. */ + +/* Simplified control using a single value, where 0.0 = off and 1.0 = maximum */ +void gme_set_stereo_depth( gme_t*, double depth ); + +struct gme_effects_t +{ + double echo; /* Amount of echo, where 0.0 = none, 1.0 = lots */ + double stereo; /* Separation, where 0.0 = mono, 1.0 = hard left and right */ + + double d2,d3,d4,d5,d6,d7; /* reserved */ + + gme_bool enabled; /* If 0, no effects are added */ + gme_bool surround;/* If 1, some channels are put in "back", using phase inversion */ + + int i1,i3,i4,i5,i6,i7; /* reserved */ +}; +typedef struct gme_effects_t gme_effects_t; + +/* Sets effects configuration, or disables effects if NULL */ +void gme_set_effects( gme_t*, gme_effects_t const* ); + +/* Passes back current effects configuration */ +void gme_effects( const gme_t*, gme_effects_t* out ); + + +/******** Game music types ********/ + +/* Music file type identifier. Can also hold NULL. */ +typedef const struct gme_type_t_* gme_type_t; + +/* Type of this emulator */ +gme_type_t gme_type( const gme_t* ); + +/* Pointer to array of all music types, with NULL entry at end. Allows a player linked +to this library to support new music types without having to be updated. */ +gme_type_t const* gme_type_list(); + +/* Name of game system for this music file type */ +const char* gme_type_system( gme_type_t ); + +/* True if this music file type supports multiple tracks */ +gme_bool gme_type_multitrack( gme_type_t ); + + +/******** Advanced file loading ********/ + +/* Same as gme_open_file(), but uses file data already in memory. Makes copy of data. */ +gme_err_t gme_open_data( void const* data, long size, gme_t** emu_out, int sample_rate ); + +/* Determines likely game music type based on first four bytes of file. Returns +string containing proper file suffix ("NSF", "SPC", etc.) or "" if file header +is not recognized. */ +const char* gme_identify_header( void const* header ); + +/* Gets corresponding music type for file path or extension passed in. */ +gme_type_t gme_identify_extension( const char path_or_extension [] ); + +/* Determines file type based on file's extension or header (if extension isn't recognized). +Sets *type_out to type, or 0 if unrecognized or error. */ +gme_err_t gme_identify_file( const char path [], gme_type_t* type_out ); + +/* Creates new emulator and sets sample rate. Returns NULL if out of memory. If you only need +track information, pass gme_info_only for sample_rate. */ +gme_t* gme_new_emu( gme_type_t, int sample_rate ); + +/* Loads music file into emulator */ +gme_err_t gme_load_file( gme_t*, const char path [] ); + +/* Loads music file from memory into emulator. Makes a copy of data passed. */ +gme_err_t gme_load_data( gme_t*, void const* data, long size ); + +/* Loads music file using custom data reader function that will be called to +read file data. Most emulators load the entire file in one read call. */ +typedef gme_err_t (*gme_reader_t)( void* your_data, void* out, int count ); +gme_err_t gme_load_custom( gme_t*, gme_reader_t, long file_size, void* your_data ); + +/* Loads m3u playlist file from memory (must be done after loading music) */ +gme_err_t gme_load_m3u_data( gme_t*, void const* data, long size ); + + +/******** Saving ********/ +typedef gme_err_t (*gme_writer_t)( void* your_data, void const* in, long count ); +gme_err_t gme_save( gme_t const*, gme_writer_t, void* your_data ); + +/******** User data ********/ + +/* Sets/gets pointer to data you want to associate with this emulator. +You can use this for whatever you want. */ +void gme_set_user_data( gme_t*, void* new_user_data ); +void* gme_user_data( const gme_t* ); + +/* Registers cleanup function to be called when deleting emulator, or NULL to +clear it. Passes user_data when calling cleanup function. */ +typedef void (*gme_user_cleanup_t)( void* user_data ); +void gme_set_user_cleanup( gme_t*, gme_user_cleanup_t func ); + + +/******** Errors ********/ + +/* Internally, a gme_err_t is a const char* that points to a normal C string. +This means that other strings can be passed to the following functions. In the +descriptions below, these other strings are referred to as being not gme_err_t +strings. */ + +/* Error string associated with err. Returns "" if err is NULL. Returns err +unchanged if it isn't a gme_err_t string. */ +const char* gme_err_str( gme_err_t err ); + +/* Details of error beyond main cause, or "" if none or err is NULL. Returns +err unchanged if it isn't a gme_err_t string. */ +const char* gme_err_details( gme_err_t err ); + +/* Numeric code corresponding to err. Returns gme_ok if err is NULL. Returns +gme_err_generic if err isn't a gme_err_t string. */ +int gme_err_code( gme_err_t err ); + +enum { + gme_ok = 0,/* Successful call. Guaranteed to be zero. */ + gme_err_generic = 0x01,/* Error of unspecified type */ + gme_err_memory = 0x02,/* Out of memory */ + gme_err_caller = 0x03,/* Caller violated requirements of function */ + gme_err_internal = 0x04,/* Internal problem, corruption, etc. */ + gme_err_limitation = 0x05,/* Exceeded program limit */ + + gme_err_file_missing = 0x20,/* File not found at specified path */ + gme_err_file_read = 0x21,/* Couldn't open file for reading */ + gme_err_file_io = 0x23,/* Read/write error */ + gme_err_file_eof = 0x25,/* Tried to read past end of file */ + + gme_err_file_type = 0x30,/* File is of wrong type */ + gme_err_file_feature = 0x32,/* File requires unsupported feature */ + gme_err_file_corrupt = 0x33 /* File is corrupt */ +}; + +/* gme_err_t corresponding to numeric code. Note that this might not recover +the original gme_err_t before it was converted to a numeric code; in +particular, gme_err_details(gme_code_to_err(code)) will be "" in most cases. */ +gme_err_t gme_code_to_err( int code ); + + + +/* Deprecated */ +typedef gme_t Music_Emu; + +#ifdef __cplusplus + } +#endif + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme.txt kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme.txt --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/gme.txt 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/gme.txt 2013-05-31 22:59:22.000000000 +0000 @@ -1,468 +1,468 @@ -Game_Music_Emu 0.6.0 Pre-release --------------------- -Author : Shay Green -Author : Chris Moeller -Website: http://www.slack.net/~ant/libs/ -Website: http://bitbucket.com/kode54/Game_Music_Emu -Forum : http://groups.google.com/group/blargg-sound-libs -License: GNU Lesser General Public License (LGPL) - -NOTE: This file has not been fully updated yet! - -Contents --------- -* Overview -* C and C++ interfaces -* Function reference -* Error handling -* Emulator types -* M3U playlist support -* Information fields -* Track length -* Loading file data -* Sound parameters -* VGM/GYM YM2413 & YM2612 FM sound -* Modular construction -* Obscure features -* Solving problems -* Deprecated features -* Thanks - - -Overview --------- -This library can open game music files, play tracks, and read game and -track information tags. To play a game music file, do the following: - -* Open the file with gme_open_file() -* Start a track with gme_start_track(); -* Generate samples as needed with gme_play() -* Play samples through speaker using your operating system -* Delete emulator when done with gme_delete() - -Your code must arrange for the generated samples to be played through -the computer's speaker using whatever method your operating system -requires. - -There are many additional features available; you can: - -* Determine of the type of a music file without opening it with -gme_identify_*() -* Load just the file's information tags with gme_info_only -* Load from a block of memory rather than a file with gme_load_data() -* Arrange for a fade-out at a particular time with gme_set_fade -* Find when a track has ended with gme_track_ended() -* Seek to a new time in the track with gme_seek() -* Load an extended m3u playlist with gme_load_m3u() -* Get a list of the voices (channels) and mute them individually with -gme_voice_names() and gme_mute_voice() -* Change the playback tempo without affecting pitch with gme_set_tempo() -* Adjust treble/bass equalization with gme_set_equalizer() -* Associate your own data with an emulator and later get it back with -gme_set_user_data() -* Register a function of yours to be called back when the emulator is -deleted with gme_set_user_cleanup() - -Refer to gme.h for a comprehensive summary of features. - - -C and C++ interfaces --------------------- -While the library is written in C++, an extensive C interface is -provided in gme.h. This C interface will be referred to throughout this -documentation unless a feature is only available in the full C++ -interface. All C interface functions and other names have the gme_ -prefix, so you can recognize a C++-only feature by the lack of gme_ in -the names used (contact me if you'd like a feature added to the C -interface). If you're building a shared library, I highly recommend -sticking to the C interface only, because it will be more stable between -releases of the library than the C++ interface. Finally, the C and C++ -interfaces can be freely mixed without problems. Compare demo/basics.c -with demo/cpp_basics.cpp to see how the C and C++ interfaces translate -between each other. - - -Function reference ------------------- -Read the following header files for a complete reference to functions -and features. The second group of header files can only be used in C++. - -blargg_config.h Library configuration -gme.h C interface (also usable from C++) - -Gme_File.h File loading and track information -Music_Emu.h Track playback and adjustments -Data_Reader.h Custom data readers -Effects_Buffer.h Sound buffer with adjustable stereo echo and panning -M3u_Playlist.h M3U playlist support -Gbs_Emu.h GBS equalizer settings -Nsf_Emu.h NSF equalizer settings -Spc_Emu.h SPC surround disable -Vgm_Emu.h VGM oversampling disable and custom buffer query - - -Error handling --------------- -Functions which can fail have a return type of gme_err_t (blargg_err_t -in the C++ interfaces), which is a pointer to an error string (const -char*). If a function is successful it returns NULL. Errors that you can -easily avoid are checked with debug assertions; gme_err_t return values -are only used for genuine run-time errors that can't be easily predicted -in advance (out of memory, I/O errors, incompatible file data). Your -code should check all error values. - -To improve usability for C programmers, C++ programmers unfamiliar with -exceptions, and compatibility with older C++ compilers, the library does -*not* throw any C++ exceptions and uses malloc() instead of the standard -operator new. This means that you *must* check for NULL when creating a -library object with the new operator. - -When loading a music file in the wrong emulator or trying to load a -non-music file, gme_wrong_file_type is returned. You can check for this -error in C++ like this: - - gme_err_t err = gme_open_file( path, &emu ); - if ( err == gme_wrong_file_type ) - ... - -To check for minor problems, call gme_warning() to get a string -describing the last warning. Your player should allow the user some way -of knowing when this is the case, since these minor errors could affect -playback. Without this information the user can't solve problems as -well. When playing a track, gme_warning() returns minor playback-related -problems (major playback problems end the track immediately and set the -warning string). - - -Emulator types --------------- -The library includes several game music emulators that each support a -different file type. Each is identified by a gme_type_t constant defined -in gme.h, for example gme_nsf_emu is for the NSF emulator. If you use -gme_open_file() or gme_open_data(), the library does the work of -determining the file type and creating an appropriate emulator. If you -want more control over this process, read on. - -There are two basic ways to identify a game music file's type: look at -its file extension, or read the header data. The library includes -functions to help with both methods. The first is preferable because it -is fast and the most common way to identify files. Sometimes the -extension is lost or wrong, so the header must be read. - -Use gme_identify_extension() to find the correct game music type based -on a filename. To identify a file based on its extension and header -contents, use gme_identify_file(). If you read the header data yourself, -use gme_identify_header(). - -If you want to remove support for some music types to reduce your -executable size, edit GME_TYPE_LIST in blargg_config.h. For example, to -support just NSF and GBS, use this: - - #define GME_TYPE_LIST gme_nsf_type, gme_gbs_type - - -M3U playlist support --------------------- -The library supports playlists in an extended m3u format with -gme_load_m3u() to give track names and times to multi-song formats: AY, -GBS, HES, KSS, NSF, NSFE, and SAP. Some aspects of the file format -itself is not well-defined so some m3u files won't work properly -(particularly those provided with KSS files). Only m3u files referencing -a single file are supported; your code must handle m3u files covering -more than one game music file, though it can use the built-in m3u -parsing provided by the library. - - -Information fields ------------------- -Support is provided for the various text fields and length information -in a file with gme_track_info(). If you just need track information for -a file (for example, building a playlist), use gme_new_info() in place -of gme_new_emu(), load the file normally, then you can access the track -count and info, but nothing else. - - M3U VGM GYM SPC SAP NSFE NSF AY GBS HES KSS - ------------------------------------------------------- -Track Count | * * * * * * * * * - | -System | * * * * * * * * * * - | -Game | * * * * * * * - | -Song | * * * * * * * - | -Author | * * * * * * * * - | -Copyright | * * * * * * * * - | -Comment | * * * * - | -Dumper | * * * * - | -Length | * * * * * * - | -Intro Length| * * * - | -Loop Length | * * * - -As listed above, the HES and KSS file formats don't include a track -count, and tracks are often scattered over the 0-255 range, so an m3u -playlist for these is a must. - -Unavailable text fields are set to an empty string and times to -1. Your -code should be prepared for any combination of available and unavailable -fields, as a particular music file might not use all of the supported -fields listed above. - -Currently text fields are truncated to 255 characters. Obscure fields of -some formats are not currently decoded; contact me if you want one -added. - - -Track length ------------- -The library leaves it up to you as to when to stop playing a track. You -can ask for available length information and then tell the library what -time it should start fading the track with gme_set_fade(). By default it -also continually checks for 6 or more seconds of silence to mark the end -of a track. Here is a reasonable algorithm you can use to decide how -long to play a track: - -* If the track length is > 0, use it -* If the loop length > 0, play for intro + loop * 2 -* Otherwise, default to 2.5 minutes (150000 msec) - -If you want to play a track longer than normal, be sure the loop length -isn't zero. See Music_Player.cpp around line 145 for example code. - -By default, the library skips silence at the beginning of a track. It -also continually checks for the end of a non-looping track by watching -for 6 seconds of unbroken silence. When doing this is scans *ahead* by -several seconds so it can report the end of the track after only one -second of silence has actually played. This feature can be disabled with -gme_ignore_silence(). - - -Loading file data ------------------ -The library allows file data to be loaded in many different ways. All -load functions return an error which you should check. The following -examples assume these variables: - - Music_Emu* emu; - gme_err_t error; - -If you're letting the library determine a file's type, you can use -either gme_open_file() or gme_open_data(): - - error = gme_open_file( pathname, &emu ); - error = gme_open_data( pointer, size, &emu ); - -If you're manually determining file type and using used gme_new_emu() to -create an emulator, you can use the following methods of loading: - -* From a block of memory: - - error = gme_load_data( emu, pointer, size ); - -* Have library call your function to read data: - - gme_err_t my_read( void* my_data, void* out, long count ) - { - // code that reads 'count' bytes into 'out' buffer - // and return 0 if no error - } - - error = gme_load_custom( emu, my_read, file_size, my_data ); - -* If you must load the file data into memory yourself, you can have the -library use your data directly *without* making a copy. If you do this, -you must not free the data until you're done playing the file. - - error = emu->load_mem( pointer, size ); - -* If you've already read the first bytes of a file (perhaps to determine -the file type) and want to avoid seeking back to the beginning for -performance reasons, use Remaining_Reader: - - Std_File_Reader in; - error = in.open( file_path ); - - char header [4]; - error = in.read( &header, sizeof header ); - ... - - Remaining_Reader rem( &header, sizeof header, &in ); - error = emu->load( rem ); - -If you merely need access to a file's header after loading, use the -emulator-specific header() functions, after casting the Music_Emu -pointer to the specific emulator's type. This example examines the -chip_flags field of the header if it's an NSF file: - - if ( music_emu->type() == gme_nsf_type ) - { - Nsf_Emu* nsf_emu = (Nsf_Emu*) music_emu; - if ( nsf_emu->header().chip_flags & 0x01 ) - ... - } - -Contact me if you want more information about loading files. - - -Sound parameters ----------------- -All emulators support an arbitrary output sampling rate. A rate of 44100 -Hz should work well on most systems. Since band-limited synthesis is -used, a sampling rate above 48000 Hz is not necessary and will actually -reduce sound quality and performance. - -All emulators also support adjustable gain, mainly for the purpose of -getting consistent volume between different music formats and avoiding -excessive modulation. The gain can only be set *before* setting the -emulator's sampling rate, so it's not useful as a general volume -control. The default gains of emulators are set so that they give -generally similar volumes, though some soundtracks are significantly -louder or quieter than normal. - -Some emulators support adjustable treble and bass frequency equalization -(AY, GBS, HES, KSS, NSF, NSFE, SAP, VGM) using set_equalizer(). -Parameters are specified using gme_equalizer_t eq = { treble_dB, -bass_freq }. Treble_dB sets the treble level (in dB), where 0.0 dB gives -normal treble; -200.0 dB is quite muffled, and 5.0 dB emphasizes treble -for an extra crisp sound. Bass_freq sets the frequency where bass -response starts to diminish; 15 Hz is normal, 0 Hz gives maximum bass, -and 15000 Hz removes all bass. For example, the following makes the -sound extra-crisp but lacking bass: - - gme_equalizer_t eq = { 5.0, 1000 }; - gme_set_equalizer( music_emu, &eq ); - -Each emulator's equalization defaults to approximate the particular -console's sound quality; this default can be determined by calling -equalizer() just after creating the emulator. The Music_Emu::tv_eq -profile gives sound as if coming from a TV speaker, and some emulators -include other profiles for different versions of the system. For -example, to use Famicom sound equalization with the NSF emulator, do the -following: - - music_emu->set_equalizer( Nsf_Emu::famicom_eq ); - - -VGM/GYM YM2413 & YM2612 FM sound --------------------------------- -The library plays Sega Genesis/Mega Drive music using a YM2612 FM sound -chip emulator based on the Gens project. Because this has some -inaccuracies, other YM2612 emulators can be used in its place by -re-implementing the interface in YM2612_Emu.h. Available on my website -is a modified version of MAME's YM2612 emulator, which sounds better in -some ways and whose author is still making improvements. - -VGM music files using the YM2413 FM sound chip are also supported, but a -YM2413 emulator isn't included with the library due to technical -reasons. I have put one of the available YM2413 emulators on my website -that can be used directly. - - -Modular construction --------------------- -The library is made of many fairly independent modules. If you're using -only one music file emulator, you can eliminate many of the library -sources from your program. Refer to the files list in readme.txt to get -a general idea of what can be removed, and be sure to edit GME_TYPE_LIST -(see "Emulator types" above). Post to the forum if you'd like me to put -together a smaller version for a particular use, as this only takes me a -few minutes to do. - -If you want to use one of the individual sound chip emulators (or CPU -cores) in your own console emulator, first check the libraries page on -my website since I have released several of them as stand alone -libraries with included documentation and examples on their use. If you -don't find it as a standalone library, contact me and I'll consider -separating it. - -The "classic" sound chips use my Blip_Buffer library, which greatly -simplifies their implementation and efficiently handles band-limited -synthesis. It is also available as a stand alone library with -documentation and many examples. - - -Obscure features ----------------- -The library's flexibility allows many possibilities. Contact me if you -want help implementing ideas or removing limitations. - -* Uses no global/static variables, allowing multiple instances of any -emulator. This is useful in a music player if you want to allow -simultaneous recording or scanning of other tracks while one is already -playing. This will also be useful if your platform disallows global -data. - -* Emulators that support a custom sound buffer can have *every* voice -routed to a different Blip_Buffer, allowing custom processing on each -voice. For example you could record a Game Boy track as a 4-channel -sound file. - -* Defining BLIP_BUFFER_FAST uses lower quality, less-multiply-intensive -synthesis on "classic" emulators, which might help on some really old -processors. This significantly lowers sound quality and prevents treble -equalization. Try this if your platform's processor isn't fast enough -for normal quality. Even on my ten-year-old 400 MHz Mac, this reduces -processor usage at most by about 0.6% (from 4% to 3.4%), hardly worth -the quality loss. - - -Solving problems ----------------- -If you're having problems, try the following: - -* If you're getting garbled sound, try this simple siren generator in -place of your call to play(). This will quickly tell whether the problem -is in the library or in your code. - - static void play_siren( long count, short* out ) - { - static double a, a2; - while ( count-- ) - *out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) ); - } - -* Enable debugging support in your environment. This enables assertions -and other run-time checks. - -* Turn the compiler's optimizer is off. Sometimes an optimizer generates -bad code. - -* If multiple threads are being used, ensure that only one at a time is -accessing a given set of objects from the library. This library is not -in general thread-safe, though independent objects can be used in -separate threads. - -* If all else fails, see if the demos work. - - -Deprecated features -------------------- -The following functions and other features have been deprecated and will -be removed in a future release of the library. Alternatives to the -deprecated features are listed to the right. - -Music_Emu::error_count() warning() -load( header, reader ) see "Loading file data" above -Spc_Emu::trailer() track_info() -Spc_Emu::trailer_size() -Gym_Emu::track_length() track_info() -Vgm_Emu::gd3_data() track_info() -Nsfe_Emu::disable_playlist() clear_playlist() - - -Thanks ------- -Big thanks to Chris Moeller (kode54) for help with library testing and -feedback, for maintaining the Foobar2000 plugin foo_gep based on it, and -for original work on openspc++ that was used when developing Spc_Emu. -Brad Martin's excellent OpenSPC SNES DSP emulator worked well from the -start. Also thanks to Richard Bannister, Mahendra Tallur, Shazz, -nenolod, theHobbit, Johan Samuelsson, and nes6502 for testing, using, -and giving feedback for the library in their respective game music -players. +Game_Music_Emu 0.6.0 Pre-release +-------------------- +Author : Shay Green +Author : Chris Moeller +Website: http://www.slack.net/~ant/libs/ +Website: http://bitbucket.com/kode54/Game_Music_Emu +Forum : http://groups.google.com/group/blargg-sound-libs +License: GNU Lesser General Public License (LGPL) + +NOTE: This file has not been fully updated yet! + +Contents +-------- +* Overview +* C and C++ interfaces +* Function reference +* Error handling +* Emulator types +* M3U playlist support +* Information fields +* Track length +* Loading file data +* Sound parameters +* VGM/GYM YM2413 & YM2612 FM sound +* Modular construction +* Obscure features +* Solving problems +* Deprecated features +* Thanks + + +Overview +-------- +This library can open game music files, play tracks, and read game and +track information tags. To play a game music file, do the following: + +* Open the file with gme_open_file() +* Start a track with gme_start_track(); +* Generate samples as needed with gme_play() +* Play samples through speaker using your operating system +* Delete emulator when done with gme_delete() + +Your code must arrange for the generated samples to be played through +the computer's speaker using whatever method your operating system +requires. + +There are many additional features available; you can: + +* Determine of the type of a music file without opening it with +gme_identify_*() +* Load just the file's information tags with gme_info_only +* Load from a block of memory rather than a file with gme_load_data() +* Arrange for a fade-out at a particular time with gme_set_fade +* Find when a track has ended with gme_track_ended() +* Seek to a new time in the track with gme_seek() +* Load an extended m3u playlist with gme_load_m3u() +* Get a list of the voices (channels) and mute them individually with +gme_voice_names() and gme_mute_voice() +* Change the playback tempo without affecting pitch with gme_set_tempo() +* Adjust treble/bass equalization with gme_set_equalizer() +* Associate your own data with an emulator and later get it back with +gme_set_user_data() +* Register a function of yours to be called back when the emulator is +deleted with gme_set_user_cleanup() + +Refer to gme.h for a comprehensive summary of features. + + +C and C++ interfaces +-------------------- +While the library is written in C++, an extensive C interface is +provided in gme.h. This C interface will be referred to throughout this +documentation unless a feature is only available in the full C++ +interface. All C interface functions and other names have the gme_ +prefix, so you can recognize a C++-only feature by the lack of gme_ in +the names used (contact me if you'd like a feature added to the C +interface). If you're building a shared library, I highly recommend +sticking to the C interface only, because it will be more stable between +releases of the library than the C++ interface. Finally, the C and C++ +interfaces can be freely mixed without problems. Compare demo/basics.c +with demo/cpp_basics.cpp to see how the C and C++ interfaces translate +between each other. + + +Function reference +------------------ +Read the following header files for a complete reference to functions +and features. The second group of header files can only be used in C++. + +blargg_config.h Library configuration +gme.h C interface (also usable from C++) + +Gme_File.h File loading and track information +Music_Emu.h Track playback and adjustments +Data_Reader.h Custom data readers +Effects_Buffer.h Sound buffer with adjustable stereo echo and panning +M3u_Playlist.h M3U playlist support +Gbs_Emu.h GBS equalizer settings +Nsf_Emu.h NSF equalizer settings +Spc_Emu.h SPC surround disable +Vgm_Emu.h VGM oversampling disable and custom buffer query + + +Error handling +-------------- +Functions which can fail have a return type of gme_err_t (blargg_err_t +in the C++ interfaces), which is a pointer to an error string (const +char*). If a function is successful it returns NULL. Errors that you can +easily avoid are checked with debug assertions; gme_err_t return values +are only used for genuine run-time errors that can't be easily predicted +in advance (out of memory, I/O errors, incompatible file data). Your +code should check all error values. + +To improve usability for C programmers, C++ programmers unfamiliar with +exceptions, and compatibility with older C++ compilers, the library does +*not* throw any C++ exceptions and uses malloc() instead of the standard +operator new. This means that you *must* check for NULL when creating a +library object with the new operator. + +When loading a music file in the wrong emulator or trying to load a +non-music file, gme_wrong_file_type is returned. You can check for this +error in C++ like this: + + gme_err_t err = gme_open_file( path, &emu ); + if ( err == gme_wrong_file_type ) + ... + +To check for minor problems, call gme_warning() to get a string +describing the last warning. Your player should allow the user some way +of knowing when this is the case, since these minor errors could affect +playback. Without this information the user can't solve problems as +well. When playing a track, gme_warning() returns minor playback-related +problems (major playback problems end the track immediately and set the +warning string). + + +Emulator types +-------------- +The library includes several game music emulators that each support a +different file type. Each is identified by a gme_type_t constant defined +in gme.h, for example gme_nsf_emu is for the NSF emulator. If you use +gme_open_file() or gme_open_data(), the library does the work of +determining the file type and creating an appropriate emulator. If you +want more control over this process, read on. + +There are two basic ways to identify a game music file's type: look at +its file extension, or read the header data. The library includes +functions to help with both methods. The first is preferable because it +is fast and the most common way to identify files. Sometimes the +extension is lost or wrong, so the header must be read. + +Use gme_identify_extension() to find the correct game music type based +on a filename. To identify a file based on its extension and header +contents, use gme_identify_file(). If you read the header data yourself, +use gme_identify_header(). + +If you want to remove support for some music types to reduce your +executable size, edit GME_TYPE_LIST in blargg_config.h. For example, to +support just NSF and GBS, use this: + + #define GME_TYPE_LIST gme_nsf_type, gme_gbs_type + + +M3U playlist support +-------------------- +The library supports playlists in an extended m3u format with +gme_load_m3u() to give track names and times to multi-song formats: AY, +GBS, HES, KSS, NSF, NSFE, and SAP. Some aspects of the file format +itself is not well-defined so some m3u files won't work properly +(particularly those provided with KSS files). Only m3u files referencing +a single file are supported; your code must handle m3u files covering +more than one game music file, though it can use the built-in m3u +parsing provided by the library. + + +Information fields +------------------ +Support is provided for the various text fields and length information +in a file with gme_track_info(). If you just need track information for +a file (for example, building a playlist), use gme_new_info() in place +of gme_new_emu(), load the file normally, then you can access the track +count and info, but nothing else. + + M3U VGM GYM SPC SAP NSFE NSF AY GBS HES KSS + ------------------------------------------------------- +Track Count | * * * * * * * * * + | +System | * * * * * * * * * * + | +Game | * * * * * * * + | +Song | * * * * * * * + | +Author | * * * * * * * * + | +Copyright | * * * * * * * * + | +Comment | * * * * + | +Dumper | * * * * + | +Length | * * * * * * + | +Intro Length| * * * + | +Loop Length | * * * + +As listed above, the HES and KSS file formats don't include a track +count, and tracks are often scattered over the 0-255 range, so an m3u +playlist for these is a must. + +Unavailable text fields are set to an empty string and times to -1. Your +code should be prepared for any combination of available and unavailable +fields, as a particular music file might not use all of the supported +fields listed above. + +Currently text fields are truncated to 255 characters. Obscure fields of +some formats are not currently decoded; contact me if you want one +added. + + +Track length +------------ +The library leaves it up to you as to when to stop playing a track. You +can ask for available length information and then tell the library what +time it should start fading the track with gme_set_fade(). By default it +also continually checks for 6 or more seconds of silence to mark the end +of a track. Here is a reasonable algorithm you can use to decide how +long to play a track: + +* If the track length is > 0, use it +* If the loop length > 0, play for intro + loop * 2 +* Otherwise, default to 2.5 minutes (150000 msec) + +If you want to play a track longer than normal, be sure the loop length +isn't zero. See Music_Player.cpp around line 145 for example code. + +By default, the library skips silence at the beginning of a track. It +also continually checks for the end of a non-looping track by watching +for 6 seconds of unbroken silence. When doing this is scans *ahead* by +several seconds so it can report the end of the track after only one +second of silence has actually played. This feature can be disabled with +gme_ignore_silence(). + + +Loading file data +----------------- +The library allows file data to be loaded in many different ways. All +load functions return an error which you should check. The following +examples assume these variables: + + Music_Emu* emu; + gme_err_t error; + +If you're letting the library determine a file's type, you can use +either gme_open_file() or gme_open_data(): + + error = gme_open_file( pathname, &emu ); + error = gme_open_data( pointer, size, &emu ); + +If you're manually determining file type and using used gme_new_emu() to +create an emulator, you can use the following methods of loading: + +* From a block of memory: + + error = gme_load_data( emu, pointer, size ); + +* Have library call your function to read data: + + gme_err_t my_read( void* my_data, void* out, long count ) + { + // code that reads 'count' bytes into 'out' buffer + // and return 0 if no error + } + + error = gme_load_custom( emu, my_read, file_size, my_data ); + +* If you must load the file data into memory yourself, you can have the +library use your data directly *without* making a copy. If you do this, +you must not free the data until you're done playing the file. + + error = emu->load_mem( pointer, size ); + +* If you've already read the first bytes of a file (perhaps to determine +the file type) and want to avoid seeking back to the beginning for +performance reasons, use Remaining_Reader: + + Std_File_Reader in; + error = in.open( file_path ); + + char header [4]; + error = in.read( &header, sizeof header ); + ... + + Remaining_Reader rem( &header, sizeof header, &in ); + error = emu->load( rem ); + +If you merely need access to a file's header after loading, use the +emulator-specific header() functions, after casting the Music_Emu +pointer to the specific emulator's type. This example examines the +chip_flags field of the header if it's an NSF file: + + if ( music_emu->type() == gme_nsf_type ) + { + Nsf_Emu* nsf_emu = (Nsf_Emu*) music_emu; + if ( nsf_emu->header().chip_flags & 0x01 ) + ... + } + +Contact me if you want more information about loading files. + + +Sound parameters +---------------- +All emulators support an arbitrary output sampling rate. A rate of 44100 +Hz should work well on most systems. Since band-limited synthesis is +used, a sampling rate above 48000 Hz is not necessary and will actually +reduce sound quality and performance. + +All emulators also support adjustable gain, mainly for the purpose of +getting consistent volume between different music formats and avoiding +excessive modulation. The gain can only be set *before* setting the +emulator's sampling rate, so it's not useful as a general volume +control. The default gains of emulators are set so that they give +generally similar volumes, though some soundtracks are significantly +louder or quieter than normal. + +Some emulators support adjustable treble and bass frequency equalization +(AY, GBS, HES, KSS, NSF, NSFE, SAP, VGM) using set_equalizer(). +Parameters are specified using gme_equalizer_t eq = { treble_dB, +bass_freq }. Treble_dB sets the treble level (in dB), where 0.0 dB gives +normal treble; -200.0 dB is quite muffled, and 5.0 dB emphasizes treble +for an extra crisp sound. Bass_freq sets the frequency where bass +response starts to diminish; 15 Hz is normal, 0 Hz gives maximum bass, +and 15000 Hz removes all bass. For example, the following makes the +sound extra-crisp but lacking bass: + + gme_equalizer_t eq = { 5.0, 1000 }; + gme_set_equalizer( music_emu, &eq ); + +Each emulator's equalization defaults to approximate the particular +console's sound quality; this default can be determined by calling +equalizer() just after creating the emulator. The Music_Emu::tv_eq +profile gives sound as if coming from a TV speaker, and some emulators +include other profiles for different versions of the system. For +example, to use Famicom sound equalization with the NSF emulator, do the +following: + + music_emu->set_equalizer( Nsf_Emu::famicom_eq ); + + +VGM/GYM YM2413 & YM2612 FM sound +-------------------------------- +The library plays Sega Genesis/Mega Drive music using a YM2612 FM sound +chip emulator based on the Gens project. Because this has some +inaccuracies, other YM2612 emulators can be used in its place by +re-implementing the interface in YM2612_Emu.h. Available on my website +is a modified version of MAME's YM2612 emulator, which sounds better in +some ways and whose author is still making improvements. + +VGM music files using the YM2413 FM sound chip are also supported, but a +YM2413 emulator isn't included with the library due to technical +reasons. I have put one of the available YM2413 emulators on my website +that can be used directly. + + +Modular construction +-------------------- +The library is made of many fairly independent modules. If you're using +only one music file emulator, you can eliminate many of the library +sources from your program. Refer to the files list in readme.txt to get +a general idea of what can be removed, and be sure to edit GME_TYPE_LIST +(see "Emulator types" above). Post to the forum if you'd like me to put +together a smaller version for a particular use, as this only takes me a +few minutes to do. + +If you want to use one of the individual sound chip emulators (or CPU +cores) in your own console emulator, first check the libraries page on +my website since I have released several of them as stand alone +libraries with included documentation and examples on their use. If you +don't find it as a standalone library, contact me and I'll consider +separating it. + +The "classic" sound chips use my Blip_Buffer library, which greatly +simplifies their implementation and efficiently handles band-limited +synthesis. It is also available as a stand alone library with +documentation and many examples. + + +Obscure features +---------------- +The library's flexibility allows many possibilities. Contact me if you +want help implementing ideas or removing limitations. + +* Uses no global/static variables, allowing multiple instances of any +emulator. This is useful in a music player if you want to allow +simultaneous recording or scanning of other tracks while one is already +playing. This will also be useful if your platform disallows global +data. + +* Emulators that support a custom sound buffer can have *every* voice +routed to a different Blip_Buffer, allowing custom processing on each +voice. For example you could record a Game Boy track as a 4-channel +sound file. + +* Defining BLIP_BUFFER_FAST uses lower quality, less-multiply-intensive +synthesis on "classic" emulators, which might help on some really old +processors. This significantly lowers sound quality and prevents treble +equalization. Try this if your platform's processor isn't fast enough +for normal quality. Even on my ten-year-old 400 MHz Mac, this reduces +processor usage at most by about 0.6% (from 4% to 3.4%), hardly worth +the quality loss. + + +Solving problems +---------------- +If you're having problems, try the following: + +* If you're getting garbled sound, try this simple siren generator in +place of your call to play(). This will quickly tell whether the problem +is in the library or in your code. + + static void play_siren( long count, short* out ) + { + static double a, a2; + while ( count-- ) + *out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) ); + } + +* Enable debugging support in your environment. This enables assertions +and other run-time checks. + +* Turn the compiler's optimizer is off. Sometimes an optimizer generates +bad code. + +* If multiple threads are being used, ensure that only one at a time is +accessing a given set of objects from the library. This library is not +in general thread-safe, though independent objects can be used in +separate threads. + +* If all else fails, see if the demos work. + + +Deprecated features +------------------- +The following functions and other features have been deprecated and will +be removed in a future release of the library. Alternatives to the +deprecated features are listed to the right. + +Music_Emu::error_count() warning() +load( header, reader ) see "Loading file data" above +Spc_Emu::trailer() track_info() +Spc_Emu::trailer_size() +Gym_Emu::track_length() track_info() +Vgm_Emu::gd3_data() track_info() +Nsfe_Emu::disable_playlist() clear_playlist() + + +Thanks +------ +Big thanks to Chris Moeller (kode54) for help with library testing and +feedback, for maintaining the Foobar2000 plugin foo_gep based on it, and +for original work on openspc++ that was used when developing Spc_Emu. +Brad Martin's excellent OpenSPC SNES DSP emulator worked well from the +start. Also thanks to Richard Bannister, Mahendra Tallur, Shazz, +nenolod, theHobbit, Johan Samuelsson, and nes6502 for testing, using, +and giving feedback for the library in their respective game music +players. diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gym_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gym_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gym_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gym_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,428 +1,428 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Gym_Emu.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -double const min_tempo = 0.25; -double const oversample = 5 / 3.0; -double const fm_gain = 3.0; - -int const base_clock = 53700300; -int const clock_rate = base_clock / 15; - -Gym_Emu::Gym_Emu() -{ - resampler.set_callback( play_frame_, this ); - pos = NULL; - disable_oversampling_ = false; - set_type( gme_gym_type ); - set_silence_lookahead( 1 ); // tracks should already be trimmed - pcm_buf = stereo_buf.center(); -} - -Gym_Emu::~Gym_Emu() { } - -// Track info - -static void get_gym_info( Gym_Emu::header_t const& h, int length, track_info_t* out ) -{ - if ( 0 != memcmp( h.tag, "GYMX", 4 ) ) - return; - - length = length * 50 / 3; // 1000 / 60 - int loop = get_le32( h.loop_start ); - if ( loop ) - { - out->intro_length = loop * 50 / 3; - out->loop_length = length - out->intro_length; - } - else - { - out->length = length; - out->intro_length = length; // make it clear that track is no longer than length - out->loop_length = 0; - } - - // more stupidity where the field should have been left blank - if ( strcmp( h.song, "Unknown Song" ) ) - GME_COPY_FIELD( h, out, song ); - - if ( strcmp( h.game, "Unknown Game" ) ) - GME_COPY_FIELD( h, out, game ); - - if ( strcmp( h.copyright, "Unknown Publisher" ) ) - GME_COPY_FIELD( h, out, copyright ); - - if ( strcmp( h.dumper, "Unknown Person" ) ) - GME_COPY_FIELD( h, out, dumper ); - - if ( strcmp( h.comment, "Header added by YMAMP" ) ) - GME_COPY_FIELD( h, out, comment ); -} - -static void hash_gym_file( Gym_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( &h.loop_start[0], sizeof(h.loop_start) ); - out.hash_( &h.packed[0], sizeof(h.packed) ); - out.hash_( data, data_size ); -} - -static int gym_track_length( byte const p [], byte const* end ) -{ - int time = 0; - while ( p < end ) - { - switch ( *p++ ) - { - case 0: - time++; - break; - - case 1: - case 2: - p += 2; - break; - - case 3: - p += 1; - break; - } - } - return time; -} - -blargg_err_t Gym_Emu::track_info_( track_info_t* out, int ) const -{ - get_gym_info( header_, gym_track_length( log_begin(), file_end() ), out ); - return blargg_ok; -} - -static blargg_err_t check_header( byte const in [], int size, int* data_offset = NULL ) -{ - if ( size < 4 ) - return blargg_err_file_type; - - if ( memcmp( in, "GYMX", 4 ) == 0 ) - { - if ( size < Gym_Emu::header_t::size + 1 ) - return blargg_err_file_type; - - if ( memcmp( ((Gym_Emu::header_t const*) in)->packed, "\0\0\0\0", 4 ) != 0 ) - return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "packed GYM file" ); - - if ( data_offset ) - *data_offset = Gym_Emu::header_t::size; - } - else if ( *in > 3 ) - { - return blargg_err_file_type; - } - - return blargg_ok; -} - -struct Gym_File : Gme_Info_ -{ - int data_offset; - - Gym_File() { set_type( gme_gym_type ); } - - blargg_err_t load_mem_( byte const in [], int size ) - { - data_offset = 0; - return check_header( in, size, &data_offset ); - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - int length = gym_track_length( &file_begin() [data_offset], file_end() ); - get_gym_info( *(Gym_Emu::header_t const*) file_begin(), length, out ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - Gym_Emu::header_t const* h = ( Gym_Emu::header_t const* ) file_begin(); - byte const* data = &file_begin() [data_offset]; - - hash_gym_file( *h, data, file_end() - data, out ); - - return blargg_ok; - } -}; - -static Music_Emu* new_gym_emu () { return BLARGG_NEW Gym_Emu ; } -static Music_Emu* new_gym_file() { return BLARGG_NEW Gym_File; } - -gme_type_t_ const gme_gym_type [1] = {{ "Sega Genesis", 1, &new_gym_emu, &new_gym_file, "GYM", 0 }}; - -// Setup - -blargg_err_t Gym_Emu::set_sample_rate_( int sample_rate ) -{ - blip_eq_t eq( -32, 8000, sample_rate ); - apu.treble_eq( eq ); - pcm_synth.treble_eq( eq ); - - apu.volume( 0.135 * fm_gain * gain() ); - - double factor = oversample; - if ( disable_oversampling_ ) - factor = (double) base_clock / 7 / 144 / sample_rate; - RETURN_ERR( resampler.setup( factor, 0.990, fm_gain * gain() ) ); - factor = resampler.rate(); - double fm_rate = sample_rate * factor; - - RETURN_ERR( stereo_buf.set_sample_rate( sample_rate, int (1000 / 60.0 / min_tempo) ) ); - stereo_buf.clock_rate( clock_rate ); - - RETURN_ERR( fm.set_rate( fm_rate, base_clock / 7.0 ) ); - RETURN_ERR( resampler.reset( (int) (1.0 / 60 / min_tempo * sample_rate) ) ); - - return blargg_ok; -} - -void Gym_Emu::set_tempo_( double t ) -{ - if ( t < min_tempo ) - { - set_tempo( min_tempo ); - return; - } - - if ( stereo_buf.sample_rate() ) - { - double denom = tempo() * 60; - clocks_per_frame = (int) (clock_rate / denom); - resampler.resize( (int) (sample_rate() / denom) ); - } -} - -void Gym_Emu::mute_voices_( int mask ) -{ - Music_Emu::mute_voices_( mask ); - fm.mute_voices( mask ); - apu.set_output( (mask & 0x80) ? 0 : stereo_buf.center() ); - pcm_synth.volume( (mask & 0x40) ? 0.0 : 0.125 / 256 * fm_gain * gain() ); -} - -blargg_err_t Gym_Emu::load_mem_( byte const in [], int size ) -{ - assert( offsetof (header_t,packed [4]) == header_t::size ); - log_offset = 0; - RETURN_ERR( check_header( in, size, &log_offset ) ); - - loop_begin = NULL; - - static const char* const names [] = { - "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG" - }; - set_voice_names( names ); - - set_voice_count( 8 ); - - if ( log_offset ) - header_ = *(header_t const*) in; - else - memset( &header_, 0, sizeof header_ ); - - return blargg_ok; -} - -// Emulation - -blargg_err_t Gym_Emu::start_track_( int track ) -{ - RETURN_ERR( Music_Emu::start_track_( track ) ); - - pos = log_begin(); - loop_remain = get_le32( header_.loop_start ); - - prev_pcm_count = 0; - pcm_enabled = 0; - pcm_amp = -1; - - fm.reset(); - apu.reset(); - stereo_buf.clear(); - resampler.clear(); - pcm_buf = stereo_buf.center(); - return blargg_ok; -} - -void Gym_Emu::run_pcm( byte const pcm_in [], int pcm_count ) -{ - // Guess beginning and end of sample and adjust rate and buffer position accordingly. - - // count dac samples in next frame - int next_pcm_count = 0; - const byte* p = this->pos; - int cmd; - while ( (cmd = *p++) != 0 ) - { - int data = *p++; - if ( cmd <= 2 ) - ++p; - if ( cmd == 1 && data == 0x2A ) - next_pcm_count++; - } - - // detect beginning and end of sample - int rate_count = pcm_count; - int start = 0; - if ( !prev_pcm_count && next_pcm_count && pcm_count < next_pcm_count ) - { - rate_count = next_pcm_count; - start = next_pcm_count - pcm_count; - } - else if ( prev_pcm_count && !next_pcm_count && pcm_count < prev_pcm_count ) - { - rate_count = prev_pcm_count; - } - - // Evenly space samples within buffer section being used - blip_resampled_time_t period = pcm_buf->resampled_duration( clocks_per_frame ) / rate_count; - - blip_resampled_time_t time = pcm_buf->resampled_time( 0 ) + period * start + (unsigned) period / 2; - - int pcm_amp = this->pcm_amp; - if ( pcm_amp < 0 ) - pcm_amp = pcm_in [0]; - - for ( int i = 0; i < pcm_count; i++ ) - { - int delta = pcm_in [i] - pcm_amp; - pcm_amp += delta; - pcm_synth.offset_resampled( time, delta, pcm_buf ); - time += period; - } - this->pcm_amp = pcm_amp; - pcm_buf->set_modified(); -} - -void Gym_Emu::parse_frame() -{ - byte pcm [1024]; // all PCM writes for frame - int pcm_size = 0; - const byte* pos = this->pos; - - if ( loop_remain && !--loop_remain ) - loop_begin = pos; // find loop on first time through sequence - - int cmd; - while ( (cmd = *pos++) != 0 ) - { - int data = *pos++; - if ( cmd == 1 ) - { - int data2 = *pos++; - if ( data == 0x2A ) - { - pcm [pcm_size] = data2; - if ( pcm_size < (int) sizeof pcm - 1 ) - pcm_size += pcm_enabled; - } - else - { - if ( data == 0x2B ) - pcm_enabled = data2 >> 7 & 1; - - fm.write0( data, data2 ); - } - } - else if ( cmd == 2 ) - { - int data2 = *pos++; - if ( data == 0xB6 ) - { - Blip_Buffer * pcm_buf = NULL; - switch ( data2 >> 6 ) - { - case 0: pcm_buf = NULL; break; - case 1: pcm_buf = stereo_buf.right(); break; - case 2: pcm_buf = stereo_buf.left(); break; - case 3: pcm_buf = stereo_buf.center(); break; - } - /*if ( this->pcm_buf != pcm_buf ) - { - if ( this->pcm_buf ) pcm_synth.offset_inline( 0, -pcm_amp, this->pcm_buf ); - if ( pcm_buf ) pcm_synth.offset_inline( 0, pcm_amp, pcm_buf ); - }*/ - this->pcm_buf = pcm_buf; - } - fm.write1( data, data2 ); - } - else if ( cmd == 3 ) - { - apu.write_data( 0, data ); - } - else - { - // to do: many GYM streams are full of errors, and error count should - // reflect cases where music is really having problems - //log_error(); - --pos; // put data back - } - } - - if ( pos >= file_end() ) - { - // Reached end - check( pos == file_end() ); - - if ( loop_begin ) - pos = loop_begin; - else - set_track_ended(); - } - this->pos = pos; - - // PCM - if ( pcm_buf && pcm_size ) - run_pcm( pcm, pcm_size ); - prev_pcm_count = pcm_size; -} - -inline int Gym_Emu::play_frame( blip_time_t blip_time, int sample_count, sample_t buf [] ) -{ - if ( !track_ended() ) - parse_frame(); - - apu.end_frame( blip_time ); - - memset( buf, 0, sample_count * sizeof *buf ); - fm.run( sample_count >> 1, buf ); - - return sample_count; -} - -int Gym_Emu::play_frame_( void* p, blip_time_t a, int b, sample_t c [] ) -{ - return STATIC_CAST(Gym_Emu*,p)->play_frame( a, b, c ); -} - -blargg_err_t Gym_Emu::play_( int count, sample_t out [] ) -{ - resampler.dual_play( count, out, stereo_buf ); - return blargg_ok; -} - -blargg_err_t Gym_Emu::hash_( Hash_Function& out ) const -{ - hash_gym_file( header(), log_begin(), file_end() - log_begin(), out ); - return blargg_ok; +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Gym_Emu.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +double const min_tempo = 0.25; +double const oversample = 5 / 3.0; +double const fm_gain = 3.0; + +int const base_clock = 53700300; +int const clock_rate = base_clock / 15; + +Gym_Emu::Gym_Emu() +{ + resampler.set_callback( play_frame_, this ); + pos = NULL; + disable_oversampling_ = false; + set_type( gme_gym_type ); + set_silence_lookahead( 1 ); // tracks should already be trimmed + pcm_buf = stereo_buf.center(); +} + +Gym_Emu::~Gym_Emu() { } + +// Track info + +static void get_gym_info( Gym_Emu::header_t const& h, int length, track_info_t* out ) +{ + if ( 0 != memcmp( h.tag, "GYMX", 4 ) ) + return; + + length = length * 50 / 3; // 1000 / 60 + int loop = get_le32( h.loop_start ); + if ( loop ) + { + out->intro_length = loop * 50 / 3; + out->loop_length = length - out->intro_length; + } + else + { + out->length = length; + out->intro_length = length; // make it clear that track is no longer than length + out->loop_length = 0; + } + + // more stupidity where the field should have been left blank + if ( strcmp( h.song, "Unknown Song" ) ) + GME_COPY_FIELD( h, out, song ); + + if ( strcmp( h.game, "Unknown Game" ) ) + GME_COPY_FIELD( h, out, game ); + + if ( strcmp( h.copyright, "Unknown Publisher" ) ) + GME_COPY_FIELD( h, out, copyright ); + + if ( strcmp( h.dumper, "Unknown Person" ) ) + GME_COPY_FIELD( h, out, dumper ); + + if ( strcmp( h.comment, "Header added by YMAMP" ) ) + GME_COPY_FIELD( h, out, comment ); +} + +static void hash_gym_file( Gym_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( &h.loop_start[0], sizeof(h.loop_start) ); + out.hash_( &h.packed[0], sizeof(h.packed) ); + out.hash_( data, data_size ); +} + +static int gym_track_length( byte const p [], byte const* end ) +{ + int time = 0; + while ( p < end ) + { + switch ( *p++ ) + { + case 0: + time++; + break; + + case 1: + case 2: + p += 2; + break; + + case 3: + p += 1; + break; + } + } + return time; +} + +blargg_err_t Gym_Emu::track_info_( track_info_t* out, int ) const +{ + get_gym_info( header_, gym_track_length( log_begin(), file_end() ), out ); + return blargg_ok; +} + +static blargg_err_t check_header( byte const in [], int size, int* data_offset = NULL ) +{ + if ( size < 4 ) + return blargg_err_file_type; + + if ( memcmp( in, "GYMX", 4 ) == 0 ) + { + if ( size < Gym_Emu::header_t::size + 1 ) + return blargg_err_file_type; + + if ( memcmp( ((Gym_Emu::header_t const*) in)->packed, "\0\0\0\0", 4 ) != 0 ) + return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "packed GYM file" ); + + if ( data_offset ) + *data_offset = Gym_Emu::header_t::size; + } + else if ( *in > 3 ) + { + return blargg_err_file_type; + } + + return blargg_ok; +} + +struct Gym_File : Gme_Info_ +{ + int data_offset; + + Gym_File() { set_type( gme_gym_type ); } + + blargg_err_t load_mem_( byte const in [], int size ) + { + data_offset = 0; + return check_header( in, size, &data_offset ); + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + int length = gym_track_length( &file_begin() [data_offset], file_end() ); + get_gym_info( *(Gym_Emu::header_t const*) file_begin(), length, out ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + Gym_Emu::header_t const* h = ( Gym_Emu::header_t const* ) file_begin(); + byte const* data = &file_begin() [data_offset]; + + hash_gym_file( *h, data, file_end() - data, out ); + + return blargg_ok; + } +}; + +static Music_Emu* new_gym_emu () { return BLARGG_NEW Gym_Emu ; } +static Music_Emu* new_gym_file() { return BLARGG_NEW Gym_File; } + +gme_type_t_ const gme_gym_type [1] = {{ "Sega Genesis", 1, &new_gym_emu, &new_gym_file, "GYM", 0 }}; + +// Setup + +blargg_err_t Gym_Emu::set_sample_rate_( int sample_rate ) +{ + blip_eq_t eq( -32, 8000, sample_rate ); + apu.treble_eq( eq ); + pcm_synth.treble_eq( eq ); + + apu.volume( 0.135 * fm_gain * gain() ); + + double factor = oversample; + if ( disable_oversampling_ ) + factor = (double) base_clock / 7 / 144 / sample_rate; + RETURN_ERR( resampler.setup( factor, 0.990, fm_gain * gain() ) ); + factor = resampler.rate(); + double fm_rate = sample_rate * factor; + + RETURN_ERR( stereo_buf.set_sample_rate( sample_rate, int (1000 / 60.0 / min_tempo) ) ); + stereo_buf.clock_rate( clock_rate ); + + RETURN_ERR( fm.set_rate( fm_rate, base_clock / 7.0 ) ); + RETURN_ERR( resampler.reset( (int) (1.0 / 60 / min_tempo * sample_rate) ) ); + + return blargg_ok; +} + +void Gym_Emu::set_tempo_( double t ) +{ + if ( t < min_tempo ) + { + set_tempo( min_tempo ); + return; + } + + if ( stereo_buf.sample_rate() ) + { + double denom = tempo() * 60; + clocks_per_frame = (int) (clock_rate / denom); + resampler.resize( (int) (sample_rate() / denom) ); + } +} + +void Gym_Emu::mute_voices_( int mask ) +{ + Music_Emu::mute_voices_( mask ); + fm.mute_voices( mask ); + apu.set_output( (mask & 0x80) ? 0 : stereo_buf.center() ); + pcm_synth.volume( (mask & 0x40) ? 0.0 : 0.125 / 256 * fm_gain * gain() ); +} + +blargg_err_t Gym_Emu::load_mem_( byte const in [], int size ) +{ + assert( offsetof (header_t,packed [4]) == header_t::size ); + log_offset = 0; + RETURN_ERR( check_header( in, size, &log_offset ) ); + + loop_begin = NULL; + + static const char* const names [] = { + "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG" + }; + set_voice_names( names ); + + set_voice_count( 8 ); + + if ( log_offset ) + header_ = *(header_t const*) in; + else + memset( &header_, 0, sizeof header_ ); + + return blargg_ok; +} + +// Emulation + +blargg_err_t Gym_Emu::start_track_( int track ) +{ + RETURN_ERR( Music_Emu::start_track_( track ) ); + + pos = log_begin(); + loop_remain = get_le32( header_.loop_start ); + + prev_pcm_count = 0; + pcm_enabled = 0; + pcm_amp = -1; + + fm.reset(); + apu.reset(); + stereo_buf.clear(); + resampler.clear(); + pcm_buf = stereo_buf.center(); + return blargg_ok; +} + +void Gym_Emu::run_pcm( byte const pcm_in [], int pcm_count ) +{ + // Guess beginning and end of sample and adjust rate and buffer position accordingly. + + // count dac samples in next frame + int next_pcm_count = 0; + const byte* p = this->pos; + int cmd; + while ( (cmd = *p++) != 0 ) + { + int data = *p++; + if ( cmd <= 2 ) + ++p; + if ( cmd == 1 && data == 0x2A ) + next_pcm_count++; + } + + // detect beginning and end of sample + int rate_count = pcm_count; + int start = 0; + if ( !prev_pcm_count && next_pcm_count && pcm_count < next_pcm_count ) + { + rate_count = next_pcm_count; + start = next_pcm_count - pcm_count; + } + else if ( prev_pcm_count && !next_pcm_count && pcm_count < prev_pcm_count ) + { + rate_count = prev_pcm_count; + } + + // Evenly space samples within buffer section being used + blip_resampled_time_t period = pcm_buf->resampled_duration( clocks_per_frame ) / rate_count; + + blip_resampled_time_t time = pcm_buf->resampled_time( 0 ) + period * start + (unsigned) period / 2; + + int pcm_amp = this->pcm_amp; + if ( pcm_amp < 0 ) + pcm_amp = pcm_in [0]; + + for ( int i = 0; i < pcm_count; i++ ) + { + int delta = pcm_in [i] - pcm_amp; + pcm_amp += delta; + pcm_synth.offset_resampled( time, delta, pcm_buf ); + time += period; + } + this->pcm_amp = pcm_amp; + pcm_buf->set_modified(); +} + +void Gym_Emu::parse_frame() +{ + byte pcm [1024]; // all PCM writes for frame + int pcm_size = 0; + const byte* pos = this->pos; + + if ( loop_remain && !--loop_remain ) + loop_begin = pos; // find loop on first time through sequence + + int cmd; + while ( (cmd = *pos++) != 0 ) + { + int data = *pos++; + if ( cmd == 1 ) + { + int data2 = *pos++; + if ( data == 0x2A ) + { + pcm [pcm_size] = data2; + if ( pcm_size < (int) sizeof pcm - 1 ) + pcm_size += pcm_enabled; + } + else + { + if ( data == 0x2B ) + pcm_enabled = data2 >> 7 & 1; + + fm.write0( data, data2 ); + } + } + else if ( cmd == 2 ) + { + int data2 = *pos++; + if ( data == 0xB6 ) + { + Blip_Buffer * pcm_buf = NULL; + switch ( data2 >> 6 ) + { + case 0: pcm_buf = NULL; break; + case 1: pcm_buf = stereo_buf.right(); break; + case 2: pcm_buf = stereo_buf.left(); break; + case 3: pcm_buf = stereo_buf.center(); break; + } + /*if ( this->pcm_buf != pcm_buf ) + { + if ( this->pcm_buf ) pcm_synth.offset_inline( 0, -pcm_amp, this->pcm_buf ); + if ( pcm_buf ) pcm_synth.offset_inline( 0, pcm_amp, pcm_buf ); + }*/ + this->pcm_buf = pcm_buf; + } + fm.write1( data, data2 ); + } + else if ( cmd == 3 ) + { + apu.write_data( 0, data ); + } + else + { + // to do: many GYM streams are full of errors, and error count should + // reflect cases where music is really having problems + //log_error(); + --pos; // put data back + } + } + + if ( pos >= file_end() ) + { + // Reached end + check( pos == file_end() ); + + if ( loop_begin ) + pos = loop_begin; + else + set_track_ended(); + } + this->pos = pos; + + // PCM + if ( pcm_buf && pcm_size ) + run_pcm( pcm, pcm_size ); + prev_pcm_count = pcm_size; +} + +inline int Gym_Emu::play_frame( blip_time_t blip_time, int sample_count, sample_t buf [] ) +{ + if ( !track_ended() ) + parse_frame(); + + apu.end_frame( blip_time ); + + memset( buf, 0, sample_count * sizeof *buf ); + fm.run( sample_count >> 1, buf ); + + return sample_count; +} + +int Gym_Emu::play_frame_( void* p, blip_time_t a, int b, sample_t c [] ) +{ + return STATIC_CAST(Gym_Emu*,p)->play_frame( a, b, c ); +} + +blargg_err_t Gym_Emu::play_( int count, sample_t out [] ) +{ + resampler.dual_play( count, out, stereo_buf ); + return blargg_ok; +} + +blargg_err_t Gym_Emu::hash_( Hash_Function& out ) const +{ + hash_gym_file( header(), log_begin(), file_end() - log_begin(), out ); + return blargg_ok; } \ No newline at end of file diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gym_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gym_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Gym_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Gym_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,88 +1,88 @@ -// Sega Genesis/Mega Drive GYM music file emulator -// Performs PCM timing recovery to improve sample quality. - -// Game_Music_Emu $vers -#ifndef GYM_EMU_H -#define GYM_EMU_H - -#include "Dual_Resampler.h" -#include "Ym2612_Emu.h" -#include "Music_Emu.h" -#include "Sms_Apu.h" - -class Gym_Emu : public Music_Emu { -public: - - // GYM file header (optional; many files have NO header at all) - struct header_t - { - enum { size = 428 }; - - char tag [ 4]; - char song [ 32]; - char game [ 32]; - char copyright [ 32]; - char emulator [ 32]; - char dumper [ 32]; - char comment [256]; - byte loop_start [ 4]; // in 1/60 seconds, 0 if not looped - byte packed [ 4]; - }; - - // Header for currently loaded file - header_t const& header() const { return header_; } - - static gme_type_t static_type() { return gme_gym_type; } - - // Disables running FM chips at higher than normal rate. Will result in slightly - // more aliasing of high notes. - void disable_oversampling( bool disable = true ) { disable_oversampling_ = disable; } - - blargg_err_t hash_( Hash_Function& ) const; - -// Implementation -public: - Gym_Emu(); - ~Gym_Emu(); - -protected: - virtual blargg_err_t load_mem_( byte const [], int ); - virtual blargg_err_t track_info_( track_info_t*, int track ) const; - virtual blargg_err_t set_sample_rate_( int sample_rate ); - virtual blargg_err_t start_track_( int ); - virtual blargg_err_t play_( int count, sample_t [] ); - virtual void mute_voices_( int ); - virtual void set_tempo_( double ); - -private: - // Log - byte const* pos; // current position - byte const* loop_begin; - int log_offset; // size of header (0 or header_t::size) - int loop_remain; // frames remaining until loop_begin has been located - int clocks_per_frame; - - bool disable_oversampling_; - - // PCM - int pcm_amp; - int prev_pcm_count; // for detecting beginning/end of group of samples - int pcm_enabled; - - // large objects - Dual_Resampler resampler; - Stereo_Buffer stereo_buf; - Blip_Buffer * pcm_buf; - Ym2612_Emu fm; - Sms_Apu apu; - Blip_Synth_Fast pcm_synth; - header_t header_; - - byte const* log_begin() const { return file_begin() + log_offset; } - void parse_frame(); - void run_pcm( byte const in [], int count ); - int play_frame( blip_time_t blip_time, int sample_count, sample_t buf [] ); - static int play_frame_( void*, blip_time_t, int, sample_t [] ); -}; - -#endif +// Sega Genesis/Mega Drive GYM music file emulator +// Performs PCM timing recovery to improve sample quality. + +// Game_Music_Emu $vers +#ifndef GYM_EMU_H +#define GYM_EMU_H + +#include "Dual_Resampler.h" +#include "Ym2612_Emu.h" +#include "Music_Emu.h" +#include "Sms_Apu.h" + +class Gym_Emu : public Music_Emu { +public: + + // GYM file header (optional; many files have NO header at all) + struct header_t + { + enum { size = 428 }; + + char tag [ 4]; + char song [ 32]; + char game [ 32]; + char copyright [ 32]; + char emulator [ 32]; + char dumper [ 32]; + char comment [256]; + byte loop_start [ 4]; // in 1/60 seconds, 0 if not looped + byte packed [ 4]; + }; + + // Header for currently loaded file + header_t const& header() const { return header_; } + + static gme_type_t static_type() { return gme_gym_type; } + + // Disables running FM chips at higher than normal rate. Will result in slightly + // more aliasing of high notes. + void disable_oversampling( bool disable = true ) { disable_oversampling_ = disable; } + + blargg_err_t hash_( Hash_Function& ) const; + +// Implementation +public: + Gym_Emu(); + ~Gym_Emu(); + +protected: + virtual blargg_err_t load_mem_( byte const [], int ); + virtual blargg_err_t track_info_( track_info_t*, int track ) const; + virtual blargg_err_t set_sample_rate_( int sample_rate ); + virtual blargg_err_t start_track_( int ); + virtual blargg_err_t play_( int count, sample_t [] ); + virtual void mute_voices_( int ); + virtual void set_tempo_( double ); + +private: + // Log + byte const* pos; // current position + byte const* loop_begin; + int log_offset; // size of header (0 or header_t::size) + int loop_remain; // frames remaining until loop_begin has been located + int clocks_per_frame; + + bool disable_oversampling_; + + // PCM + int pcm_amp; + int prev_pcm_count; // for detecting beginning/end of group of samples + int pcm_enabled; + + // large objects + Dual_Resampler resampler; + Stereo_Buffer stereo_buf; + Blip_Buffer * pcm_buf; + Ym2612_Emu fm; + Sms_Apu apu; + Blip_Synth_Fast pcm_synth; + header_t header_; + + byte const* log_begin() const { return file_begin() + log_offset; } + void parse_frame(); + void run_pcm( byte const in [], int count ); + int play_frame( blip_time_t blip_time, int sample_count, sample_t buf [] ); + static int play_frame_( void*, blip_time_t, int, sample_t [] ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Hes_Apu_Adpcm.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Hes_Apu_Adpcm.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Hes_Apu_Adpcm.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Hes_Apu_Adpcm.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,309 +1,309 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Hes_Apu_Adpcm.h" - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Hes_Apu_Adpcm::Hes_Apu_Adpcm() -{ - output = NULL; - - memset( &state, 0, sizeof( state ) ); - - reset(); -} - -void Hes_Apu_Adpcm::reset() -{ - last_time = 0; - next_timer = 0; - last_amp = 0; - - memset( &state.pcmbuf, 0, sizeof(state.pcmbuf) ); - memset( &state.port, 0, sizeof(state.port) ); - - state.ad_sample = 0; - state.ad_ref_index = 0; - - state.addr = 0; - state.freq = 0; - state.writeptr = 0; - state.readptr = 0; - state.playflag = 0; - state.repeatflag = 0; - state.length = 0; - state.volume = 0xFF; - state.fadetimer = 0; - state.fadecount = 0; -} - -void Hes_Apu_Adpcm::set_output( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL) - require( !center || (center && !left && !right) || (center && left && right) ); - require( (unsigned) i < osc_count ); // fails if you pass invalid osc index - - if ( !center || !left || !right ) - { - left = center; - right = center; - } - - output = center; -} - -void Hes_Apu_Adpcm::run_until( blip_time_t end_time ) -{ - int volume = state.volume; - int fadetimer = state.fadetimer; - int fadecount = state.fadecount; - int last_time = this->last_time; - double next_timer = this->next_timer; - int last_amp = this->last_amp; - - Blip_Buffer* output = this->output; // cache often-used values - - while ( state.playflag && last_time < end_time ) - { - while ( last_time >= next_timer ) - { - if ( fadetimer ) - { - if ( fadecount > 0 ) - { - fadecount--; - volume = 0xFF * fadecount / fadetimer; - } - else if ( fadecount < 0 ) - { - fadecount++; - volume = 0xFF - ( 0xFF * fadecount / fadetimer ); - } - } - next_timer += 7159.091; - } - int amp; - if ( state.ad_low_nibble ) - { - amp = adpcm_decode( state.pcmbuf[ state.playptr ] & 0x0F ); - state.ad_low_nibble = false; - state.playptr++; - state.playedsamplecount++; - if ( state.playedsamplecount == state.playlength ) - { - state.playflag = 0; - } - } - else - { - amp = adpcm_decode( state.pcmbuf[ state.playptr ] >> 4 ); - state.ad_low_nibble = true; - } - amp = amp * volume / 0xFF; - int delta = amp - last_amp; - if ( output && delta ) - { - last_amp = amp; - synth.offset_inline( last_time, delta, output ); - } - last_time += state.freq; - } - - if ( !state.playflag ) - { - while ( next_timer <= end_time ) next_timer += 7159.091; - last_time = end_time; - } - - this->last_time = last_time; - this->next_timer = next_timer; - this->last_amp = last_amp; - state.volume = volume; - state.fadetimer = fadetimer; - state.fadecount = fadecount; -} - -void Hes_Apu_Adpcm::write_data( blip_time_t time, int addr, int data ) -{ - if ( time > last_time ) run_until( time ); - - data &= 0xFF; - state.port[ addr & 15 ] = data; - switch ( addr & 15 ) - { - case 8: - state.addr &= 0xFF00; - state.addr |= data; - break; - case 9: - state.addr &= 0xFF; - state.addr |= data << 8; - break; - case 10: - state.pcmbuf[ state.writeptr++ ] = data; - state.playlength ++; - break; - case 11: - dprintf("ADPCM DMA 0x%02X", data); - break; - case 13: - if ( data & 0x80 ) - { - state.addr = 0; - state.freq = 0; - state.writeptr = 0; - state.readptr = 0; - state.playflag = 0; - state.repeatflag = 0; - state.length = 0; - state.volume = 0xFF; - } - if ( ( data & 3 ) == 3 ) - { - state.writeptr = state.addr; - } - if ( data & 8 ) - { - state.readptr = state.addr ? state.addr - 1 : state.addr; - } - if ( data & 0x10 ) - { - state.length = state.addr; - } - state.repeatflag = data & 0x20; - state.playflag = data & 0x40; - if ( state.playflag ) - { - state.playptr = state.readptr; - state.playlength = state.length + 1; - state.playedsamplecount = 0; - state.ad_sample = 0; - state.ad_low_nibble = false; - } - break; - case 14: - state.freq = 7159091 / ( 32000 / ( 16 - ( data & 15 ) ) ); - break; - case 15: - switch ( data & 15 ) - { - case 0: - case 8: - case 12: - state.fadetimer = -100; - state.fadecount = state.fadetimer; - break; - case 10: - state.fadetimer = 5000; - state.fadecount = state.fadetimer; - break; - case 14: - state.fadetimer = 1500; - state.fadecount = state.fadetimer; - break; - } - break; - } -} - -int Hes_Apu_Adpcm::read_data( blip_time_t time, int addr ) -{ - if ( time > last_time ) run_until( time ); - - switch ( addr & 15 ) - { - case 10: - return state.pcmbuf [state.readptr++]; - case 11: - return state.port [11] & ~1; - case 12: - if (!state.playflag) - { - state.port [12] |= 1; - state.port [12] &= ~8; - } - else - { - state.port [12] &= ~1; - state.port [12] |= 8; - } - return state.port [12]; - case 13: - return state.port [13]; - } - - return 0xFF; -} - -void Hes_Apu_Adpcm::end_frame( blip_time_t end_time ) -{ - run_until( end_time ); - last_time -= end_time; - next_timer -= (double)end_time; - check( last_time >= 0 ); - if ( output ) - output->set_modified(); -} - -static short stepsize[49] = { - 16, 17, 19, 21, 23, 25, 28, - 31, 34, 37, 41, 45, 50, 55, - 60, 66, 73, 80, 88, 97, 107, - 118, 130, 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 -}; - -int Hes_Apu_Adpcm::adpcm_decode( int code ) -{ - int step = stepsize[state.ad_ref_index]; - int delta; - int c = code & 7; -#if 1 - delta = 0; - if ( c & 4 ) delta += step; - step >>= 1; - if ( c & 2 ) delta += step; - step >>= 1; - if ( c & 1 ) delta += step; - step >>= 1; - delta += step; -#else - delta = ( ( c + c + 1 ) * step ) / 8; // maybe faster, but introduces rounding -#endif - if ( c != code ) - { - state.ad_sample -= delta; - if ( state.ad_sample < -2048 ) - state.ad_sample = -2048; - } - else - { - state.ad_sample += delta; - if ( state.ad_sample > 2047 ) - state.ad_sample = 2047; - } - - static int const steps [8] = { - -1, -1, -1, -1, 2, 4, 6, 8 - }; - state.ad_ref_index += steps [c]; - if ( state.ad_ref_index < 0 ) - state.ad_ref_index = 0; - else if ( state.ad_ref_index > 48 ) - state.ad_ref_index = 48; - - return state.ad_sample; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Hes_Apu_Adpcm.h" + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Hes_Apu_Adpcm::Hes_Apu_Adpcm() +{ + output = NULL; + + memset( &state, 0, sizeof( state ) ); + + reset(); +} + +void Hes_Apu_Adpcm::reset() +{ + last_time = 0; + next_timer = 0; + last_amp = 0; + + memset( &state.pcmbuf, 0, sizeof(state.pcmbuf) ); + memset( &state.port, 0, sizeof(state.port) ); + + state.ad_sample = 0; + state.ad_ref_index = 0; + + state.addr = 0; + state.freq = 0; + state.writeptr = 0; + state.readptr = 0; + state.playflag = 0; + state.repeatflag = 0; + state.length = 0; + state.volume = 0xFF; + state.fadetimer = 0; + state.fadecount = 0; +} + +void Hes_Apu_Adpcm::set_output( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) +{ + // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL) + require( !center || (center && !left && !right) || (center && left && right) ); + require( (unsigned) i < osc_count ); // fails if you pass invalid osc index + + if ( !center || !left || !right ) + { + left = center; + right = center; + } + + output = center; +} + +void Hes_Apu_Adpcm::run_until( blip_time_t end_time ) +{ + int volume = state.volume; + int fadetimer = state.fadetimer; + int fadecount = state.fadecount; + int last_time = this->last_time; + double next_timer = this->next_timer; + int last_amp = this->last_amp; + + Blip_Buffer* output = this->output; // cache often-used values + + while ( state.playflag && last_time < end_time ) + { + while ( last_time >= next_timer ) + { + if ( fadetimer ) + { + if ( fadecount > 0 ) + { + fadecount--; + volume = 0xFF * fadecount / fadetimer; + } + else if ( fadecount < 0 ) + { + fadecount++; + volume = 0xFF - ( 0xFF * fadecount / fadetimer ); + } + } + next_timer += 7159.091; + } + int amp; + if ( state.ad_low_nibble ) + { + amp = adpcm_decode( state.pcmbuf[ state.playptr ] & 0x0F ); + state.ad_low_nibble = false; + state.playptr++; + state.playedsamplecount++; + if ( state.playedsamplecount == state.playlength ) + { + state.playflag = 0; + } + } + else + { + amp = adpcm_decode( state.pcmbuf[ state.playptr ] >> 4 ); + state.ad_low_nibble = true; + } + amp = amp * volume / 0xFF; + int delta = amp - last_amp; + if ( output && delta ) + { + last_amp = amp; + synth.offset_inline( last_time, delta, output ); + } + last_time += state.freq; + } + + if ( !state.playflag ) + { + while ( next_timer <= end_time ) next_timer += 7159.091; + last_time = end_time; + } + + this->last_time = last_time; + this->next_timer = next_timer; + this->last_amp = last_amp; + state.volume = volume; + state.fadetimer = fadetimer; + state.fadecount = fadecount; +} + +void Hes_Apu_Adpcm::write_data( blip_time_t time, int addr, int data ) +{ + if ( time > last_time ) run_until( time ); + + data &= 0xFF; + state.port[ addr & 15 ] = data; + switch ( addr & 15 ) + { + case 8: + state.addr &= 0xFF00; + state.addr |= data; + break; + case 9: + state.addr &= 0xFF; + state.addr |= data << 8; + break; + case 10: + state.pcmbuf[ state.writeptr++ ] = data; + state.playlength ++; + break; + case 11: + dprintf("ADPCM DMA 0x%02X", data); + break; + case 13: + if ( data & 0x80 ) + { + state.addr = 0; + state.freq = 0; + state.writeptr = 0; + state.readptr = 0; + state.playflag = 0; + state.repeatflag = 0; + state.length = 0; + state.volume = 0xFF; + } + if ( ( data & 3 ) == 3 ) + { + state.writeptr = state.addr; + } + if ( data & 8 ) + { + state.readptr = state.addr ? state.addr - 1 : state.addr; + } + if ( data & 0x10 ) + { + state.length = state.addr; + } + state.repeatflag = data & 0x20; + state.playflag = data & 0x40; + if ( state.playflag ) + { + state.playptr = state.readptr; + state.playlength = state.length + 1; + state.playedsamplecount = 0; + state.ad_sample = 0; + state.ad_low_nibble = false; + } + break; + case 14: + state.freq = 7159091 / ( 32000 / ( 16 - ( data & 15 ) ) ); + break; + case 15: + switch ( data & 15 ) + { + case 0: + case 8: + case 12: + state.fadetimer = -100; + state.fadecount = state.fadetimer; + break; + case 10: + state.fadetimer = 5000; + state.fadecount = state.fadetimer; + break; + case 14: + state.fadetimer = 1500; + state.fadecount = state.fadetimer; + break; + } + break; + } +} + +int Hes_Apu_Adpcm::read_data( blip_time_t time, int addr ) +{ + if ( time > last_time ) run_until( time ); + + switch ( addr & 15 ) + { + case 10: + return state.pcmbuf [state.readptr++]; + case 11: + return state.port [11] & ~1; + case 12: + if (!state.playflag) + { + state.port [12] |= 1; + state.port [12] &= ~8; + } + else + { + state.port [12] &= ~1; + state.port [12] |= 8; + } + return state.port [12]; + case 13: + return state.port [13]; + } + + return 0xFF; +} + +void Hes_Apu_Adpcm::end_frame( blip_time_t end_time ) +{ + run_until( end_time ); + last_time -= end_time; + next_timer -= (double)end_time; + check( last_time >= 0 ); + if ( output ) + output->set_modified(); +} + +static short stepsize[49] = { + 16, 17, 19, 21, 23, 25, 28, + 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, + 118, 130, 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 +}; + +int Hes_Apu_Adpcm::adpcm_decode( int code ) +{ + int step = stepsize[state.ad_ref_index]; + int delta; + int c = code & 7; +#if 1 + delta = 0; + if ( c & 4 ) delta += step; + step >>= 1; + if ( c & 2 ) delta += step; + step >>= 1; + if ( c & 1 ) delta += step; + step >>= 1; + delta += step; +#else + delta = ( ( c + c + 1 ) * step ) / 8; // maybe faster, but introduces rounding +#endif + if ( c != code ) + { + state.ad_sample -= delta; + if ( state.ad_sample < -2048 ) + state.ad_sample = -2048; + } + else + { + state.ad_sample += delta; + if ( state.ad_sample > 2047 ) + state.ad_sample = 2047; + } + + static int const steps [8] = { + -1, -1, -1, -1, 2, 4, 6, 8 + }; + state.ad_ref_index += steps [c]; + if ( state.ad_ref_index < 0 ) + state.ad_ref_index = 0; + else if ( state.ad_ref_index > 48 ) + state.ad_ref_index = 48; + + return state.ad_sample; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Hes_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Hes_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Hes_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Hes_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,192 +1,192 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Hes_Emu.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Hes_Emu::Hes_Emu() -{ - set_type( gme_hes_type ); - set_silence_lookahead( 6 ); - set_gain( 1.11 ); -} - -Hes_Emu::~Hes_Emu() { } - -void Hes_Emu::unload() -{ - core.unload(); - Music_Emu::unload(); -} - -static byte const* copy_field( byte const in [], char* out ) -{ - if ( in ) - { - int len = 0x20; - if ( in [0x1F] && !in [0x2F] ) - len = 0x30; // fields are sometimes 16 bytes longer (ugh) - - // since text fields are where any data could be, detect non-text - // and fields with data after zero byte terminator - - int i = 0; - for ( ; i < len && in [i]; i++ ) - if ( (unsigned) (in [i] - ' ') >= 0xFF - ' ' ) // also treat 0xFF as non-text - return 0; // non-ASCII found - - for ( ; i < len; i++ ) - if ( in [i] ) - return 0; // data after terminator - - Gme_File::copy_field_( out, (char const*) in, len ); - in += len; - } - return in; -} - -static byte const* copy_hes_fields( byte const in [], track_info_t* out ) -{ - byte const* in_offset = in; - if ( *in_offset >= ' ' ) - { - in_offset = copy_field( in_offset, out->game ); - in_offset = copy_field( in_offset, out->author ); - in_offset = copy_field( in_offset, out->copyright ); - } - return in_offset ? in_offset : in; -} - -static void hash_hes_file( Hes_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( &h.vers, sizeof(h.vers) ); - out.hash_( &h.first_track, sizeof(h.first_track) ); - out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); - out.hash_( &h.banks[0], sizeof(h.banks) ); - out.hash_( &h.data_size[0], sizeof(h.data_size) ); - out.hash_( &h.addr[0], sizeof(h.addr) ); - out.hash_( &h.unused[0], sizeof(h.unused) ); - out.hash_( data, Hes_Core::info_offset ); - - track_info_t temp; // GCC whines about passing a pointer to a temporary here - byte const* more_data = copy_hes_fields( data + Hes_Core::info_offset, &temp ); - out.hash_( more_data, data_size - ( more_data - data ) ); -} - -blargg_err_t Hes_Emu::track_info_( track_info_t* out, int ) const -{ - copy_hes_fields( core.data() + core.info_offset, out ); - return blargg_ok; -} - -struct Hes_File : Gme_Info_ -{ - enum { fields_offset = Hes_Core::header_t::size + Hes_Core::info_offset }; - - union header_t { - Hes_Core::header_t header; - byte data [fields_offset + 0x30 * 3]; - } const* h; - - Hes_File() - { - set_type( gme_hes_type ); - } - - blargg_err_t load_mem_( byte const begin [], int size ) - { - h = ( header_t const* ) begin; - - if ( !h->header.valid_tag() ) - return blargg_err_file_type; - - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_hes_fields( h->data + fields_offset, out ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_hes_file( h->header, file_begin() + h->header.size, file_end() - file_begin() - h->header.size, out ); - return blargg_ok; - } -}; - -static Music_Emu* new_hes_emu () { return BLARGG_NEW Hes_Emu ; } -static Music_Emu* new_hes_file() { return BLARGG_NEW Hes_File; } - -gme_type_t_ const gme_hes_type [1] = {{ "PC Engine", 256, &new_hes_emu, &new_hes_file, "HES", 1 }}; - -blargg_err_t Hes_Emu::load_( Data_Reader& in ) -{ - RETURN_ERR( core.load( in ) ); - - static const char* const names [Hes_Apu::osc_count + Hes_Apu_Adpcm::osc_count] = { - "Wave 1", "Wave 2", "Wave 3", "Wave 4", "Multi 1", "Multi 2", "ADPCM" - }; - set_voice_names( names ); - - static int const types [Hes_Apu::osc_count + Hes_Apu_Adpcm::osc_count] = { - wave_type+0, wave_type+1, wave_type+2, wave_type+3, mixed_type+0, mixed_type+1, mixed_type+2 - }; - set_voice_types( types ); - - set_voice_count( core.apu().osc_count + core.adpcm().osc_count ); - core.apu().volume( gain() ); - core.adpcm().volume( gain() ); - - return setup_buffer( 7159091 ); -} - -void Hes_Emu::update_eq( blip_eq_t const& eq ) -{ - core.apu().treble_eq( eq ); - core.adpcm().treble_eq( eq ); -} - -void Hes_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) -{ - if ( i < core.apu().osc_count ) - core.apu().set_output( i, c, l, r ); - else if ( i == core.apu().osc_count ) - core.adpcm().set_output( 0, c, l, r ); -} - -void Hes_Emu::set_tempo_( double t ) -{ - core.set_tempo( t ); -} - -blargg_err_t Hes_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - return core.start_track( track ); -} - -blargg_err_t Hes_Emu::run_clocks( blip_time_t& duration_, int ) -{ - return core.end_frame( duration_ ); -} - -blargg_err_t Hes_Emu::hash_( Hash_Function& out ) const -{ - hash_hes_file( header(), core.data(), core.data_size(), out ); - return blargg_ok; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Hes_Emu.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Hes_Emu::Hes_Emu() +{ + set_type( gme_hes_type ); + set_silence_lookahead( 6 ); + set_gain( 1.11 ); +} + +Hes_Emu::~Hes_Emu() { } + +void Hes_Emu::unload() +{ + core.unload(); + Music_Emu::unload(); +} + +static byte const* copy_field( byte const in [], char* out ) +{ + if ( in ) + { + int len = 0x20; + if ( in [0x1F] && !in [0x2F] ) + len = 0x30; // fields are sometimes 16 bytes longer (ugh) + + // since text fields are where any data could be, detect non-text + // and fields with data after zero byte terminator + + int i = 0; + for ( ; i < len && in [i]; i++ ) + if ( (unsigned) (in [i] - ' ') >= 0xFF - ' ' ) // also treat 0xFF as non-text + return 0; // non-ASCII found + + for ( ; i < len; i++ ) + if ( in [i] ) + return 0; // data after terminator + + Gme_File::copy_field_( out, (char const*) in, len ); + in += len; + } + return in; +} + +static byte const* copy_hes_fields( byte const in [], track_info_t* out ) +{ + byte const* in_offset = in; + if ( *in_offset >= ' ' ) + { + in_offset = copy_field( in_offset, out->game ); + in_offset = copy_field( in_offset, out->author ); + in_offset = copy_field( in_offset, out->copyright ); + } + return in_offset ? in_offset : in; +} + +static void hash_hes_file( Hes_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( &h.vers, sizeof(h.vers) ); + out.hash_( &h.first_track, sizeof(h.first_track) ); + out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); + out.hash_( &h.banks[0], sizeof(h.banks) ); + out.hash_( &h.data_size[0], sizeof(h.data_size) ); + out.hash_( &h.addr[0], sizeof(h.addr) ); + out.hash_( &h.unused[0], sizeof(h.unused) ); + out.hash_( data, Hes_Core::info_offset ); + + track_info_t temp; // GCC whines about passing a pointer to a temporary here + byte const* more_data = copy_hes_fields( data + Hes_Core::info_offset, &temp ); + out.hash_( more_data, data_size - ( more_data - data ) ); +} + +blargg_err_t Hes_Emu::track_info_( track_info_t* out, int ) const +{ + copy_hes_fields( core.data() + core.info_offset, out ); + return blargg_ok; +} + +struct Hes_File : Gme_Info_ +{ + enum { fields_offset = Hes_Core::header_t::size + Hes_Core::info_offset }; + + union header_t { + Hes_Core::header_t header; + byte data [fields_offset + 0x30 * 3]; + } const* h; + + Hes_File() + { + set_type( gme_hes_type ); + } + + blargg_err_t load_mem_( byte const begin [], int size ) + { + h = ( header_t const* ) begin; + + if ( !h->header.valid_tag() ) + return blargg_err_file_type; + + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + copy_hes_fields( h->data + fields_offset, out ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_hes_file( h->header, file_begin() + h->header.size, file_end() - file_begin() - h->header.size, out ); + return blargg_ok; + } +}; + +static Music_Emu* new_hes_emu () { return BLARGG_NEW Hes_Emu ; } +static Music_Emu* new_hes_file() { return BLARGG_NEW Hes_File; } + +gme_type_t_ const gme_hes_type [1] = {{ "PC Engine", 256, &new_hes_emu, &new_hes_file, "HES", 1 }}; + +blargg_err_t Hes_Emu::load_( Data_Reader& in ) +{ + RETURN_ERR( core.load( in ) ); + + static const char* const names [Hes_Apu::osc_count + Hes_Apu_Adpcm::osc_count] = { + "Wave 1", "Wave 2", "Wave 3", "Wave 4", "Multi 1", "Multi 2", "ADPCM" + }; + set_voice_names( names ); + + static int const types [Hes_Apu::osc_count + Hes_Apu_Adpcm::osc_count] = { + wave_type+0, wave_type+1, wave_type+2, wave_type+3, mixed_type+0, mixed_type+1, mixed_type+2 + }; + set_voice_types( types ); + + set_voice_count( core.apu().osc_count + core.adpcm().osc_count ); + core.apu().volume( gain() ); + core.adpcm().volume( gain() ); + + return setup_buffer( 7159091 ); +} + +void Hes_Emu::update_eq( blip_eq_t const& eq ) +{ + core.apu().treble_eq( eq ); + core.adpcm().treble_eq( eq ); +} + +void Hes_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) +{ + if ( i < core.apu().osc_count ) + core.apu().set_output( i, c, l, r ); + else if ( i == core.apu().osc_count ) + core.adpcm().set_output( 0, c, l, r ); +} + +void Hes_Emu::set_tempo_( double t ) +{ + core.set_tempo( t ); +} + +blargg_err_t Hes_Emu::start_track_( int track ) +{ + RETURN_ERR( Classic_Emu::start_track_( track ) ); + return core.start_track( track ); +} + +blargg_err_t Hes_Emu::run_clocks( blip_time_t& duration_, int ) +{ + return core.end_frame( duration_ ); +} + +blargg_err_t Hes_Emu::hash_( Hash_Function& out ) const +{ + hash_hes_file( header(), core.data(), core.data_size(), out ); + return blargg_ok; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/higan/dsp/SPC_DSP.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/higan/dsp/SPC_DSP.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/higan/dsp/SPC_DSP.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/higan/dsp/SPC_DSP.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -135,302 +135,302 @@ 1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, }; -static short const cubic [514] = -{ - 0, -4, -8, -12, -16, -20, -23, -27, -30, -34, -37, -41, -44, -47, -50, -53, - -56, -59, -62, -65, -68, -71, -73, -76, -78, -81, -84, -87, -89, -91, -93, -95, - -98,-100,-102,-104,-106,-109,-110,-112,-113,-116,-117,-119,-121,-122,-123,-125, --126,-128,-129,-131,-132,-134,-134,-136,-136,-138,-138,-140,-141,-141,-142,-143, --144,-144,-145,-146,-147,-148,-147,-148,-148,-149,-149,-150,-150,-150,-150,-151, --151,-151,-151,-151,-152,-152,-151,-152,-151,-152,-151,-151,-151,-151,-150,-150, --150,-149,-149,-149,-149,-148,-147,-147,-146,-146,-145,-145,-144,-144,-143,-142, --141,-141,-140,-139,-139,-138,-137,-136,-135,-135,-133,-133,-132,-131,-130,-129, --128,-127,-126,-125,-124,-123,-121,-121,-119,-118,-117,-116,-115,-114,-112,-111, --110,-109,-107,-106,-105,-104,-102,-102,-100, -99, -97, -97, -95, -94, -92, -91, - -90, -88, -87, -86, -85, -84, -82, -81, -79, -78, -76, -76, -74, -73, -71, -70, - -68, -67, -66, -65, -63, -62, -60, -60, -58, -57, -55, -55, -53, -52, -50, -49, - -48, -46, -45, -44, -43, -42, -40, -39, -38, -37, -36, -35, -34, -32, -31, -30, - -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -19, -17, -16, -15, -14, - -14, -13, -12, -11, -11, -10, -9, -9, -8, -8, -7, -7, -6, -5, -4, -4, - -3, -3, -3, -2, -2, -2, -1, -1, 0, -1, 0, -1, 0, 0, 0, 0, - 0, -2048,2048,2048,2048,2047,2047,2046,2045,2043,2042,2041,2039,2037,2035,2033,2031, -2028,2026,2024,2021,2018,2015,2012,2009,2005,2002,1999,1995,1991,1987,1982,1978, -1974,1969,1965,1960,1955,1951,1946,1940,1934,1929,1924,1918,1912,1906,1900,1895, -1888,1882,1875,1869,1862,1856,1849,1842,1835,1828,1821,1814,1806,1799,1791,1783, -1776,1768,1760,1753,1744,1737,1728,1720,1711,1703,1695,1686,1677,1668,1659,1651, -1641,1633,1623,1614,1605,1596,1587,1577,1567,1559,1549,1539,1529,1520,1510,1499, -1490,1480,1470,1460,1450,1440,1430,1420,1408,1398,1389,1378,1367,1357,1346,1336, -1325,1315,1304,1293,1282,1272,1261,1250,1239,1229,1218,1207,1196,1185,1174,1163, -1152,1141,1130,1119,1108,1097,1086,1075,1063,1052,1042,1030,1019,1008, 997, 986, - 974, 964, 952, 941, 930, 919, 908, 897, 886, 875, 864, 853, 842, 831, 820, 809, - 798, 787, 776, 765, 754, 744, 733, 722, 711, 700, 690, 679, 668, 658, 647, 637, - 626, 616, 605, 595, 584, 574, 564, 554, 543, 534, 524, 514, 503, 494, 483, 473, - 464, 454, 444, 435, 425, 416, 407, 397, 387, 378, 370, 360, 351, 342, 333, 325, - 315, 307, 298, 290, 281, 273, 265, 256, 248, 241, 233, 225, 216, 209, 201, 193, - 186, 178, 171, 164, 157, 150, 143, 137, 129, 123, 117, 110, 103, 97, 91, 85, - 79, 74, 68, 62, 56, 51, 46, 41, 35, 31, 27, 22, 17, 13, 8, 4, - 0 -}; - -static short const sinc [2048] = -{ - 39, -315, 666, 15642, 666, -315, 39, -38, - 38, -302, 613, 15642, 718, -328, 41, -38, - 36, -288, 561, 15641, 772, -342, 42, -38, - 35, -275, 510, 15639, 826, -355, 44, -38, - 33, -263, 459, 15636, 880, -369, 46, -38, - 32, -250, 408, 15632, 935, -383, 47, -38, - 31, -237, 358, 15628, 990, -396, 49, -38, - 29, -224, 309, 15622, 1046, -410, 51, -38, - 28, -212, 259, 15616, 1103, -425, 53, -38, - 27, -200, 211, 15609, 1159, -439, 54, -38, - 25, -188, 163, 15601, 1216, -453, 56, -38, - 24, -175, 115, 15593, 1274, -467, 58, -38, - 23, -164, 68, 15583, 1332, -482, 60, -38, - 22, -152, 22, 15573, 1391, -496, 62, -37, - 21, -140, -24, 15562, 1450, -511, 64, -37, - 19, -128, -70, 15550, 1509, -526, 66, -37, - 18, -117, -115, 15538, 1569, -540, 68, -37, - 17, -106, -159, 15524, 1629, -555, 70, -37, - 16, -94, -203, 15510, 1690, -570, 72, -36, - 15, -83, -247, 15495, 1751, -585, 74, -36, - 14, -72, -289, 15479, 1813, -600, 76, -36, - 13, -62, -332, 15462, 1875, -616, 79, -36, - 12, -51, -374, 15445, 1937, -631, 81, -35, - 11, -40, -415, 15426, 2000, -646, 83, -35, - 11, -30, -456, 15407, 2063, -662, 85, -35, - 10, -20, -496, 15387, 2127, -677, 88, -34, - 9, -9, -536, 15366, 2191, -693, 90, -34, - 8, 1, -576, 15345, 2256, -708, 92, -34, - 7, 10, -614, 15323, 2321, -724, 95, -33, - 7, 20, -653, 15300, 2386, -740, 97, -33, - 6, 30, -690, 15276, 2451, -755, 99, -33, - 5, 39, -728, 15251, 2517, -771, 102, -32, - 5, 49, -764, 15226, 2584, -787, 104, -32, - 4, 58, -801, 15200, 2651, -803, 107, -32, - 3, 67, -836, 15173, 2718, -819, 109, -31, - 3, 76, -871, 15145, 2785, -835, 112, -31, - 2, 85, -906, 15117, 2853, -851, 115, -30, - 2, 93, -940, 15087, 2921, -867, 117, -30, - 1, 102, -974, 15057, 2990, -883, 120, -29, - 1, 110, -1007, 15027, 3059, -899, 122, -29, - 0, 118, -1039, 14995, 3128, -915, 125, -29, - 0, 127, -1071, 14963, 3198, -931, 128, -28, - -1, 135, -1103, 14930, 3268, -948, 131, -28, - -1, 142, -1134, 14896, 3338, -964, 133, -27, - -1, 150, -1164, 14862, 3409, -980, 136, -27, - -2, 158, -1194, 14827, 3480, -996, 139, -26, - -2, 165, -1224, 14791, 3551, -1013, 142, -26, - -3, 172, -1253, 14754, 3622, -1029, 144, -25, - -3, 179, -1281, 14717, 3694, -1045, 147, -25, - -3, 187, -1309, 14679, 3766, -1062, 150, -24, - -3, 193, -1337, 14640, 3839, -1078, 153, -24, - -4, 200, -1363, 14601, 3912, -1094, 156, -23, - -4, 207, -1390, 14561, 3985, -1110, 159, -23, - -4, 213, -1416, 14520, 4058, -1127, 162, -22, - -4, 220, -1441, 14479, 4131, -1143, 165, -22, - -4, 226, -1466, 14437, 4205, -1159, 168, -22, - -5, 232, -1490, 14394, 4279, -1175, 171, -21, - -5, 238, -1514, 14350, 4354, -1192, 174, -21, - -5, 244, -1537, 14306, 4428, -1208, 177, -20, - -5, 249, -1560, 14261, 4503, -1224, 180, -20, - -5, 255, -1583, 14216, 4578, -1240, 183, -19, - -5, 260, -1604, 14169, 4653, -1256, 186, -19, - -5, 265, -1626, 14123, 4729, -1272, 189, -18, - -5, 271, -1647, 14075, 4805, -1288, 192, -18, - -5, 276, -1667, 14027, 4881, -1304, 195, -17, - -6, 280, -1687, 13978, 4957, -1320, 198, -17, - -6, 285, -1706, 13929, 5033, -1336, 201, -16, - -6, 290, -1725, 13879, 5110, -1352, 204, -16, - -6, 294, -1744, 13829, 5186, -1368, 207, -15, - -6, 299, -1762, 13777, 5263, -1383, 210, -15, - -6, 303, -1779, 13726, 5340, -1399, 213, -14, - -6, 307, -1796, 13673, 5418, -1414, 216, -14, - -6, 311, -1813, 13620, 5495, -1430, 219, -13, - -5, 315, -1829, 13567, 5573, -1445, 222, -13, - -5, 319, -1844, 13512, 5651, -1461, 225, -13, - -5, 322, -1859, 13458, 5728, -1476, 229, -12, - -5, 326, -1874, 13402, 5806, -1491, 232, -12, - -5, 329, -1888, 13347, 5885, -1506, 235, -11, - -5, 332, -1902, 13290, 5963, -1521, 238, -11, - -5, 335, -1915, 13233, 6041, -1536, 241, -10, - -5, 338, -1928, 13176, 6120, -1551, 244, -10, - -5, 341, -1940, 13118, 6199, -1566, 247, -10, - -5, 344, -1952, 13059, 6277, -1580, 250, -9, - -5, 347, -1964, 13000, 6356, -1595, 253, -9, - -5, 349, -1975, 12940, 6435, -1609, 256, -8, - -4, 352, -1986, 12880, 6514, -1623, 259, -8, - -4, 354, -1996, 12819, 6594, -1637, 262, -8, - -4, 356, -2005, 12758, 6673, -1651, 265, -7, - -4, 358, -2015, 12696, 6752, -1665, 268, -7, - -4, 360, -2024, 12634, 6831, -1679, 271, -7, - -4, 362, -2032, 12572, 6911, -1693, 274, -6, - -4, 364, -2040, 12509, 6990, -1706, 277, -6, - -4, 366, -2048, 12445, 7070, -1719, 280, -6, - -3, 367, -2055, 12381, 7149, -1732, 283, -5, - -3, 369, -2062, 12316, 7229, -1745, 286, -5, - -3, 370, -2068, 12251, 7308, -1758, 289, -5, - -3, 371, -2074, 12186, 7388, -1771, 291, -4, - -3, 372, -2079, 12120, 7467, -1784, 294, -4, - -3, 373, -2084, 12054, 7547, -1796, 297, -4, - -3, 374, -2089, 11987, 7626, -1808, 300, -4, - -2, 375, -2094, 11920, 7706, -1820, 303, -3, - -2, 376, -2098, 11852, 7785, -1832, 305, -3, - -2, 376, -2101, 11785, 7865, -1844, 308, -3, - -2, 377, -2104, 11716, 7944, -1855, 311, -3, - -2, 377, -2107, 11647, 8024, -1866, 313, -2, - -2, 378, -2110, 11578, 8103, -1877, 316, -2, - -2, 378, -2112, 11509, 8182, -1888, 318, -2, - -1, 378, -2113, 11439, 8262, -1899, 321, -2, - -1, 378, -2115, 11369, 8341, -1909, 323, -2, - -1, 378, -2116, 11298, 8420, -1920, 326, -2, - -1, 378, -2116, 11227, 8499, -1930, 328, -1, - -1, 378, -2116, 11156, 8578, -1940, 331, -1, - -1, 378, -2116, 11084, 8656, -1949, 333, -1, - -1, 377, -2116, 11012, 8735, -1959, 335, -1, - -1, 377, -2115, 10940, 8814, -1968, 337, -1, - -1, 377, -2114, 10867, 8892, -1977, 340, -1, - -1, 376, -2112, 10795, 8971, -1985, 342, -1, - 0, 375, -2111, 10721, 9049, -1994, 344, -1, - 0, 375, -2108, 10648, 9127, -2002, 346, 0, - 0, 374, -2106, 10574, 9205, -2010, 348, 0, - 0, 373, -2103, 10500, 9283, -2018, 350, 0, - 0, 372, -2100, 10426, 9360, -2025, 352, 0, - 0, 371, -2097, 10351, 9438, -2032, 354, 0, - 0, 370, -2093, 10276, 9515, -2039, 355, 0, - 0, 369, -2089, 10201, 9592, -2046, 357, 0, - 0, 367, -2084, 10126, 9669, -2052, 359, 0, - 0, 366, -2080, 10050, 9745, -2058, 360, 0, - 0, 365, -2075, 9974, 9822, -2064, 362, 0, - 0, 363, -2070, 9898, 9898, -2070, 363, 0, - 0, 362, -2064, 9822, 9974, -2075, 365, 0, - 0, 360, -2058, 9745, 10050, -2080, 366, 0, - 0, 359, -2052, 9669, 10126, -2084, 367, 0, - 0, 357, -2046, 9592, 10201, -2089, 369, 0, - 0, 355, -2039, 9515, 10276, -2093, 370, 0, - 0, 354, -2032, 9438, 10351, -2097, 371, 0, - 0, 352, -2025, 9360, 10426, -2100, 372, 0, - 0, 350, -2018, 9283, 10500, -2103, 373, 0, - 0, 348, -2010, 9205, 10574, -2106, 374, 0, - 0, 346, -2002, 9127, 10648, -2108, 375, 0, - -1, 344, -1994, 9049, 10721, -2111, 375, 0, - -1, 342, -1985, 8971, 10795, -2112, 376, -1, - -1, 340, -1977, 8892, 10867, -2114, 377, -1, - -1, 337, -1968, 8814, 10940, -2115, 377, -1, - -1, 335, -1959, 8735, 11012, -2116, 377, -1, - -1, 333, -1949, 8656, 11084, -2116, 378, -1, - -1, 331, -1940, 8578, 11156, -2116, 378, -1, - -1, 328, -1930, 8499, 11227, -2116, 378, -1, - -2, 326, -1920, 8420, 11298, -2116, 378, -1, - -2, 323, -1909, 8341, 11369, -2115, 378, -1, - -2, 321, -1899, 8262, 11439, -2113, 378, -1, - -2, 318, -1888, 8182, 11509, -2112, 378, -2, - -2, 316, -1877, 8103, 11578, -2110, 378, -2, - -2, 313, -1866, 8024, 11647, -2107, 377, -2, - -3, 311, -1855, 7944, 11716, -2104, 377, -2, - -3, 308, -1844, 7865, 11785, -2101, 376, -2, - -3, 305, -1832, 7785, 11852, -2098, 376, -2, - -3, 303, -1820, 7706, 11920, -2094, 375, -2, - -4, 300, -1808, 7626, 11987, -2089, 374, -3, - -4, 297, -1796, 7547, 12054, -2084, 373, -3, - -4, 294, -1784, 7467, 12120, -2079, 372, -3, - -4, 291, -1771, 7388, 12186, -2074, 371, -3, - -5, 289, -1758, 7308, 12251, -2068, 370, -3, - -5, 286, -1745, 7229, 12316, -2062, 369, -3, - -5, 283, -1732, 7149, 12381, -2055, 367, -3, - -6, 280, -1719, 7070, 12445, -2048, 366, -4, - -6, 277, -1706, 6990, 12509, -2040, 364, -4, - -6, 274, -1693, 6911, 12572, -2032, 362, -4, - -7, 271, -1679, 6831, 12634, -2024, 360, -4, - -7, 268, -1665, 6752, 12696, -2015, 358, -4, - -7, 265, -1651, 6673, 12758, -2005, 356, -4, - -8, 262, -1637, 6594, 12819, -1996, 354, -4, - -8, 259, -1623, 6514, 12880, -1986, 352, -4, - -8, 256, -1609, 6435, 12940, -1975, 349, -5, - -9, 253, -1595, 6356, 13000, -1964, 347, -5, - -9, 250, -1580, 6277, 13059, -1952, 344, -5, - -10, 247, -1566, 6199, 13118, -1940, 341, -5, - -10, 244, -1551, 6120, 13176, -1928, 338, -5, - -10, 241, -1536, 6041, 13233, -1915, 335, -5, - -11, 238, -1521, 5963, 13290, -1902, 332, -5, - -11, 235, -1506, 5885, 13347, -1888, 329, -5, - -12, 232, -1491, 5806, 13402, -1874, 326, -5, - -12, 229, -1476, 5728, 13458, -1859, 322, -5, - -13, 225, -1461, 5651, 13512, -1844, 319, -5, - -13, 222, -1445, 5573, 13567, -1829, 315, -5, - -13, 219, -1430, 5495, 13620, -1813, 311, -6, - -14, 216, -1414, 5418, 13673, -1796, 307, -6, - -14, 213, -1399, 5340, 13726, -1779, 303, -6, - -15, 210, -1383, 5263, 13777, -1762, 299, -6, - -15, 207, -1368, 5186, 13829, -1744, 294, -6, - -16, 204, -1352, 5110, 13879, -1725, 290, -6, - -16, 201, -1336, 5033, 13929, -1706, 285, -6, - -17, 198, -1320, 4957, 13978, -1687, 280, -6, - -17, 195, -1304, 4881, 14027, -1667, 276, -5, - -18, 192, -1288, 4805, 14075, -1647, 271, -5, - -18, 189, -1272, 4729, 14123, -1626, 265, -5, - -19, 186, -1256, 4653, 14169, -1604, 260, -5, - -19, 183, -1240, 4578, 14216, -1583, 255, -5, - -20, 180, -1224, 4503, 14261, -1560, 249, -5, - -20, 177, -1208, 4428, 14306, -1537, 244, -5, - -21, 174, -1192, 4354, 14350, -1514, 238, -5, - -21, 171, -1175, 4279, 14394, -1490, 232, -5, - -22, 168, -1159, 4205, 14437, -1466, 226, -4, - -22, 165, -1143, 4131, 14479, -1441, 220, -4, - -22, 162, -1127, 4058, 14520, -1416, 213, -4, - -23, 159, -1110, 3985, 14561, -1390, 207, -4, - -23, 156, -1094, 3912, 14601, -1363, 200, -4, - -24, 153, -1078, 3839, 14640, -1337, 193, -3, - -24, 150, -1062, 3766, 14679, -1309, 187, -3, - -25, 147, -1045, 3694, 14717, -1281, 179, -3, - -25, 144, -1029, 3622, 14754, -1253, 172, -3, - -26, 142, -1013, 3551, 14791, -1224, 165, -2, - -26, 139, -996, 3480, 14827, -1194, 158, -2, - -27, 136, -980, 3409, 14862, -1164, 150, -1, - -27, 133, -964, 3338, 14896, -1134, 142, -1, - -28, 131, -948, 3268, 14930, -1103, 135, -1, - -28, 128, -931, 3198, 14963, -1071, 127, 0, - -29, 125, -915, 3128, 14995, -1039, 118, 0, - -29, 122, -899, 3059, 15027, -1007, 110, 1, - -29, 120, -883, 2990, 15057, -974, 102, 1, - -30, 117, -867, 2921, 15087, -940, 93, 2, - -30, 115, -851, 2853, 15117, -906, 85, 2, - -31, 112, -835, 2785, 15145, -871, 76, 3, - -31, 109, -819, 2718, 15173, -836, 67, 3, - -32, 107, -803, 2651, 15200, -801, 58, 4, - -32, 104, -787, 2584, 15226, -764, 49, 5, - -32, 102, -771, 2517, 15251, -728, 39, 5, - -33, 99, -755, 2451, 15276, -690, 30, 6, - -33, 97, -740, 2386, 15300, -653, 20, 7, - -33, 95, -724, 2321, 15323, -614, 10, 7, - -34, 92, -708, 2256, 15345, -576, 1, 8, - -34, 90, -693, 2191, 15366, -536, -9, 9, - -34, 88, -677, 2127, 15387, -496, -20, 10, - -35, 85, -662, 2063, 15407, -456, -30, 11, - -35, 83, -646, 2000, 15426, -415, -40, 11, - -35, 81, -631, 1937, 15445, -374, -51, 12, - -36, 79, -616, 1875, 15462, -332, -62, 13, - -36, 76, -600, 1813, 15479, -289, -72, 14, - -36, 74, -585, 1751, 15495, -247, -83, 15, - -36, 72, -570, 1690, 15510, -203, -94, 16, - -37, 70, -555, 1629, 15524, -159, -106, 17, - -37, 68, -540, 1569, 15538, -115, -117, 18, - -37, 66, -526, 1509, 15550, -70, -128, 19, - -37, 64, -511, 1450, 15562, -24, -140, 21, - -37, 62, -496, 1391, 15573, 22, -152, 22, - -38, 60, -482, 1332, 15583, 68, -164, 23, - -38, 58, -467, 1274, 15593, 115, -175, 24, - -38, 56, -453, 1216, 15601, 163, -188, 25, - -38, 54, -439, 1159, 15609, 211, -200, 27, - -38, 53, -425, 1103, 15616, 259, -212, 28, - -38, 51, -410, 1046, 15622, 309, -224, 29, - -38, 49, -396, 990, 15628, 358, -237, 31, - -38, 47, -383, 935, 15632, 408, -250, 32, - -38, 46, -369, 880, 15636, 459, -263, 33, - -38, 44, -355, 826, 15639, 510, -275, 35, - -38, 42, -342, 772, 15641, 561, -288, 36, - -38, 41, -328, 718, 15642, 613, -302, 38, +static short const cubic [514] = +{ + 0, -4, -8, -12, -16, -20, -23, -27, -30, -34, -37, -41, -44, -47, -50, -53, + -56, -59, -62, -65, -68, -71, -73, -76, -78, -81, -84, -87, -89, -91, -93, -95, + -98,-100,-102,-104,-106,-109,-110,-112,-113,-116,-117,-119,-121,-122,-123,-125, +-126,-128,-129,-131,-132,-134,-134,-136,-136,-138,-138,-140,-141,-141,-142,-143, +-144,-144,-145,-146,-147,-148,-147,-148,-148,-149,-149,-150,-150,-150,-150,-151, +-151,-151,-151,-151,-152,-152,-151,-152,-151,-152,-151,-151,-151,-151,-150,-150, +-150,-149,-149,-149,-149,-148,-147,-147,-146,-146,-145,-145,-144,-144,-143,-142, +-141,-141,-140,-139,-139,-138,-137,-136,-135,-135,-133,-133,-132,-131,-130,-129, +-128,-127,-126,-125,-124,-123,-121,-121,-119,-118,-117,-116,-115,-114,-112,-111, +-110,-109,-107,-106,-105,-104,-102,-102,-100, -99, -97, -97, -95, -94, -92, -91, + -90, -88, -87, -86, -85, -84, -82, -81, -79, -78, -76, -76, -74, -73, -71, -70, + -68, -67, -66, -65, -63, -62, -60, -60, -58, -57, -55, -55, -53, -52, -50, -49, + -48, -46, -45, -44, -43, -42, -40, -39, -38, -37, -36, -35, -34, -32, -31, -30, + -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -19, -17, -16, -15, -14, + -14, -13, -12, -11, -11, -10, -9, -9, -8, -8, -7, -7, -6, -5, -4, -4, + -3, -3, -3, -2, -2, -2, -1, -1, 0, -1, 0, -1, 0, 0, 0, 0, + 0, +2048,2048,2048,2048,2047,2047,2046,2045,2043,2042,2041,2039,2037,2035,2033,2031, +2028,2026,2024,2021,2018,2015,2012,2009,2005,2002,1999,1995,1991,1987,1982,1978, +1974,1969,1965,1960,1955,1951,1946,1940,1934,1929,1924,1918,1912,1906,1900,1895, +1888,1882,1875,1869,1862,1856,1849,1842,1835,1828,1821,1814,1806,1799,1791,1783, +1776,1768,1760,1753,1744,1737,1728,1720,1711,1703,1695,1686,1677,1668,1659,1651, +1641,1633,1623,1614,1605,1596,1587,1577,1567,1559,1549,1539,1529,1520,1510,1499, +1490,1480,1470,1460,1450,1440,1430,1420,1408,1398,1389,1378,1367,1357,1346,1336, +1325,1315,1304,1293,1282,1272,1261,1250,1239,1229,1218,1207,1196,1185,1174,1163, +1152,1141,1130,1119,1108,1097,1086,1075,1063,1052,1042,1030,1019,1008, 997, 986, + 974, 964, 952, 941, 930, 919, 908, 897, 886, 875, 864, 853, 842, 831, 820, 809, + 798, 787, 776, 765, 754, 744, 733, 722, 711, 700, 690, 679, 668, 658, 647, 637, + 626, 616, 605, 595, 584, 574, 564, 554, 543, 534, 524, 514, 503, 494, 483, 473, + 464, 454, 444, 435, 425, 416, 407, 397, 387, 378, 370, 360, 351, 342, 333, 325, + 315, 307, 298, 290, 281, 273, 265, 256, 248, 241, 233, 225, 216, 209, 201, 193, + 186, 178, 171, 164, 157, 150, 143, 137, 129, 123, 117, 110, 103, 97, 91, 85, + 79, 74, 68, 62, 56, 51, 46, 41, 35, 31, 27, 22, 17, 13, 8, 4, + 0 +}; + +static short const sinc [2048] = +{ + 39, -315, 666, 15642, 666, -315, 39, -38, + 38, -302, 613, 15642, 718, -328, 41, -38, + 36, -288, 561, 15641, 772, -342, 42, -38, + 35, -275, 510, 15639, 826, -355, 44, -38, + 33, -263, 459, 15636, 880, -369, 46, -38, + 32, -250, 408, 15632, 935, -383, 47, -38, + 31, -237, 358, 15628, 990, -396, 49, -38, + 29, -224, 309, 15622, 1046, -410, 51, -38, + 28, -212, 259, 15616, 1103, -425, 53, -38, + 27, -200, 211, 15609, 1159, -439, 54, -38, + 25, -188, 163, 15601, 1216, -453, 56, -38, + 24, -175, 115, 15593, 1274, -467, 58, -38, + 23, -164, 68, 15583, 1332, -482, 60, -38, + 22, -152, 22, 15573, 1391, -496, 62, -37, + 21, -140, -24, 15562, 1450, -511, 64, -37, + 19, -128, -70, 15550, 1509, -526, 66, -37, + 18, -117, -115, 15538, 1569, -540, 68, -37, + 17, -106, -159, 15524, 1629, -555, 70, -37, + 16, -94, -203, 15510, 1690, -570, 72, -36, + 15, -83, -247, 15495, 1751, -585, 74, -36, + 14, -72, -289, 15479, 1813, -600, 76, -36, + 13, -62, -332, 15462, 1875, -616, 79, -36, + 12, -51, -374, 15445, 1937, -631, 81, -35, + 11, -40, -415, 15426, 2000, -646, 83, -35, + 11, -30, -456, 15407, 2063, -662, 85, -35, + 10, -20, -496, 15387, 2127, -677, 88, -34, + 9, -9, -536, 15366, 2191, -693, 90, -34, + 8, 1, -576, 15345, 2256, -708, 92, -34, + 7, 10, -614, 15323, 2321, -724, 95, -33, + 7, 20, -653, 15300, 2386, -740, 97, -33, + 6, 30, -690, 15276, 2451, -755, 99, -33, + 5, 39, -728, 15251, 2517, -771, 102, -32, + 5, 49, -764, 15226, 2584, -787, 104, -32, + 4, 58, -801, 15200, 2651, -803, 107, -32, + 3, 67, -836, 15173, 2718, -819, 109, -31, + 3, 76, -871, 15145, 2785, -835, 112, -31, + 2, 85, -906, 15117, 2853, -851, 115, -30, + 2, 93, -940, 15087, 2921, -867, 117, -30, + 1, 102, -974, 15057, 2990, -883, 120, -29, + 1, 110, -1007, 15027, 3059, -899, 122, -29, + 0, 118, -1039, 14995, 3128, -915, 125, -29, + 0, 127, -1071, 14963, 3198, -931, 128, -28, + -1, 135, -1103, 14930, 3268, -948, 131, -28, + -1, 142, -1134, 14896, 3338, -964, 133, -27, + -1, 150, -1164, 14862, 3409, -980, 136, -27, + -2, 158, -1194, 14827, 3480, -996, 139, -26, + -2, 165, -1224, 14791, 3551, -1013, 142, -26, + -3, 172, -1253, 14754, 3622, -1029, 144, -25, + -3, 179, -1281, 14717, 3694, -1045, 147, -25, + -3, 187, -1309, 14679, 3766, -1062, 150, -24, + -3, 193, -1337, 14640, 3839, -1078, 153, -24, + -4, 200, -1363, 14601, 3912, -1094, 156, -23, + -4, 207, -1390, 14561, 3985, -1110, 159, -23, + -4, 213, -1416, 14520, 4058, -1127, 162, -22, + -4, 220, -1441, 14479, 4131, -1143, 165, -22, + -4, 226, -1466, 14437, 4205, -1159, 168, -22, + -5, 232, -1490, 14394, 4279, -1175, 171, -21, + -5, 238, -1514, 14350, 4354, -1192, 174, -21, + -5, 244, -1537, 14306, 4428, -1208, 177, -20, + -5, 249, -1560, 14261, 4503, -1224, 180, -20, + -5, 255, -1583, 14216, 4578, -1240, 183, -19, + -5, 260, -1604, 14169, 4653, -1256, 186, -19, + -5, 265, -1626, 14123, 4729, -1272, 189, -18, + -5, 271, -1647, 14075, 4805, -1288, 192, -18, + -5, 276, -1667, 14027, 4881, -1304, 195, -17, + -6, 280, -1687, 13978, 4957, -1320, 198, -17, + -6, 285, -1706, 13929, 5033, -1336, 201, -16, + -6, 290, -1725, 13879, 5110, -1352, 204, -16, + -6, 294, -1744, 13829, 5186, -1368, 207, -15, + -6, 299, -1762, 13777, 5263, -1383, 210, -15, + -6, 303, -1779, 13726, 5340, -1399, 213, -14, + -6, 307, -1796, 13673, 5418, -1414, 216, -14, + -6, 311, -1813, 13620, 5495, -1430, 219, -13, + -5, 315, -1829, 13567, 5573, -1445, 222, -13, + -5, 319, -1844, 13512, 5651, -1461, 225, -13, + -5, 322, -1859, 13458, 5728, -1476, 229, -12, + -5, 326, -1874, 13402, 5806, -1491, 232, -12, + -5, 329, -1888, 13347, 5885, -1506, 235, -11, + -5, 332, -1902, 13290, 5963, -1521, 238, -11, + -5, 335, -1915, 13233, 6041, -1536, 241, -10, + -5, 338, -1928, 13176, 6120, -1551, 244, -10, + -5, 341, -1940, 13118, 6199, -1566, 247, -10, + -5, 344, -1952, 13059, 6277, -1580, 250, -9, + -5, 347, -1964, 13000, 6356, -1595, 253, -9, + -5, 349, -1975, 12940, 6435, -1609, 256, -8, + -4, 352, -1986, 12880, 6514, -1623, 259, -8, + -4, 354, -1996, 12819, 6594, -1637, 262, -8, + -4, 356, -2005, 12758, 6673, -1651, 265, -7, + -4, 358, -2015, 12696, 6752, -1665, 268, -7, + -4, 360, -2024, 12634, 6831, -1679, 271, -7, + -4, 362, -2032, 12572, 6911, -1693, 274, -6, + -4, 364, -2040, 12509, 6990, -1706, 277, -6, + -4, 366, -2048, 12445, 7070, -1719, 280, -6, + -3, 367, -2055, 12381, 7149, -1732, 283, -5, + -3, 369, -2062, 12316, 7229, -1745, 286, -5, + -3, 370, -2068, 12251, 7308, -1758, 289, -5, + -3, 371, -2074, 12186, 7388, -1771, 291, -4, + -3, 372, -2079, 12120, 7467, -1784, 294, -4, + -3, 373, -2084, 12054, 7547, -1796, 297, -4, + -3, 374, -2089, 11987, 7626, -1808, 300, -4, + -2, 375, -2094, 11920, 7706, -1820, 303, -3, + -2, 376, -2098, 11852, 7785, -1832, 305, -3, + -2, 376, -2101, 11785, 7865, -1844, 308, -3, + -2, 377, -2104, 11716, 7944, -1855, 311, -3, + -2, 377, -2107, 11647, 8024, -1866, 313, -2, + -2, 378, -2110, 11578, 8103, -1877, 316, -2, + -2, 378, -2112, 11509, 8182, -1888, 318, -2, + -1, 378, -2113, 11439, 8262, -1899, 321, -2, + -1, 378, -2115, 11369, 8341, -1909, 323, -2, + -1, 378, -2116, 11298, 8420, -1920, 326, -2, + -1, 378, -2116, 11227, 8499, -1930, 328, -1, + -1, 378, -2116, 11156, 8578, -1940, 331, -1, + -1, 378, -2116, 11084, 8656, -1949, 333, -1, + -1, 377, -2116, 11012, 8735, -1959, 335, -1, + -1, 377, -2115, 10940, 8814, -1968, 337, -1, + -1, 377, -2114, 10867, 8892, -1977, 340, -1, + -1, 376, -2112, 10795, 8971, -1985, 342, -1, + 0, 375, -2111, 10721, 9049, -1994, 344, -1, + 0, 375, -2108, 10648, 9127, -2002, 346, 0, + 0, 374, -2106, 10574, 9205, -2010, 348, 0, + 0, 373, -2103, 10500, 9283, -2018, 350, 0, + 0, 372, -2100, 10426, 9360, -2025, 352, 0, + 0, 371, -2097, 10351, 9438, -2032, 354, 0, + 0, 370, -2093, 10276, 9515, -2039, 355, 0, + 0, 369, -2089, 10201, 9592, -2046, 357, 0, + 0, 367, -2084, 10126, 9669, -2052, 359, 0, + 0, 366, -2080, 10050, 9745, -2058, 360, 0, + 0, 365, -2075, 9974, 9822, -2064, 362, 0, + 0, 363, -2070, 9898, 9898, -2070, 363, 0, + 0, 362, -2064, 9822, 9974, -2075, 365, 0, + 0, 360, -2058, 9745, 10050, -2080, 366, 0, + 0, 359, -2052, 9669, 10126, -2084, 367, 0, + 0, 357, -2046, 9592, 10201, -2089, 369, 0, + 0, 355, -2039, 9515, 10276, -2093, 370, 0, + 0, 354, -2032, 9438, 10351, -2097, 371, 0, + 0, 352, -2025, 9360, 10426, -2100, 372, 0, + 0, 350, -2018, 9283, 10500, -2103, 373, 0, + 0, 348, -2010, 9205, 10574, -2106, 374, 0, + 0, 346, -2002, 9127, 10648, -2108, 375, 0, + -1, 344, -1994, 9049, 10721, -2111, 375, 0, + -1, 342, -1985, 8971, 10795, -2112, 376, -1, + -1, 340, -1977, 8892, 10867, -2114, 377, -1, + -1, 337, -1968, 8814, 10940, -2115, 377, -1, + -1, 335, -1959, 8735, 11012, -2116, 377, -1, + -1, 333, -1949, 8656, 11084, -2116, 378, -1, + -1, 331, -1940, 8578, 11156, -2116, 378, -1, + -1, 328, -1930, 8499, 11227, -2116, 378, -1, + -2, 326, -1920, 8420, 11298, -2116, 378, -1, + -2, 323, -1909, 8341, 11369, -2115, 378, -1, + -2, 321, -1899, 8262, 11439, -2113, 378, -1, + -2, 318, -1888, 8182, 11509, -2112, 378, -2, + -2, 316, -1877, 8103, 11578, -2110, 378, -2, + -2, 313, -1866, 8024, 11647, -2107, 377, -2, + -3, 311, -1855, 7944, 11716, -2104, 377, -2, + -3, 308, -1844, 7865, 11785, -2101, 376, -2, + -3, 305, -1832, 7785, 11852, -2098, 376, -2, + -3, 303, -1820, 7706, 11920, -2094, 375, -2, + -4, 300, -1808, 7626, 11987, -2089, 374, -3, + -4, 297, -1796, 7547, 12054, -2084, 373, -3, + -4, 294, -1784, 7467, 12120, -2079, 372, -3, + -4, 291, -1771, 7388, 12186, -2074, 371, -3, + -5, 289, -1758, 7308, 12251, -2068, 370, -3, + -5, 286, -1745, 7229, 12316, -2062, 369, -3, + -5, 283, -1732, 7149, 12381, -2055, 367, -3, + -6, 280, -1719, 7070, 12445, -2048, 366, -4, + -6, 277, -1706, 6990, 12509, -2040, 364, -4, + -6, 274, -1693, 6911, 12572, -2032, 362, -4, + -7, 271, -1679, 6831, 12634, -2024, 360, -4, + -7, 268, -1665, 6752, 12696, -2015, 358, -4, + -7, 265, -1651, 6673, 12758, -2005, 356, -4, + -8, 262, -1637, 6594, 12819, -1996, 354, -4, + -8, 259, -1623, 6514, 12880, -1986, 352, -4, + -8, 256, -1609, 6435, 12940, -1975, 349, -5, + -9, 253, -1595, 6356, 13000, -1964, 347, -5, + -9, 250, -1580, 6277, 13059, -1952, 344, -5, + -10, 247, -1566, 6199, 13118, -1940, 341, -5, + -10, 244, -1551, 6120, 13176, -1928, 338, -5, + -10, 241, -1536, 6041, 13233, -1915, 335, -5, + -11, 238, -1521, 5963, 13290, -1902, 332, -5, + -11, 235, -1506, 5885, 13347, -1888, 329, -5, + -12, 232, -1491, 5806, 13402, -1874, 326, -5, + -12, 229, -1476, 5728, 13458, -1859, 322, -5, + -13, 225, -1461, 5651, 13512, -1844, 319, -5, + -13, 222, -1445, 5573, 13567, -1829, 315, -5, + -13, 219, -1430, 5495, 13620, -1813, 311, -6, + -14, 216, -1414, 5418, 13673, -1796, 307, -6, + -14, 213, -1399, 5340, 13726, -1779, 303, -6, + -15, 210, -1383, 5263, 13777, -1762, 299, -6, + -15, 207, -1368, 5186, 13829, -1744, 294, -6, + -16, 204, -1352, 5110, 13879, -1725, 290, -6, + -16, 201, -1336, 5033, 13929, -1706, 285, -6, + -17, 198, -1320, 4957, 13978, -1687, 280, -6, + -17, 195, -1304, 4881, 14027, -1667, 276, -5, + -18, 192, -1288, 4805, 14075, -1647, 271, -5, + -18, 189, -1272, 4729, 14123, -1626, 265, -5, + -19, 186, -1256, 4653, 14169, -1604, 260, -5, + -19, 183, -1240, 4578, 14216, -1583, 255, -5, + -20, 180, -1224, 4503, 14261, -1560, 249, -5, + -20, 177, -1208, 4428, 14306, -1537, 244, -5, + -21, 174, -1192, 4354, 14350, -1514, 238, -5, + -21, 171, -1175, 4279, 14394, -1490, 232, -5, + -22, 168, -1159, 4205, 14437, -1466, 226, -4, + -22, 165, -1143, 4131, 14479, -1441, 220, -4, + -22, 162, -1127, 4058, 14520, -1416, 213, -4, + -23, 159, -1110, 3985, 14561, -1390, 207, -4, + -23, 156, -1094, 3912, 14601, -1363, 200, -4, + -24, 153, -1078, 3839, 14640, -1337, 193, -3, + -24, 150, -1062, 3766, 14679, -1309, 187, -3, + -25, 147, -1045, 3694, 14717, -1281, 179, -3, + -25, 144, -1029, 3622, 14754, -1253, 172, -3, + -26, 142, -1013, 3551, 14791, -1224, 165, -2, + -26, 139, -996, 3480, 14827, -1194, 158, -2, + -27, 136, -980, 3409, 14862, -1164, 150, -1, + -27, 133, -964, 3338, 14896, -1134, 142, -1, + -28, 131, -948, 3268, 14930, -1103, 135, -1, + -28, 128, -931, 3198, 14963, -1071, 127, 0, + -29, 125, -915, 3128, 14995, -1039, 118, 0, + -29, 122, -899, 3059, 15027, -1007, 110, 1, + -29, 120, -883, 2990, 15057, -974, 102, 1, + -30, 117, -867, 2921, 15087, -940, 93, 2, + -30, 115, -851, 2853, 15117, -906, 85, 2, + -31, 112, -835, 2785, 15145, -871, 76, 3, + -31, 109, -819, 2718, 15173, -836, 67, 3, + -32, 107, -803, 2651, 15200, -801, 58, 4, + -32, 104, -787, 2584, 15226, -764, 49, 5, + -32, 102, -771, 2517, 15251, -728, 39, 5, + -33, 99, -755, 2451, 15276, -690, 30, 6, + -33, 97, -740, 2386, 15300, -653, 20, 7, + -33, 95, -724, 2321, 15323, -614, 10, 7, + -34, 92, -708, 2256, 15345, -576, 1, 8, + -34, 90, -693, 2191, 15366, -536, -9, 9, + -34, 88, -677, 2127, 15387, -496, -20, 10, + -35, 85, -662, 2063, 15407, -456, -30, 11, + -35, 83, -646, 2000, 15426, -415, -40, 11, + -35, 81, -631, 1937, 15445, -374, -51, 12, + -36, 79, -616, 1875, 15462, -332, -62, 13, + -36, 76, -600, 1813, 15479, -289, -72, 14, + -36, 74, -585, 1751, 15495, -247, -83, 15, + -36, 72, -570, 1690, 15510, -203, -94, 16, + -37, 70, -555, 1629, 15524, -159, -106, 17, + -37, 68, -540, 1569, 15538, -115, -117, 18, + -37, 66, -526, 1509, 15550, -70, -128, 19, + -37, 64, -511, 1450, 15562, -24, -140, 21, + -37, 62, -496, 1391, 15573, 22, -152, 22, + -38, 60, -482, 1332, 15583, 68, -164, 23, + -38, 58, -467, 1274, 15593, 115, -175, 24, + -38, 56, -453, 1216, 15601, 163, -188, 25, + -38, 54, -439, 1159, 15609, 211, -200, 27, + -38, 53, -425, 1103, 15616, 259, -212, 28, + -38, 51, -410, 1046, 15622, 309, -224, 29, + -38, 49, -396, 990, 15628, 358, -237, 31, + -38, 47, -383, 935, 15632, 408, -250, 32, + -38, 46, -369, 880, 15636, 459, -263, 33, + -38, 44, -355, 826, 15639, 510, -275, 35, + -38, 42, -342, 772, 15641, 561, -288, 36, + -38, 41, -328, 718, 15642, 613, -302, 38, }; inline int SPC_DSP::interpolate( voice_t const* v ) @@ -453,67 +453,67 @@ return out; } -inline int SPC_DSP::interpolate_cubic( voice_t const* v ) -{ - // Make pointers into cubic based on fractional position between samples - int offset = v->interp_pos >> 4 & 0xFF; - short const* fwd = cubic + offset; - short const* rev = cubic + 256 - offset; // mirror left half of cubic - - int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; - int out; - out = fwd [ 0] * in [0]; - out += fwd [257] * in [1]; - out += rev [257] * in [2]; - out += rev [ 0] * in [3]; - out >>= 11; - - CLAMP16( out ); - out &= ~1; - return out; -} - -inline int SPC_DSP::interpolate_sinc( voice_t const* v ) -{ - // Make pointers into cubic based on fractional position between samples - int offset = v->interp_pos & 0xFF0; - short const* filt = (short const*) (((char const*)sinc) + offset); - - int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; - int out; - out = filt [0] * in [0]; - out += filt [1] * in [1]; - out += filt [2] * in [2]; - out += filt [3] * in [3]; - out += filt [4] * in [4]; - out += filt [5] * in [5]; - out += filt [6] * in [6]; - out += filt [7] * in [7]; - out >>= 14; - - CLAMP16( out ); - out &= ~1; - return out; -} - -inline int SPC_DSP::interpolate_linear( voice_t const* v ) -{ - int fract = v->interp_pos & 0xFFF; - - int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; - int out; - out = (0x1000 - fract) * in [0]; - out += fract * in [1]; - out >>= 12; - - // no need to clamp - out &= ~1; - return out; -} - -inline int SPC_DSP::interpolate_nearest( voice_t const* v ) -{ - return v->buf [(v->interp_pos >> 12) + v->buf_pos] & ~1; +inline int SPC_DSP::interpolate_cubic( voice_t const* v ) +{ + // Make pointers into cubic based on fractional position between samples + int offset = v->interp_pos >> 4 & 0xFF; + short const* fwd = cubic + offset; + short const* rev = cubic + 256 - offset; // mirror left half of cubic + + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + int out; + out = fwd [ 0] * in [0]; + out += fwd [257] * in [1]; + out += rev [257] * in [2]; + out += rev [ 0] * in [3]; + out >>= 11; + + CLAMP16( out ); + out &= ~1; + return out; +} + +inline int SPC_DSP::interpolate_sinc( voice_t const* v ) +{ + // Make pointers into cubic based on fractional position between samples + int offset = v->interp_pos & 0xFF0; + short const* filt = (short const*) (((char const*)sinc) + offset); + + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + int out; + out = filt [0] * in [0]; + out += filt [1] * in [1]; + out += filt [2] * in [2]; + out += filt [3] * in [3]; + out += filt [4] * in [4]; + out += filt [5] * in [5]; + out += filt [6] * in [6]; + out += filt [7] * in [7]; + out >>= 14; + + CLAMP16( out ); + out &= ~1; + return out; +} + +inline int SPC_DSP::interpolate_linear( voice_t const* v ) +{ + int fract = v->interp_pos & 0xFFF; + + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + int out; + out = (0x1000 - fract) * in [0]; + out += fract * in [1]; + out >>= 12; + + // no need to clamp + out &= ~1; + return out; +} + +inline int SPC_DSP::interpolate_nearest( voice_t const* v ) +{ + return v->buf [(v->interp_pos >> 12) + v->buf_pos] & ~1; } @@ -817,29 +817,29 @@ // Gaussian interpolation { int output; - - switch ( m.interpolation_level ) - { - case 0: - default: - output = interpolate( v ); - break; - - case 1: - output = interpolate_cubic( v ); - break; - - case 2: - output = interpolate_sinc( v ); - break; - - case -1: - output = interpolate_linear( v ); - break; - - case -2: - output = interpolate_nearest( v ); - break; + + switch ( m.interpolation_level ) + { + case 0: + default: + output = interpolate( v ); + break; + + case 1: + output = interpolate_cubic( v ); + break; + + case 2: + output = interpolate_sinc( v ); + break; + + case -1: + output = interpolate_linear( v ); + break; + + case -2: + output = interpolate_nearest( v ); + break; } // Noise @@ -887,10 +887,10 @@ // Apply left/right volume int amp = (m.t_output * vol) >> 7; - int abs_amp = abs( amp ); - if ( abs_amp > m.max_level[v - (const SPC_DSP::voice_t *)&m.voices][ch] ) - m.max_level[v - (const SPC_DSP::voice_t *)&m.voices][ch] = abs_amp; - + int abs_amp = abs( amp ); + if ( abs_amp > m.max_level[v - (const SPC_DSP::voice_t *)&m.voices][ch] ) + m.max_level[v - (const SPC_DSP::voice_t *)&m.voices][ch] = abs_amp; + // Add to output total m.t_main_out [ch] += amp; CLAMP16( m.t_main_out [ch] ); diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Kss_Cpu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Kss_Cpu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Kss_Cpu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Kss_Cpu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,35 +1,35 @@ -// $package. http://www.slack.net/~ant/ - -#include "Kss_Core.h" - -#include "blargg_endian.h" -//#include "z80_cpu_log.h" - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#define OUT_PORT( addr, data ) cpu_out( TIME(), addr, data ) -#define IN_PORT( addr ) cpu_in( TIME(), addr ) -#define WRITE_MEM( addr, data ) {FLUSH_TIME(); cpu_write( addr, data );} -#define IDLE_ADDR idle_addr -#define CPU cpu - -#define CPU_BEGIN \ -bool Kss_Core::run_cpu( time_t end_time )\ -{\ - cpu.set_end_time( end_time ); - - #include "Z80_Cpu_run.h" - - return warning; -} +// $package. http://www.slack.net/~ant/ + +#include "Kss_Core.h" + +#include "blargg_endian.h" +//#include "z80_cpu_log.h" + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#define OUT_PORT( addr, data ) cpu_out( TIME(), addr, data ) +#define IN_PORT( addr ) cpu_in( TIME(), addr ) +#define WRITE_MEM( addr, data ) {FLUSH_TIME(); cpu_write( addr, data );} +#define IDLE_ADDR idle_addr +#define CPU cpu + +#define CPU_BEGIN \ +bool Kss_Core::run_cpu( time_t end_time )\ +{\ + cpu.set_end_time( end_time ); + + #include "Z80_Cpu_run.h" + + return warning; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/license.txt kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/license.txt --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/license.txt 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/license.txt 2013-05-31 22:59:22.000000000 +0000 @@ -1,504 +1,504 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/M3u_Playlist.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/M3u_Playlist.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/M3u_Playlist.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/M3u_Playlist.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,476 +1,476 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "M3u_Playlist.h" -#include "Music_Emu.h" - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// gme functions defined here to avoid linking in m3u code unless it's used - -blargg_err_t Gme_File::load_m3u_( blargg_err_t err ) -{ - if ( !err ) - { - require( raw_track_count_ ); // file must be loaded first - if ( playlist.size() ) - track_count_ = playlist.size(); - - int line = playlist.first_error(); - if ( line ) - { - // avoid using bloated printf() - char* out = &playlist_warning [sizeof playlist_warning]; - *--out = 0; - do { - *--out = line % 10 + '0'; - } while ( (line /= 10) > 0 ); - - static const char str [] = "Problem in m3u at line "; - out -= sizeof str - 1; - memcpy( out, str, sizeof str - 1 ); - set_warning( out ); - } - } - return err; -} - -blargg_err_t Gme_File::load_m3u( const char path [] ) { return load_m3u_( playlist.load( path ) ); } - -blargg_err_t Gme_File::load_m3u( Data_Reader& in ) { return load_m3u_( playlist.load( in ) ); } - -gme_err_t gme_load_m3u( Music_Emu* me, const char path [] ) { return me->load_m3u( path ); } - -gme_err_t gme_load_m3u_data( Music_Emu* me, const void* data, long size ) -{ - Mem_File_Reader in( data, size ); - return me->load_m3u( in ); -} - -static char* skip_white( char* in ) -{ - while ( unsigned (*in - 1) <= ' ' - 1 ) - in++; - return in; -} - -inline unsigned from_dec( unsigned n ) { return n - '0'; } - -static char* parse_filename( char* in, M3u_Playlist::entry_t& entry ) -{ - entry.file = in; - entry.type = ""; - char* out = in; - while ( 1 ) - { - int c = *in; - if ( !c ) break; - in++; - - if ( c == ',' ) // commas in filename - { - char* p = skip_white( in ); - if ( *p == '$' || from_dec( *p ) <= 9 ) - { - in = p; - break; - } - } - - if ( c == ':' && in [0] == ':' && in [1] && in [2] != ',' ) // ::type suffix - { - entry.type = ++in; - while ( (c = *in) != 0 && c != ',' ) - in++; - if ( c == ',' ) - { - *in++ = 0; // terminate type - in = skip_white( in ); - } - break; - } - - if ( c == '\\' ) // \ prefix for special characters - { - c = *in; - if ( !c ) break; - in++; - } - *out++ = (char) c; - } - *out = 0; // terminate string - return in; -} - -static char* next_field( char* in, int* result ) -{ - while ( 1 ) - { - in = skip_white( in ); - - if ( !*in ) - break; - - if ( *in == ',' ) - { - in++; - break; - } - - *result = 1; - in++; - } - return skip_white( in ); -} - -static char* parse_int_( char* in, int* out ) -{ - int n = 0; - while ( 1 ) - { - unsigned d = from_dec( *in ); - if ( d > 9 ) - break; - in++; - n = n * 10 + d; - *out = n; - } - return in; -} - -static char* parse_int( char* in, int* out, int* result ) -{ - return next_field( parse_int_( in, out ), result ); -} - -// Returns 16 or greater if not hex -inline int from_hex_char( int h ) -{ - h -= 0x30; - if ( (unsigned) h > 9 ) - h = ((h - 0x11) & 0xDF) + 10; - return h; -} - -static char* parse_track( char* in, M3u_Playlist::entry_t& entry, int* result ) -{ - if ( *in == '$' ) - { - in++; - int n = 0; - while ( 1 ) - { - int h = from_hex_char( *in ); - if ( h > 15 ) - break; - in++; - n = n * 16 + h; - entry.track = n; - } - } - else - { - in = parse_int_( in, &entry.track ); - if ( entry.track >= 0 ) - entry.decimal_track = 1; - } - return next_field( in, result ); -} - -static char* parse_time_( char* in, int* out ) -{ - *out = -1; - int n = -1; - in = parse_int_( in, &n ); - if ( n >= 0 ) - { - *out = n; - while ( *in == ':' ) - { - n = -1; - in = parse_int_( in + 1, &n ); - if ( n >= 0 ) - *out = *out * 60 + n; - } - *out *= 1000; - if ( *in == '.' ) - { - n = -1; - in = parse_int_( in + 1, &n ); - if ( n >= 0 ) - *out = *out + n; - } - } - return in; -} - -static char* parse_time( char* in, int* out, int* result ) -{ - return next_field( parse_time_( in, out ), result ); -} - -static char* parse_name( char* in ) -{ - char* out = in; - while ( 1 ) - { - int c = *in; - if ( !c ) break; - in++; - - if ( c == ',' ) // commas in string - { - char* p = skip_white( in ); - if ( *p == ',' || *p == '-' || from_dec( *p ) <= 9 ) - { - in = p; - break; - } - } - - if ( c == '\\' ) // \ prefix for special characters - { - c = *in; - if ( !c ) break; - in++; - } - *out++ = (char) c; - } - *out = 0; // terminate string - return in; -} - -static int parse_line( char* in, M3u_Playlist::entry_t& entry ) -{ - int result = 0; - - // file - entry.file = in; - entry.type = ""; - in = parse_filename( in, entry ); - - // track - entry.track = -1; - entry.decimal_track = 0; - in = parse_track( in, entry, &result ); - - // name - entry.name = in; - in = parse_name( in ); - - // time - entry.length = -1; - in = parse_time( in, &entry.length, &result ); - - // loop - entry.intro = -1; - entry.loop = -1; - if ( *in == '-' ) - { - entry.loop = entry.length; - in++; - } - else - { - in = parse_time_( in, &entry.loop ); - if ( entry.loop >= 0 ) - { - entry.intro = entry.length - entry.loop; - if ( *in == '-' ) // trailing '-' means that intro length was specified - { - in++; - entry.intro = entry.loop; - entry.loop = entry.length - entry.intro; - } - } - } - in = next_field( in, &result ); - - // fade - entry.fade = -1; - in = parse_time( in, &entry.fade, &result ); - - // repeat - entry.repeat = -1; - in = parse_int( in, &entry.repeat, &result ); - - return result; -} - -static void parse_comment( char* in, M3u_Playlist::info_t& info, char *& last_comment_value, bool first ) -{ - in = skip_white( in + 1 ); - const char* field = in; - if ( *field != '@' ) - while ( *in && *in != ':' ) - in++; - - if ( *in == ':' ) - { - const char* text = skip_white( in + 1 ); - if ( *text ) - { - *in = 0; - if ( !strcmp( "Composer" , field ) ) info.composer = text; - else if ( !strcmp( "Engineer" , field ) ) info.engineer = text; - else if ( !strcmp( "Ripping" , field ) ) info.ripping = text; - else if ( !strcmp( "Tagging" , field ) ) info.tagging = text; - else if ( !strcmp( "Game" , field ) ) info.title = text; - else if ( !strcmp( "Artist" , field ) ) info.artist = text; - else if ( !strcmp( "Copyright", field ) ) info.copyright = text; - else - text = 0; - if ( text ) - return; - *in = ':'; - } - } - else if ( *field == '@' ) - { - ++field; - in = (char*)field; - while ( *in && *in > ' ' ) - in++; - const char* text = skip_white( in ); - if ( *text ) - { - char saved = *in; - *in = 0; - if ( !strcmp( "TITLE" , field ) ) info.title = text; - else if ( !strcmp( "ARTIST", field ) ) info.artist = text; - else if ( !strcmp( "DATE", field ) ) info.date = text; - else if ( !strcmp( "COMPOSER", field ) ) info.composer = text; - else if ( !strcmp( "SEQUENCER", field ) ) info.sequencer = text; - else if ( !strcmp( "ENGINEER", field ) ) info.engineer = text; - else if ( !strcmp( "RIPPER", field ) ) info.ripping = text; - else if ( !strcmp( "TAGGER", field ) ) info.tagging = text; - else - text = 0; - if ( text ) - { - last_comment_value = (char*)text; - return; - } - *in = saved; - } - } - else if ( last_comment_value ) - { - size_t len = strlen( last_comment_value ); - last_comment_value[ len ] = ','; - last_comment_value[ len + 1 ] = ' '; - size_t field_len = strlen( field ); - memmove( last_comment_value + len + 2, field, field_len ); - last_comment_value[ len + 2 + field_len ] = 0; - return; - } - - if ( first ) - info.title = field; -} - -blargg_err_t M3u_Playlist::parse_() -{ - info_.title = ""; - info_.artist = ""; - info_.date = ""; - info_.composer = ""; - info_.sequencer = ""; - info_.engineer = ""; - info_.ripping = ""; - info_.tagging = ""; - info_.copyright = ""; - - int const CR = 13; - int const LF = 10; - - data.end() [-1] = LF; // terminate input - - first_error_ = 0; - bool first_comment = true; - int line = 0; - int count = 0; - char* in = data.begin(); - char* last_comment_value = 0; - while ( in < data.end() ) - { - // find end of line and terminate it - line++; - char* begin = in; - while ( *in != CR && *in != LF ) - { - if ( !*in ) - return blargg_err_file_type; - in++; - } - if ( in [0] == CR && in [1] == LF ) // treat CR,LF as a single line - *in++ = 0; - *in++ = 0; - - // parse line - if ( *begin == '#' ) - { - parse_comment( begin, info_, last_comment_value, first_comment ); - first_comment = false; - } - else if ( *begin ) - { - if ( (int) entries.size() <= count ) - RETURN_ERR( entries.resize( count * 2 + 64 ) ); - - if ( !parse_line( begin, entries [count] ) ) - count++; - else if ( !first_error_ ) - first_error_ = line; - first_comment = false; - } - else last_comment_value = 0; - } - if ( count <= 0 ) - return blargg_err_file_type; - - // Treat first comment as title only if another field is also specified - if ( !(info_.artist [0] | info_.composer [0] | info_.date [0] | info_.engineer [0] | info_.ripping [0] | info_.sequencer [0] | info_.tagging [0] | info_.copyright[0]) ) - info_.title = ""; - - return entries.resize( count ); -} - -blargg_err_t M3u_Playlist::parse() -{ - blargg_err_t err = parse_(); - if ( err ) - clear_(); - return err; -} - -blargg_err_t M3u_Playlist::load( Data_Reader& in ) -{ - RETURN_ERR( data.resize( in.remain() + 1 ) ); - RETURN_ERR( in.read( data.begin(), data.size() - 1 ) ); - return parse(); -} - -blargg_err_t M3u_Playlist::load( const char path [] ) -{ - GME_FILE_READER in; - RETURN_ERR( in.open( path ) ); - return load( in ); -} - -blargg_err_t M3u_Playlist::load( void const* in, long size ) -{ - RETURN_ERR( data.resize( size + 1 ) ); - memcpy( data.begin(), in, size ); - return parse(); -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "M3u_Playlist.h" +#include "Music_Emu.h" + +/* Copyright (C) 2006 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// gme functions defined here to avoid linking in m3u code unless it's used + +blargg_err_t Gme_File::load_m3u_( blargg_err_t err ) +{ + if ( !err ) + { + require( raw_track_count_ ); // file must be loaded first + if ( playlist.size() ) + track_count_ = playlist.size(); + + int line = playlist.first_error(); + if ( line ) + { + // avoid using bloated printf() + char* out = &playlist_warning [sizeof playlist_warning]; + *--out = 0; + do { + *--out = line % 10 + '0'; + } while ( (line /= 10) > 0 ); + + static const char str [] = "Problem in m3u at line "; + out -= sizeof str - 1; + memcpy( out, str, sizeof str - 1 ); + set_warning( out ); + } + } + return err; +} + +blargg_err_t Gme_File::load_m3u( const char path [] ) { return load_m3u_( playlist.load( path ) ); } + +blargg_err_t Gme_File::load_m3u( Data_Reader& in ) { return load_m3u_( playlist.load( in ) ); } + +gme_err_t gme_load_m3u( Music_Emu* me, const char path [] ) { return me->load_m3u( path ); } + +gme_err_t gme_load_m3u_data( Music_Emu* me, const void* data, long size ) +{ + Mem_File_Reader in( data, size ); + return me->load_m3u( in ); +} + +static char* skip_white( char* in ) +{ + while ( unsigned (*in - 1) <= ' ' - 1 ) + in++; + return in; +} + +inline unsigned from_dec( unsigned n ) { return n - '0'; } + +static char* parse_filename( char* in, M3u_Playlist::entry_t& entry ) +{ + entry.file = in; + entry.type = ""; + char* out = in; + while ( 1 ) + { + int c = *in; + if ( !c ) break; + in++; + + if ( c == ',' ) // commas in filename + { + char* p = skip_white( in ); + if ( *p == '$' || from_dec( *p ) <= 9 ) + { + in = p; + break; + } + } + + if ( c == ':' && in [0] == ':' && in [1] && in [2] != ',' ) // ::type suffix + { + entry.type = ++in; + while ( (c = *in) != 0 && c != ',' ) + in++; + if ( c == ',' ) + { + *in++ = 0; // terminate type + in = skip_white( in ); + } + break; + } + + if ( c == '\\' ) // \ prefix for special characters + { + c = *in; + if ( !c ) break; + in++; + } + *out++ = (char) c; + } + *out = 0; // terminate string + return in; +} + +static char* next_field( char* in, int* result ) +{ + while ( 1 ) + { + in = skip_white( in ); + + if ( !*in ) + break; + + if ( *in == ',' ) + { + in++; + break; + } + + *result = 1; + in++; + } + return skip_white( in ); +} + +static char* parse_int_( char* in, int* out ) +{ + int n = 0; + while ( 1 ) + { + unsigned d = from_dec( *in ); + if ( d > 9 ) + break; + in++; + n = n * 10 + d; + *out = n; + } + return in; +} + +static char* parse_int( char* in, int* out, int* result ) +{ + return next_field( parse_int_( in, out ), result ); +} + +// Returns 16 or greater if not hex +inline int from_hex_char( int h ) +{ + h -= 0x30; + if ( (unsigned) h > 9 ) + h = ((h - 0x11) & 0xDF) + 10; + return h; +} + +static char* parse_track( char* in, M3u_Playlist::entry_t& entry, int* result ) +{ + if ( *in == '$' ) + { + in++; + int n = 0; + while ( 1 ) + { + int h = from_hex_char( *in ); + if ( h > 15 ) + break; + in++; + n = n * 16 + h; + entry.track = n; + } + } + else + { + in = parse_int_( in, &entry.track ); + if ( entry.track >= 0 ) + entry.decimal_track = 1; + } + return next_field( in, result ); +} + +static char* parse_time_( char* in, int* out ) +{ + *out = -1; + int n = -1; + in = parse_int_( in, &n ); + if ( n >= 0 ) + { + *out = n; + while ( *in == ':' ) + { + n = -1; + in = parse_int_( in + 1, &n ); + if ( n >= 0 ) + *out = *out * 60 + n; + } + *out *= 1000; + if ( *in == '.' ) + { + n = -1; + in = parse_int_( in + 1, &n ); + if ( n >= 0 ) + *out = *out + n; + } + } + return in; +} + +static char* parse_time( char* in, int* out, int* result ) +{ + return next_field( parse_time_( in, out ), result ); +} + +static char* parse_name( char* in ) +{ + char* out = in; + while ( 1 ) + { + int c = *in; + if ( !c ) break; + in++; + + if ( c == ',' ) // commas in string + { + char* p = skip_white( in ); + if ( *p == ',' || *p == '-' || from_dec( *p ) <= 9 ) + { + in = p; + break; + } + } + + if ( c == '\\' ) // \ prefix for special characters + { + c = *in; + if ( !c ) break; + in++; + } + *out++ = (char) c; + } + *out = 0; // terminate string + return in; +} + +static int parse_line( char* in, M3u_Playlist::entry_t& entry ) +{ + int result = 0; + + // file + entry.file = in; + entry.type = ""; + in = parse_filename( in, entry ); + + // track + entry.track = -1; + entry.decimal_track = 0; + in = parse_track( in, entry, &result ); + + // name + entry.name = in; + in = parse_name( in ); + + // time + entry.length = -1; + in = parse_time( in, &entry.length, &result ); + + // loop + entry.intro = -1; + entry.loop = -1; + if ( *in == '-' ) + { + entry.loop = entry.length; + in++; + } + else + { + in = parse_time_( in, &entry.loop ); + if ( entry.loop >= 0 ) + { + entry.intro = entry.length - entry.loop; + if ( *in == '-' ) // trailing '-' means that intro length was specified + { + in++; + entry.intro = entry.loop; + entry.loop = entry.length - entry.intro; + } + } + } + in = next_field( in, &result ); + + // fade + entry.fade = -1; + in = parse_time( in, &entry.fade, &result ); + + // repeat + entry.repeat = -1; + in = parse_int( in, &entry.repeat, &result ); + + return result; +} + +static void parse_comment( char* in, M3u_Playlist::info_t& info, char *& last_comment_value, bool first ) +{ + in = skip_white( in + 1 ); + const char* field = in; + if ( *field != '@' ) + while ( *in && *in != ':' ) + in++; + + if ( *in == ':' ) + { + const char* text = skip_white( in + 1 ); + if ( *text ) + { + *in = 0; + if ( !strcmp( "Composer" , field ) ) info.composer = text; + else if ( !strcmp( "Engineer" , field ) ) info.engineer = text; + else if ( !strcmp( "Ripping" , field ) ) info.ripping = text; + else if ( !strcmp( "Tagging" , field ) ) info.tagging = text; + else if ( !strcmp( "Game" , field ) ) info.title = text; + else if ( !strcmp( "Artist" , field ) ) info.artist = text; + else if ( !strcmp( "Copyright", field ) ) info.copyright = text; + else + text = 0; + if ( text ) + return; + *in = ':'; + } + } + else if ( *field == '@' ) + { + ++field; + in = (char*)field; + while ( *in && *in > ' ' ) + in++; + const char* text = skip_white( in ); + if ( *text ) + { + char saved = *in; + *in = 0; + if ( !strcmp( "TITLE" , field ) ) info.title = text; + else if ( !strcmp( "ARTIST", field ) ) info.artist = text; + else if ( !strcmp( "DATE", field ) ) info.date = text; + else if ( !strcmp( "COMPOSER", field ) ) info.composer = text; + else if ( !strcmp( "SEQUENCER", field ) ) info.sequencer = text; + else if ( !strcmp( "ENGINEER", field ) ) info.engineer = text; + else if ( !strcmp( "RIPPER", field ) ) info.ripping = text; + else if ( !strcmp( "TAGGER", field ) ) info.tagging = text; + else + text = 0; + if ( text ) + { + last_comment_value = (char*)text; + return; + } + *in = saved; + } + } + else if ( last_comment_value ) + { + size_t len = strlen( last_comment_value ); + last_comment_value[ len ] = ','; + last_comment_value[ len + 1 ] = ' '; + size_t field_len = strlen( field ); + memmove( last_comment_value + len + 2, field, field_len ); + last_comment_value[ len + 2 + field_len ] = 0; + return; + } + + if ( first ) + info.title = field; +} + +blargg_err_t M3u_Playlist::parse_() +{ + info_.title = ""; + info_.artist = ""; + info_.date = ""; + info_.composer = ""; + info_.sequencer = ""; + info_.engineer = ""; + info_.ripping = ""; + info_.tagging = ""; + info_.copyright = ""; + + int const CR = 13; + int const LF = 10; + + data.end() [-1] = LF; // terminate input + + first_error_ = 0; + bool first_comment = true; + int line = 0; + int count = 0; + char* in = data.begin(); + char* last_comment_value = 0; + while ( in < data.end() ) + { + // find end of line and terminate it + line++; + char* begin = in; + while ( *in != CR && *in != LF ) + { + if ( !*in ) + return blargg_err_file_type; + in++; + } + if ( in [0] == CR && in [1] == LF ) // treat CR,LF as a single line + *in++ = 0; + *in++ = 0; + + // parse line + if ( *begin == '#' ) + { + parse_comment( begin, info_, last_comment_value, first_comment ); + first_comment = false; + } + else if ( *begin ) + { + if ( (int) entries.size() <= count ) + RETURN_ERR( entries.resize( count * 2 + 64 ) ); + + if ( !parse_line( begin, entries [count] ) ) + count++; + else if ( !first_error_ ) + first_error_ = line; + first_comment = false; + } + else last_comment_value = 0; + } + if ( count <= 0 ) + return blargg_err_file_type; + + // Treat first comment as title only if another field is also specified + if ( !(info_.artist [0] | info_.composer [0] | info_.date [0] | info_.engineer [0] | info_.ripping [0] | info_.sequencer [0] | info_.tagging [0] | info_.copyright[0]) ) + info_.title = ""; + + return entries.resize( count ); +} + +blargg_err_t M3u_Playlist::parse() +{ + blargg_err_t err = parse_(); + if ( err ) + clear_(); + return err; +} + +blargg_err_t M3u_Playlist::load( Data_Reader& in ) +{ + RETURN_ERR( data.resize( in.remain() + 1 ) ); + RETURN_ERR( in.read( data.begin(), data.size() - 1 ) ); + return parse(); +} + +blargg_err_t M3u_Playlist::load( const char path [] ) +{ + GME_FILE_READER in; + RETURN_ERR( in.open( path ) ); + return load( in ); +} + +blargg_err_t M3u_Playlist::load( void const* in, long size ) +{ + RETURN_ERR( data.resize( size + 1 ) ); + memcpy( data.begin(), in, size ); + return parse(); +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/M3u_Playlist.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/M3u_Playlist.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/M3u_Playlist.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/M3u_Playlist.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,87 +1,87 @@ -// M3U playlist file parser, with support for subtrack information - -// Game_Music_Emu $vers -#ifndef M3U_PLAYLIST_H -#define M3U_PLAYLIST_H - -#include "blargg_common.h" -#include "Data_Reader.h" - -class M3u_Playlist { -public: - // Load playlist data - blargg_err_t load( const char* path ); - blargg_err_t load( Data_Reader& in ); - blargg_err_t load( void const* data, long size ); - - // Line number of first parse error, 0 if no error. Any lines with parse - // errors are ignored. - int first_error() const { return first_error_; } - - // All string pointers point to valid string, or "" if not available - struct info_t - { - const char* title; - const char* artist; - const char* date; - const char* composer; - const char* sequencer; - const char* engineer; - const char* ripping; - const char* tagging; - const char* copyright; - }; - info_t const& info() const { return info_; } - - struct entry_t - { - const char* file; // filename without stupid ::TYPE suffix - const char* type; // if filename has ::TYPE suffix, this is "TYPE", otherwise "" - const char* name; - bool decimal_track; // true if track was specified in decimal - // integers are -1 if not present - int track; - int length; // milliseconds - int intro; - int loop; - int fade; - int repeat; // count - }; - entry_t const& operator [] ( int i ) const { return entries [i]; } - int size() const { return entries.size(); } - - void clear(); - -private: - blargg_vector entries; - blargg_vector data; - int first_error_; - info_t info_; - - blargg_err_t parse(); - blargg_err_t parse_(); - void clear_(); -}; - -inline void M3u_Playlist::clear_() -{ - info_.title = ""; - info_.artist = ""; - info_.date = ""; - info_.composer = ""; - info_.sequencer = ""; - info_.engineer = ""; - info_.ripping = ""; - info_.tagging = ""; - info_.copyright = ""; - entries.clear(); - data.clear(); -} - -inline void M3u_Playlist::clear() -{ - first_error_ = 0; - clear_(); -} - -#endif +// M3U playlist file parser, with support for subtrack information + +// Game_Music_Emu $vers +#ifndef M3U_PLAYLIST_H +#define M3U_PLAYLIST_H + +#include "blargg_common.h" +#include "Data_Reader.h" + +class M3u_Playlist { +public: + // Load playlist data + blargg_err_t load( const char* path ); + blargg_err_t load( Data_Reader& in ); + blargg_err_t load( void const* data, long size ); + + // Line number of first parse error, 0 if no error. Any lines with parse + // errors are ignored. + int first_error() const { return first_error_; } + + // All string pointers point to valid string, or "" if not available + struct info_t + { + const char* title; + const char* artist; + const char* date; + const char* composer; + const char* sequencer; + const char* engineer; + const char* ripping; + const char* tagging; + const char* copyright; + }; + info_t const& info() const { return info_; } + + struct entry_t + { + const char* file; // filename without stupid ::TYPE suffix + const char* type; // if filename has ::TYPE suffix, this is "TYPE", otherwise "" + const char* name; + bool decimal_track; // true if track was specified in decimal + // integers are -1 if not present + int track; + int length; // milliseconds + int intro; + int loop; + int fade; + int repeat; // count + }; + entry_t const& operator [] ( int i ) const { return entries [i]; } + int size() const { return entries.size(); } + + void clear(); + +private: + blargg_vector entries; + blargg_vector data; + int first_error_; + info_t info_; + + blargg_err_t parse(); + blargg_err_t parse_(); + void clear_(); +}; + +inline void M3u_Playlist::clear_() +{ + info_.title = ""; + info_.artist = ""; + info_.date = ""; + info_.composer = ""; + info_.sequencer = ""; + info_.engineer = ""; + info_.ripping = ""; + info_.tagging = ""; + info_.copyright = ""; + entries.clear(); + data.clear(); +} + +inline void M3u_Playlist::clear() +{ + first_error_ = 0; + clear_(); +} + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Multi_Buffer.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Multi_Buffer.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Multi_Buffer.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Multi_Buffer.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,290 +1,290 @@ -// Blip_Buffer $vers. http://www.slack.net/~ant/ - -#include "Multi_Buffer.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf ) -{ - length_ = 0; - sample_rate_ = 0; - channels_changed_count_ = 1; - channel_types_ = NULL; - channel_count_ = 0; - immediate_removal_ = true; -} - -Multi_Buffer::channel_t Multi_Buffer::channel( int /*index*/ ) -{ - channel_t ch; - ch.center = ch.left = ch.right = NULL; - return ch; -} - -// Silent_Buffer - -Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse -{ - // TODO: better to use empty Blip_Buffer so caller never has to check for NULL? - chan.left = NULL; - chan.center = NULL; - chan.right = NULL; -} - -// Mono_Buffer - -Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 ) -{ - chan.center = &buf; - chan.left = &buf; - chan.right = &buf; -} - -Mono_Buffer::~Mono_Buffer() { } - -blargg_err_t Mono_Buffer::set_sample_rate( int rate, int msec ) -{ - RETURN_ERR( buf.set_sample_rate( rate, msec ) ); - return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() ); -} - - -// Tracked_Blip_Buffer - -int const blip_buffer_extra = 32; // TODO: explain why this value - -Tracked_Blip_Buffer::Tracked_Blip_Buffer() -{ - last_non_silence = 0; -} - -void Tracked_Blip_Buffer::clear() -{ - last_non_silence = 0; - Blip_Buffer::clear(); -} - -void Tracked_Blip_Buffer::end_frame( blip_time_t t ) -{ - Blip_Buffer::end_frame( t ); - if ( modified() ) - { - clear_modified(); - last_non_silence = samples_avail() + blip_buffer_extra; - } -} - -unsigned Tracked_Blip_Buffer::non_silent() const -{ - return last_non_silence | unsettled(); -} - -inline void Tracked_Blip_Buffer::remove_( int n ) -{ - if ( (last_non_silence -= n) < 0 ) - last_non_silence = 0; -} - -void Tracked_Blip_Buffer::remove_silence( int n ) -{ - remove_( n ); - Blip_Buffer::remove_silence( n ); -} - -void Tracked_Blip_Buffer::remove_samples( int n ) -{ - remove_( n ); - Blip_Buffer::remove_samples( n ); -} - -void Tracked_Blip_Buffer::remove_all_samples() -{ - int avail = samples_avail(); - if ( !non_silent() ) - remove_silence( avail ); - else - remove_samples( avail ); -} - -int Tracked_Blip_Buffer::read_samples( blip_sample_t out [], int count ) -{ - count = Blip_Buffer::read_samples( out, count ); - remove_( count ); - return count; -} - -// Stereo_Buffer - -int const stereo = 2; - -Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 ) -{ - chan.center = mixer.bufs [2] = &bufs [2]; - chan.left = mixer.bufs [0] = &bufs [0]; - chan.right = mixer.bufs [1] = &bufs [1]; - mixer.samples_read = 0; -} - -Stereo_Buffer::~Stereo_Buffer() { } - -blargg_err_t Stereo_Buffer::set_sample_rate( int rate, int msec ) -{ - mixer.samples_read = 0; - for ( int i = bufs_size; --i >= 0; ) - RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) ); - return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() ); -} - -void Stereo_Buffer::clock_rate( int rate ) -{ - for ( int i = bufs_size; --i >= 0; ) - bufs [i].clock_rate( rate ); -} - -void Stereo_Buffer::bass_freq( int bass ) -{ - for ( int i = bufs_size; --i >= 0; ) - bufs [i].bass_freq( bass ); -} - -void Stereo_Buffer::clear() -{ - mixer.samples_read = 0; - for ( int i = bufs_size; --i >= 0; ) - bufs [i].clear(); -} - -void Stereo_Buffer::end_frame( blip_time_t time ) -{ - for ( int i = bufs_size; --i >= 0; ) - bufs [i].end_frame( time ); -} - -int Stereo_Buffer::read_samples( blip_sample_t out [], int out_size ) -{ - require( (out_size & 1) == 0 ); // must read an even number of samples - out_size = min( out_size, samples_avail() ); - - int pair_count = int (out_size >> 1); - if ( pair_count ) - { - mixer.read_pairs( out, pair_count ); - - if ( samples_avail() <= 0 || immediate_removal() ) - { - for ( int i = bufs_size; --i >= 0; ) - { - buf_t& b = bufs [i]; - // TODO: might miss non-silence settling since it checks END of last read - if ( !b.non_silent() ) - b.remove_silence( mixer.samples_read ); - else - b.remove_samples( mixer.samples_read ); - } - mixer.samples_read = 0; - } - } - return out_size; -} - - -// Stereo_Mixer - -// mixers use a single index value to improve performance on register-challenged processors -// offset goes from negative to zero - -void Stereo_Mixer::read_pairs( blip_sample_t out [], int count ) -{ - // TODO: if caller never marks buffers as modified, uses mono - // except that buffer isn't cleared, so caller can encounter - // subtle problems and not realize the cause. - samples_read += count; - if ( bufs [0]->non_silent() | bufs [1]->non_silent() ) - mix_stereo( out, count ); - else - mix_mono( out, count ); -} - -void Stereo_Mixer::mix_mono( blip_sample_t out_ [], int count ) -{ - int const bass = bufs [2]->highpass_shift(); - Blip_Buffer::delta_t const* center = bufs [2]->read_pos() + samples_read; - int center_sum = bufs [2]->integrator(); - - typedef blip_sample_t stereo_blip_sample_t [stereo]; - stereo_blip_sample_t* BLARGG_RESTRICT out = (stereo_blip_sample_t*) out_ + count; - int offset = -count; - do - { - int s = center_sum >> bufs [2]->delta_bits; - - center_sum -= center_sum >> bass; - center_sum += center [offset]; - - BLIP_CLAMP( s, s ); - - out [offset] [0] = (blip_sample_t) s; - out [offset] [1] = (blip_sample_t) s; - } - while ( ++offset ); - - bufs [2]->set_integrator( center_sum ); -} - -void Stereo_Mixer::mix_stereo( blip_sample_t out_ [], int count ) -{ - blip_sample_t* BLARGG_RESTRICT out = out_ + count * stereo; - - // do left + center and right + center separately to reduce register load - Tracked_Blip_Buffer* const* buf = &bufs [2]; - while ( true ) // loop runs twice - { - --buf; - --out; - - int const bass = bufs [2]->highpass_shift(); - Blip_Buffer::delta_t const* side = (*buf)->read_pos() + samples_read; - Blip_Buffer::delta_t const* center = bufs [2]->read_pos() + samples_read; - - int side_sum = (*buf)->integrator(); - int center_sum = bufs [2]->integrator(); - - int offset = -count; - do - { - int s = (center_sum + side_sum) >> Blip_Buffer::delta_bits; - - side_sum -= side_sum >> bass; - center_sum -= center_sum >> bass; - - side_sum += side [offset]; - center_sum += center [offset]; - - BLIP_CLAMP( s, s ); - - ++offset; // before write since out is decremented to slightly before end - out [offset * stereo] = (blip_sample_t) s; - } - while ( offset ); - - (*buf)->set_integrator( side_sum ); - - if ( buf != bufs ) - continue; - - // only end center once - bufs [2]->set_integrator( center_sum ); - break; - } -} +// Blip_Buffer $vers. http://www.slack.net/~ant/ + +#include "Multi_Buffer.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf ) +{ + length_ = 0; + sample_rate_ = 0; + channels_changed_count_ = 1; + channel_types_ = NULL; + channel_count_ = 0; + immediate_removal_ = true; +} + +Multi_Buffer::channel_t Multi_Buffer::channel( int /*index*/ ) +{ + channel_t ch; + ch.center = ch.left = ch.right = NULL; + return ch; +} + +// Silent_Buffer + +Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse +{ + // TODO: better to use empty Blip_Buffer so caller never has to check for NULL? + chan.left = NULL; + chan.center = NULL; + chan.right = NULL; +} + +// Mono_Buffer + +Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 ) +{ + chan.center = &buf; + chan.left = &buf; + chan.right = &buf; +} + +Mono_Buffer::~Mono_Buffer() { } + +blargg_err_t Mono_Buffer::set_sample_rate( int rate, int msec ) +{ + RETURN_ERR( buf.set_sample_rate( rate, msec ) ); + return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() ); +} + + +// Tracked_Blip_Buffer + +int const blip_buffer_extra = 32; // TODO: explain why this value + +Tracked_Blip_Buffer::Tracked_Blip_Buffer() +{ + last_non_silence = 0; +} + +void Tracked_Blip_Buffer::clear() +{ + last_non_silence = 0; + Blip_Buffer::clear(); +} + +void Tracked_Blip_Buffer::end_frame( blip_time_t t ) +{ + Blip_Buffer::end_frame( t ); + if ( modified() ) + { + clear_modified(); + last_non_silence = samples_avail() + blip_buffer_extra; + } +} + +unsigned Tracked_Blip_Buffer::non_silent() const +{ + return last_non_silence | unsettled(); +} + +inline void Tracked_Blip_Buffer::remove_( int n ) +{ + if ( (last_non_silence -= n) < 0 ) + last_non_silence = 0; +} + +void Tracked_Blip_Buffer::remove_silence( int n ) +{ + remove_( n ); + Blip_Buffer::remove_silence( n ); +} + +void Tracked_Blip_Buffer::remove_samples( int n ) +{ + remove_( n ); + Blip_Buffer::remove_samples( n ); +} + +void Tracked_Blip_Buffer::remove_all_samples() +{ + int avail = samples_avail(); + if ( !non_silent() ) + remove_silence( avail ); + else + remove_samples( avail ); +} + +int Tracked_Blip_Buffer::read_samples( blip_sample_t out [], int count ) +{ + count = Blip_Buffer::read_samples( out, count ); + remove_( count ); + return count; +} + +// Stereo_Buffer + +int const stereo = 2; + +Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 ) +{ + chan.center = mixer.bufs [2] = &bufs [2]; + chan.left = mixer.bufs [0] = &bufs [0]; + chan.right = mixer.bufs [1] = &bufs [1]; + mixer.samples_read = 0; +} + +Stereo_Buffer::~Stereo_Buffer() { } + +blargg_err_t Stereo_Buffer::set_sample_rate( int rate, int msec ) +{ + mixer.samples_read = 0; + for ( int i = bufs_size; --i >= 0; ) + RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) ); + return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() ); +} + +void Stereo_Buffer::clock_rate( int rate ) +{ + for ( int i = bufs_size; --i >= 0; ) + bufs [i].clock_rate( rate ); +} + +void Stereo_Buffer::bass_freq( int bass ) +{ + for ( int i = bufs_size; --i >= 0; ) + bufs [i].bass_freq( bass ); +} + +void Stereo_Buffer::clear() +{ + mixer.samples_read = 0; + for ( int i = bufs_size; --i >= 0; ) + bufs [i].clear(); +} + +void Stereo_Buffer::end_frame( blip_time_t time ) +{ + for ( int i = bufs_size; --i >= 0; ) + bufs [i].end_frame( time ); +} + +int Stereo_Buffer::read_samples( blip_sample_t out [], int out_size ) +{ + require( (out_size & 1) == 0 ); // must read an even number of samples + out_size = min( out_size, samples_avail() ); + + int pair_count = int (out_size >> 1); + if ( pair_count ) + { + mixer.read_pairs( out, pair_count ); + + if ( samples_avail() <= 0 || immediate_removal() ) + { + for ( int i = bufs_size; --i >= 0; ) + { + buf_t& b = bufs [i]; + // TODO: might miss non-silence settling since it checks END of last read + if ( !b.non_silent() ) + b.remove_silence( mixer.samples_read ); + else + b.remove_samples( mixer.samples_read ); + } + mixer.samples_read = 0; + } + } + return out_size; +} + + +// Stereo_Mixer + +// mixers use a single index value to improve performance on register-challenged processors +// offset goes from negative to zero + +void Stereo_Mixer::read_pairs( blip_sample_t out [], int count ) +{ + // TODO: if caller never marks buffers as modified, uses mono + // except that buffer isn't cleared, so caller can encounter + // subtle problems and not realize the cause. + samples_read += count; + if ( bufs [0]->non_silent() | bufs [1]->non_silent() ) + mix_stereo( out, count ); + else + mix_mono( out, count ); +} + +void Stereo_Mixer::mix_mono( blip_sample_t out_ [], int count ) +{ + int const bass = bufs [2]->highpass_shift(); + Blip_Buffer::delta_t const* center = bufs [2]->read_pos() + samples_read; + int center_sum = bufs [2]->integrator(); + + typedef blip_sample_t stereo_blip_sample_t [stereo]; + stereo_blip_sample_t* BLARGG_RESTRICT out = (stereo_blip_sample_t*) out_ + count; + int offset = -count; + do + { + int s = center_sum >> bufs [2]->delta_bits; + + center_sum -= center_sum >> bass; + center_sum += center [offset]; + + BLIP_CLAMP( s, s ); + + out [offset] [0] = (blip_sample_t) s; + out [offset] [1] = (blip_sample_t) s; + } + while ( ++offset ); + + bufs [2]->set_integrator( center_sum ); +} + +void Stereo_Mixer::mix_stereo( blip_sample_t out_ [], int count ) +{ + blip_sample_t* BLARGG_RESTRICT out = out_ + count * stereo; + + // do left + center and right + center separately to reduce register load + Tracked_Blip_Buffer* const* buf = &bufs [2]; + while ( true ) // loop runs twice + { + --buf; + --out; + + int const bass = bufs [2]->highpass_shift(); + Blip_Buffer::delta_t const* side = (*buf)->read_pos() + samples_read; + Blip_Buffer::delta_t const* center = bufs [2]->read_pos() + samples_read; + + int side_sum = (*buf)->integrator(); + int center_sum = bufs [2]->integrator(); + + int offset = -count; + do + { + int s = (center_sum + side_sum) >> Blip_Buffer::delta_bits; + + side_sum -= side_sum >> bass; + center_sum -= center_sum >> bass; + + side_sum += side [offset]; + center_sum += center [offset]; + + BLIP_CLAMP( s, s ); + + ++offset; // before write since out is decremented to slightly before end + out [offset * stereo] = (blip_sample_t) s; + } + while ( offset ); + + (*buf)->set_integrator( side_sum ); + + if ( buf != bufs ) + continue; + + // only end center once + bufs [2]->set_integrator( center_sum ); + break; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Music_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Music_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Music_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Music_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,244 +1,244 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Music_Emu.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const stereo = 2; // number of channels for stereo - -Music_Emu::equalizer_t const Music_Emu::tv_eq = { -8.0, 180, 0,0,0,0,0,0,0,0 }; - -void Music_Emu::clear_track_vars() -{ - current_track_ = -1; - warning(); // clear warning - track_filter.stop(); -} - -void Music_Emu::unload() -{ - voice_count_ = 0; - clear_track_vars(); - Gme_File::unload(); -} - -Music_Emu::gme_t() -{ - effects_buffer_ = NULL; - sample_rate_ = 0; - mute_mask_ = 0; - tempo_ = 1.0; - gain_ = 1.0; - - fade_set = false; - - // defaults - tfilter = track_filter.setup(); - set_max_initial_silence( 15 ); - set_silence_lookahead( 3 ); - ignore_silence( false ); - - equalizer_.treble = -1.0; - equalizer_.bass = 60; - - static const char* const names [] = { - "Voice 1", "Voice 2", "Voice 3", "Voice 4", - "Voice 5", "Voice 6", "Voice 7", "Voice 8" - }; - set_voice_names( names ); - Music_Emu::unload(); // clears fields -} - -Music_Emu::~gme_t() -{ - assert( !effects_buffer_ ); -} - -blargg_err_t Music_Emu::set_sample_rate( int rate ) -{ - require( !sample_rate() ); // sample rate can't be changed once set - RETURN_ERR( set_sample_rate_( rate ) ); - RETURN_ERR( track_filter.init( this ) ); - sample_rate_ = rate; - tfilter.max_silence = 6 * stereo * sample_rate(); - return blargg_ok; -} - -void Music_Emu::pre_load() -{ - require( sample_rate() ); // set_sample_rate() must be called before loading a file - Gme_File::pre_load(); -} - -void Music_Emu::set_equalizer( equalizer_t const& eq ) -{ - // TODO: why is GCC generating memcpy call here? - // Without the 'if', valgrind flags it. - if ( &eq != &equalizer_ ) - equalizer_ = eq; - set_equalizer_( eq ); -} - -void Music_Emu::mute_voice( int index, bool mute ) -{ - require( (unsigned) index < (unsigned) voice_count() ); - int bit = 1 << index; - int mask = mute_mask_ | bit; - if ( !mute ) - mask ^= bit; - mute_voices( mask ); -} - -void Music_Emu::mute_voices( int mask ) -{ - require( sample_rate() ); // sample rate must be set first - mute_mask_ = mask; - mute_voices_( mask ); -} - -const char* Music_Emu::voice_name( int i ) const -{ - if ( (unsigned) i < (unsigned) voice_count_ ) - return voice_names_ [i]; - - //check( false ); // TODO: enable? - return ""; -} - -void Music_Emu::set_tempo( double t ) -{ - require( sample_rate() ); // sample rate must be set first - double const min = 0.02; - double const max = 4.00; - if ( t < min ) t = min; - if ( t > max ) t = max; - tempo_ = t; - set_tempo_( t ); -} - -blargg_err_t Music_Emu::post_load() -{ - set_tempo( tempo_ ); - remute_voices(); - return Gme_File::post_load(); -} - -// Tell/Seek - -int Music_Emu::msec_to_samples( int msec ) const -{ - int sec = msec / 1000; - msec -= sec * 1000; - return (sec * sample_rate() + msec * sample_rate() / 1000) * stereo; -} - -int Music_Emu::tell() const -{ - int rate = sample_rate() * stereo; - int sec = track_filter.sample_count() / rate; - return sec * 1000 + (track_filter.sample_count() - sec * rate) * 1000 / rate; -} - -blargg_err_t Music_Emu::seek( int msec ) -{ - int time = msec_to_samples( msec ); - if ( time < track_filter.sample_count() ) - { - RETURN_ERR( start_track( current_track_ ) ); - if ( fade_set ) - set_fade( length_msec, fade_msec ); - } - return skip( time - track_filter.sample_count() ); -} - -blargg_err_t Music_Emu::skip( int count ) -{ - require( current_track() >= 0 ); // start_track() must have been called already - return track_filter.skip( count ); -} - -blargg_err_t Music_Emu::skip_( int count ) -{ - // for long skip, mute sound - const int threshold = 32768; - if ( count > threshold ) - { - int saved_mute = mute_mask_; - mute_voices( ~0 ); - - int n = count - threshold/2; - n &= ~(2048-1); // round to multiple of 2048 - count -= n; - RETURN_ERR( track_filter.skip_( n ) ); - - mute_voices( saved_mute ); - } - - return track_filter.skip_( count ); -} - -// Playback - -blargg_err_t Music_Emu::start_track( int track ) -{ - clear_track_vars(); - - int remapped = track; - RETURN_ERR( remap_track_( &remapped ) ); - current_track_ = track; - blargg_err_t err = start_track_( remapped ); - if ( err ) - { - current_track_ = -1; - return err; - } - - // convert filter times to samples - Track_Filter::setup_t s = tfilter; - s.max_initial *= sample_rate() * stereo; - #if GME_DISABLE_SILENCE_LOOKAHEAD - s.lookahead = 1; - #endif - track_filter.setup( s ); - - return track_filter.start_track(); -} - -void Music_Emu::set_fade( int start_msec, int length_msec ) -{ - fade_set = true; - this->length_msec = start_msec; - this->fade_msec = length_msec; - track_filter.set_fade( msec_to_samples( start_msec ), - length_msec * sample_rate() / (1000 / stereo) ); -} - -blargg_err_t Music_Emu::play( int out_count, sample_t out [] ) -{ - require( current_track() >= 0 ); - require( out_count % stereo == 0 ); - - return track_filter.play( out_count, out ); -} - -// Gme_Info_ - -blargg_err_t Gme_Info_::set_sample_rate_( int ) { return blargg_ok; } -void Gme_Info_::pre_load() { Gme_File::pre_load(); } // skip Music_Emu -blargg_err_t Gme_Info_::post_load() { return Gme_File::post_load(); } // skip Music_Emu -void Gme_Info_::set_equalizer_( equalizer_t const& ){ check( false ); } -void Gme_Info_::mute_voices_( int ) { check( false ); } -void Gme_Info_::set_tempo_( double ) { } -blargg_err_t Gme_Info_::start_track_( int ) { return BLARGG_ERR( BLARGG_ERR_CALLER, "can't play file opened for info only" ); } -blargg_err_t Gme_Info_::play_( int, sample_t [] ) { return BLARGG_ERR( BLARGG_ERR_CALLER, "can't play file opened for info only" ); } +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Music_Emu.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const stereo = 2; // number of channels for stereo + +Music_Emu::equalizer_t const Music_Emu::tv_eq = { -8.0, 180, 0,0,0,0,0,0,0,0 }; + +void Music_Emu::clear_track_vars() +{ + current_track_ = -1; + warning(); // clear warning + track_filter.stop(); +} + +void Music_Emu::unload() +{ + voice_count_ = 0; + clear_track_vars(); + Gme_File::unload(); +} + +Music_Emu::gme_t() +{ + effects_buffer_ = NULL; + sample_rate_ = 0; + mute_mask_ = 0; + tempo_ = 1.0; + gain_ = 1.0; + + fade_set = false; + + // defaults + tfilter = track_filter.setup(); + set_max_initial_silence( 15 ); + set_silence_lookahead( 3 ); + ignore_silence( false ); + + equalizer_.treble = -1.0; + equalizer_.bass = 60; + + static const char* const names [] = { + "Voice 1", "Voice 2", "Voice 3", "Voice 4", + "Voice 5", "Voice 6", "Voice 7", "Voice 8" + }; + set_voice_names( names ); + Music_Emu::unload(); // clears fields +} + +Music_Emu::~gme_t() +{ + assert( !effects_buffer_ ); +} + +blargg_err_t Music_Emu::set_sample_rate( int rate ) +{ + require( !sample_rate() ); // sample rate can't be changed once set + RETURN_ERR( set_sample_rate_( rate ) ); + RETURN_ERR( track_filter.init( this ) ); + sample_rate_ = rate; + tfilter.max_silence = 6 * stereo * sample_rate(); + return blargg_ok; +} + +void Music_Emu::pre_load() +{ + require( sample_rate() ); // set_sample_rate() must be called before loading a file + Gme_File::pre_load(); +} + +void Music_Emu::set_equalizer( equalizer_t const& eq ) +{ + // TODO: why is GCC generating memcpy call here? + // Without the 'if', valgrind flags it. + if ( &eq != &equalizer_ ) + equalizer_ = eq; + set_equalizer_( eq ); +} + +void Music_Emu::mute_voice( int index, bool mute ) +{ + require( (unsigned) index < (unsigned) voice_count() ); + int bit = 1 << index; + int mask = mute_mask_ | bit; + if ( !mute ) + mask ^= bit; + mute_voices( mask ); +} + +void Music_Emu::mute_voices( int mask ) +{ + require( sample_rate() ); // sample rate must be set first + mute_mask_ = mask; + mute_voices_( mask ); +} + +const char* Music_Emu::voice_name( int i ) const +{ + if ( (unsigned) i < (unsigned) voice_count_ ) + return voice_names_ [i]; + + //check( false ); // TODO: enable? + return ""; +} + +void Music_Emu::set_tempo( double t ) +{ + require( sample_rate() ); // sample rate must be set first + double const min = 0.02; + double const max = 4.00; + if ( t < min ) t = min; + if ( t > max ) t = max; + tempo_ = t; + set_tempo_( t ); +} + +blargg_err_t Music_Emu::post_load() +{ + set_tempo( tempo_ ); + remute_voices(); + return Gme_File::post_load(); +} + +// Tell/Seek + +int Music_Emu::msec_to_samples( int msec ) const +{ + int sec = msec / 1000; + msec -= sec * 1000; + return (sec * sample_rate() + msec * sample_rate() / 1000) * stereo; +} + +int Music_Emu::tell() const +{ + int rate = sample_rate() * stereo; + int sec = track_filter.sample_count() / rate; + return sec * 1000 + (track_filter.sample_count() - sec * rate) * 1000 / rate; +} + +blargg_err_t Music_Emu::seek( int msec ) +{ + int time = msec_to_samples( msec ); + if ( time < track_filter.sample_count() ) + { + RETURN_ERR( start_track( current_track_ ) ); + if ( fade_set ) + set_fade( length_msec, fade_msec ); + } + return skip( time - track_filter.sample_count() ); +} + +blargg_err_t Music_Emu::skip( int count ) +{ + require( current_track() >= 0 ); // start_track() must have been called already + return track_filter.skip( count ); +} + +blargg_err_t Music_Emu::skip_( int count ) +{ + // for long skip, mute sound + const int threshold = 32768; + if ( count > threshold ) + { + int saved_mute = mute_mask_; + mute_voices( ~0 ); + + int n = count - threshold/2; + n &= ~(2048-1); // round to multiple of 2048 + count -= n; + RETURN_ERR( track_filter.skip_( n ) ); + + mute_voices( saved_mute ); + } + + return track_filter.skip_( count ); +} + +// Playback + +blargg_err_t Music_Emu::start_track( int track ) +{ + clear_track_vars(); + + int remapped = track; + RETURN_ERR( remap_track_( &remapped ) ); + current_track_ = track; + blargg_err_t err = start_track_( remapped ); + if ( err ) + { + current_track_ = -1; + return err; + } + + // convert filter times to samples + Track_Filter::setup_t s = tfilter; + s.max_initial *= sample_rate() * stereo; + #if GME_DISABLE_SILENCE_LOOKAHEAD + s.lookahead = 1; + #endif + track_filter.setup( s ); + + return track_filter.start_track(); +} + +void Music_Emu::set_fade( int start_msec, int length_msec ) +{ + fade_set = true; + this->length_msec = start_msec; + this->fade_msec = length_msec; + track_filter.set_fade( start_msec < 0 ? Track_Filter::indefinite_count : msec_to_samples( start_msec ), + length_msec * sample_rate() / (1000 / stereo) ); +} + +blargg_err_t Music_Emu::play( int out_count, sample_t out [] ) +{ + require( current_track() >= 0 ); + require( out_count % stereo == 0 ); + + return track_filter.play( out_count, out ); +} + +// Gme_Info_ + +blargg_err_t Gme_Info_::set_sample_rate_( int ) { return blargg_ok; } +void Gme_Info_::pre_load() { Gme_File::pre_load(); } // skip Music_Emu +blargg_err_t Gme_Info_::post_load() { return Gme_File::post_load(); } // skip Music_Emu +void Gme_Info_::set_equalizer_( equalizer_t const& ){ check( false ); } +void Gme_Info_::mute_voices_( int ) { check( false ); } +void Gme_Info_::set_tempo_( double ) { } +blargg_err_t Gme_Info_::start_track_( int ) { return BLARGG_ERR( BLARGG_ERR_CALLER, "can't play file opened for info only" ); } +blargg_err_t Gme_Info_::play_( int, sample_t [] ) { return BLARGG_ERR( BLARGG_ERR_CALLER, "can't play file opened for info only" ); } diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Music_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Music_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Music_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Music_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,280 +1,280 @@ -// Common interface to game music file emulators - -// Game_Music_Emu $vers -#ifndef MUSIC_EMU_H -#define MUSIC_EMU_H - -#include "Gme_File.h" -#include "Track_Filter.h" -#include "blargg_errors.h" -class Multi_Buffer; - -struct gme_t : public Gme_File, private Track_Filter::callbacks_t { -public: - // Sets output sample rate. Must be called only once before loading file. - blargg_err_t set_sample_rate( int sample_rate ); - - // Sample rate sound is generated at - int sample_rate() const; - -// File loading - - // See Gme_Loader.h - -// Basic playback - - // Starts a track, where 0 is the first track. Also clears warning string. - blargg_err_t start_track( int ); - - // Generates 'count' samples info 'buf'. Output is in stereo. Any emulation - // errors set warning string, and major errors also end track. - typedef short sample_t; - blargg_err_t play( int count, sample_t* buf ); - -// Track information - - // See Gme_File.h - - // Index of current track or -1 if one hasn't been started - int current_track() const; - - // Info for currently playing track - using Gme_File::track_info; - blargg_err_t track_info( track_info_t* out ) const; - blargg_err_t set_track_info( const track_info_t* in ); - blargg_err_t set_track_info( const track_info_t* in, int track_number ); - - struct Hash_Function - { - virtual void hash_( byte const* data, size_t size ) BLARGG_PURE( ; ) - }; - virtual blargg_err_t hash_( Hash_Function& ) const BLARGG_PURE( ; ) - - blargg_err_t save( gme_writer_t writer, void* your_data) const; - -// Track status/control - - // Number of milliseconds played since beginning of track (1000 per second) - int tell() const; - - // Seeks to new time in track. Seeking backwards or far forward can take a while. - blargg_err_t seek( int msec ); - - // Skips n samples - blargg_err_t skip( int n ); - - // True if a track has reached its end - bool track_ended() const; - - // Sets start time and length of track fade out. Once fade ends track_ended() returns - // true. Fade time must be set after track has been started, and can be changed - // at any time. - void set_fade( int start_msec, int length_msec = 8000 ); - - // Disables automatic end-of-track detection and skipping of silence at beginning - void ignore_silence( bool disable = true ); - -// Voices - - // Number of voices used by currently loaded file - int voice_count() const; - - // Name of voice i, from 0 to voice_count()-1 - const char* voice_name( int i ) const; - - // Mutes/unmutes voice i, where voice 0 is first voice - void mute_voice( int index, bool mute = true ); - - // Sets muting state of all voices at once using a bit mask, where -1 mutes them all, - // 0 unmutes them all, 0x01 mutes just the first voice, etc. - void mute_voices( int mask ); - -// Sound customization - - // Adjusts song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. - // Track length as returned by track_info() assumes a tempo of 1.0. - void set_tempo( double ); - - // Changes overall output amplitude, where 1.0 results in minimal clamping. - // Must be called before set_sample_rate(). - void set_gain( double ); - - // Requests use of custom multichannel buffer. Only supported by "classic" emulators; - // on others this has no effect. Should be called only once *before* set_sample_rate(). - virtual void set_buffer( class Multi_Buffer* ) { } - -// Sound equalization (treble/bass) - - // Frequency equalizer parameters (see gme.txt) - // See gme.h for definition of struct gme_equalizer_t. - typedef gme_equalizer_t equalizer_t; - - // Current frequency equalizater parameters - equalizer_t const& equalizer() const; - - // Sets frequency equalizer parameters - void set_equalizer( equalizer_t const& ); - - // Equalizer preset for a TV speaker - static equalizer_t const tv_eq; - -// Derived interface -protected: - // Cause any further generated samples to be silence, instead of calling play_() - void set_track_ended() { track_filter.set_track_ended(); } - - // If more than secs of silence are encountered, track is ended - void set_max_initial_silence( int secs ) { tfilter.max_initial = secs; } - - // Sets rate emulator is run at when scanning ahead for silence. 1=100%, 2=200% etc. - void set_silence_lookahead( int rate ) { tfilter.lookahead = rate; } - - // Sets number of voices - void set_voice_count( int n ) { voice_count_ = n; } - - // Sets names of voices - void set_voice_names( const char* const names [] ); - - // Current gain - double gain() const { return gain_; } - - // Current tempo - double tempo() const { return tempo_; } - - // Re-applies muting mask using mute_voices_() - void remute_voices(); - -// Overrides should do the indicated task - - // Set sample rate as close as possible to sample_rate, then call - // Music_Emu::set_sample_rate_() with the actual rate used. - virtual blargg_err_t set_sample_rate_( int sample_rate ) BLARGG_PURE( ; ) - - // Set equalizer parameters - virtual void set_equalizer_( equalizer_t const& ) { } - - // Mute voices based on mask - virtual void mute_voices_( int mask ) BLARGG_PURE( ; ) - - // Set tempo to t, which is constrained to the range 0.02 to 4.0. - virtual void set_tempo_( double t ) BLARGG_PURE( ; ) - - // Start track t, where 0 is the first track - virtual blargg_err_t start_track_( int t ) BLARGG_PURE( ; ) // tempo is set before this - - // Generate count samples into *out. Count will always be even. - virtual blargg_err_t play_( int count, sample_t out [] ) BLARGG_PURE( ; ) - - // Skip count samples. Count will always be even. - virtual blargg_err_t skip_( int count ); - - // Save current state of file to specified writer. - virtual blargg_err_t save_( gme_writer_t, void* ) const { return "Not supported by this format"; } - - // Set track info - virtual blargg_err_t set_track_info_( const track_info_t*, int ) { return "Not supported by this format"; } - -// Implementation -public: - gme_t(); - ~gme_t(); - BLARGG_DEPRECATED( const char** voice_names() const { return CONST_CAST(const char**,voice_names_); } ) - -protected: - virtual void unload(); - virtual void pre_load(); - virtual blargg_err_t post_load(); - -private: - Track_Filter::setup_t tfilter; - Track_Filter track_filter; - equalizer_t equalizer_; - const char* const* voice_names_; - int voice_count_; - int mute_mask_; - double tempo_; - double gain_; - int sample_rate_; - int current_track_; - - bool fade_set; - int length_msec; - int fade_msec; - - void clear_track_vars(); - int msec_to_samples( int msec ) const; - - friend Music_Emu* gme_new_emu( gme_type_t, int ); - friend void gme_effects( Music_Emu const*, gme_effects_t* ); - friend void gme_set_effects( Music_Emu*, gme_effects_t const* ); - friend void gme_set_stereo_depth( Music_Emu*, double ); - friend const char** gme_voice_names ( Music_Emu const* ); - -protected: - Multi_Buffer* effects_buffer_; -}; - -// base class for info-only derivations -struct Gme_Info_ : Music_Emu -{ - virtual blargg_err_t set_sample_rate_( int sample_rate ); - virtual void set_equalizer_( equalizer_t const& ); - virtual void mute_voices_( int mask ); - virtual void set_tempo_( double ); - virtual blargg_err_t start_track_( int ); - virtual blargg_err_t play_( int count, sample_t out [] ); - virtual void pre_load(); - virtual blargg_err_t post_load(); -}; - -inline blargg_err_t Music_Emu::track_info( track_info_t* out ) const -{ - return track_info( out, current_track_ ); -} - -inline blargg_err_t Music_Emu::save(gme_writer_t writer, void *your_data) const -{ - return save_( writer, your_data ); -} - -inline blargg_err_t Music_Emu::set_track_info(const track_info_t *in) -{ - return set_track_info_( in, current_track_ ); -} - -inline blargg_err_t Music_Emu::set_track_info(const track_info_t *in, int track) -{ - return set_track_info_( in, track ); -} - -inline int Music_Emu::sample_rate() const { return sample_rate_; } -inline int Music_Emu::voice_count() const { return voice_count_; } -inline int Music_Emu::current_track() const { return current_track_; } -inline bool Music_Emu::track_ended() const { return track_filter.track_ended(); } -inline const Music_Emu::equalizer_t& Music_Emu::equalizer() const { return equalizer_; } - -inline void Music_Emu::ignore_silence( bool b ) { track_filter.ignore_silence( b ); } -inline void Music_Emu::set_tempo_( double t ) { tempo_ = t; } -inline void Music_Emu::remute_voices() { mute_voices( mute_mask_ ); } - -inline void Music_Emu::set_voice_names( const char* const p [] ) { voice_names_ = p; } - -inline void Music_Emu::mute_voices_( int ) { } - -inline void Music_Emu::set_gain( double g ) -{ - assert( !sample_rate() ); // you must set gain before setting sample rate - gain_ = g; -} - -inline blargg_err_t Music_Emu::start_track_( int ) { return blargg_ok; } - -inline blargg_err_t Music_Emu::set_sample_rate_( int ) { return blargg_ok; } - -inline blargg_err_t Music_Emu::play_( int, sample_t [] ) { return blargg_ok; } - -inline blargg_err_t Music_Emu::hash_( Hash_Function& ) const { return BLARGG_ERR( BLARGG_ERR_CALLER, "no hashing function defined" ); } - -inline void Music_Emu::Hash_Function::hash_( byte const*, size_t ) { } - -#endif +// Common interface to game music file emulators + +// Game_Music_Emu $vers +#ifndef MUSIC_EMU_H +#define MUSIC_EMU_H + +#include "Gme_File.h" +#include "Track_Filter.h" +#include "blargg_errors.h" +class Multi_Buffer; + +struct gme_t : public Gme_File, private Track_Filter::callbacks_t { +public: + // Sets output sample rate. Must be called only once before loading file. + blargg_err_t set_sample_rate( int sample_rate ); + + // Sample rate sound is generated at + int sample_rate() const; + +// File loading + + // See Gme_Loader.h + +// Basic playback + + // Starts a track, where 0 is the first track. Also clears warning string. + blargg_err_t start_track( int ); + + // Generates 'count' samples info 'buf'. Output is in stereo. Any emulation + // errors set warning string, and major errors also end track. + typedef short sample_t; + blargg_err_t play( int count, sample_t* buf ); + +// Track information + + // See Gme_File.h + + // Index of current track or -1 if one hasn't been started + int current_track() const; + + // Info for currently playing track + using Gme_File::track_info; + blargg_err_t track_info( track_info_t* out ) const; + blargg_err_t set_track_info( const track_info_t* in ); + blargg_err_t set_track_info( const track_info_t* in, int track_number ); + + struct Hash_Function + { + virtual void hash_( byte const* data, size_t size ) BLARGG_PURE( ; ) + }; + virtual blargg_err_t hash_( Hash_Function& ) const BLARGG_PURE( ; ) + + blargg_err_t save( gme_writer_t writer, void* your_data) const; + +// Track status/control + + // Number of milliseconds played since beginning of track (1000 per second) + int tell() const; + + // Seeks to new time in track. Seeking backwards or far forward can take a while. + blargg_err_t seek( int msec ); + + // Skips n samples + blargg_err_t skip( int n ); + + // True if a track has reached its end + bool track_ended() const; + + // Sets start time and length of track fade out. Once fade ends track_ended() returns + // true. Fade time must be set after track has been started, and can be changed + // at any time. + void set_fade( int start_msec, int length_msec = 8000 ); + + // Disables automatic end-of-track detection and skipping of silence at beginning + void ignore_silence( bool disable = true ); + +// Voices + + // Number of voices used by currently loaded file + int voice_count() const; + + // Name of voice i, from 0 to voice_count()-1 + const char* voice_name( int i ) const; + + // Mutes/unmutes voice i, where voice 0 is first voice + void mute_voice( int index, bool mute = true ); + + // Sets muting state of all voices at once using a bit mask, where -1 mutes them all, + // 0 unmutes them all, 0x01 mutes just the first voice, etc. + void mute_voices( int mask ); + +// Sound customization + + // Adjusts song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. + // Track length as returned by track_info() assumes a tempo of 1.0. + void set_tempo( double ); + + // Changes overall output amplitude, where 1.0 results in minimal clamping. + // Must be called before set_sample_rate(). + void set_gain( double ); + + // Requests use of custom multichannel buffer. Only supported by "classic" emulators; + // on others this has no effect. Should be called only once *before* set_sample_rate(). + virtual void set_buffer( class Multi_Buffer* ) { } + +// Sound equalization (treble/bass) + + // Frequency equalizer parameters (see gme.txt) + // See gme.h for definition of struct gme_equalizer_t. + typedef gme_equalizer_t equalizer_t; + + // Current frequency equalizater parameters + equalizer_t const& equalizer() const; + + // Sets frequency equalizer parameters + void set_equalizer( equalizer_t const& ); + + // Equalizer preset for a TV speaker + static equalizer_t const tv_eq; + +// Derived interface +protected: + // Cause any further generated samples to be silence, instead of calling play_() + void set_track_ended() { track_filter.set_track_ended(); } + + // If more than secs of silence are encountered, track is ended + void set_max_initial_silence( int secs ) { tfilter.max_initial = secs; } + + // Sets rate emulator is run at when scanning ahead for silence. 1=100%, 2=200% etc. + void set_silence_lookahead( int rate ) { tfilter.lookahead = rate; } + + // Sets number of voices + void set_voice_count( int n ) { voice_count_ = n; } + + // Sets names of voices + void set_voice_names( const char* const names [] ); + + // Current gain + double gain() const { return gain_; } + + // Current tempo + double tempo() const { return tempo_; } + + // Re-applies muting mask using mute_voices_() + void remute_voices(); + +// Overrides should do the indicated task + + // Set sample rate as close as possible to sample_rate, then call + // Music_Emu::set_sample_rate_() with the actual rate used. + virtual blargg_err_t set_sample_rate_( int sample_rate ) BLARGG_PURE( ; ) + + // Set equalizer parameters + virtual void set_equalizer_( equalizer_t const& ) { } + + // Mute voices based on mask + virtual void mute_voices_( int mask ) BLARGG_PURE( ; ) + + // Set tempo to t, which is constrained to the range 0.02 to 4.0. + virtual void set_tempo_( double t ) BLARGG_PURE( ; ) + + // Start track t, where 0 is the first track + virtual blargg_err_t start_track_( int t ) BLARGG_PURE( ; ) // tempo is set before this + + // Generate count samples into *out. Count will always be even. + virtual blargg_err_t play_( int count, sample_t out [] ) BLARGG_PURE( ; ) + + // Skip count samples. Count will always be even. + virtual blargg_err_t skip_( int count ); + + // Save current state of file to specified writer. + virtual blargg_err_t save_( gme_writer_t, void* ) const { return "Not supported by this format"; } + + // Set track info + virtual blargg_err_t set_track_info_( const track_info_t*, int ) { return "Not supported by this format"; } + +// Implementation +public: + gme_t(); + ~gme_t(); + BLARGG_DEPRECATED( const char** voice_names() const { return CONST_CAST(const char**,voice_names_); } ) + +protected: + virtual void unload(); + virtual void pre_load(); + virtual blargg_err_t post_load(); + +private: + Track_Filter::setup_t tfilter; + Track_Filter track_filter; + equalizer_t equalizer_; + const char* const* voice_names_; + int voice_count_; + int mute_mask_; + double tempo_; + double gain_; + int sample_rate_; + int current_track_; + + bool fade_set; + int length_msec; + int fade_msec; + + void clear_track_vars(); + int msec_to_samples( int msec ) const; + + friend Music_Emu* gme_new_emu( gme_type_t, int ); + friend void gme_effects( Music_Emu const*, gme_effects_t* ); + friend void gme_set_effects( Music_Emu*, gme_effects_t const* ); + friend void gme_set_stereo_depth( Music_Emu*, double ); + friend const char** gme_voice_names ( Music_Emu const* ); + +protected: + Multi_Buffer* effects_buffer_; +}; + +// base class for info-only derivations +struct Gme_Info_ : Music_Emu +{ + virtual blargg_err_t set_sample_rate_( int sample_rate ); + virtual void set_equalizer_( equalizer_t const& ); + virtual void mute_voices_( int mask ); + virtual void set_tempo_( double ); + virtual blargg_err_t start_track_( int ); + virtual blargg_err_t play_( int count, sample_t out [] ); + virtual void pre_load(); + virtual blargg_err_t post_load(); +}; + +inline blargg_err_t Music_Emu::track_info( track_info_t* out ) const +{ + return track_info( out, current_track_ ); +} + +inline blargg_err_t Music_Emu::save(gme_writer_t writer, void *your_data) const +{ + return save_( writer, your_data ); +} + +inline blargg_err_t Music_Emu::set_track_info(const track_info_t *in) +{ + return set_track_info_( in, current_track_ ); +} + +inline blargg_err_t Music_Emu::set_track_info(const track_info_t *in, int track) +{ + return set_track_info_( in, track ); +} + +inline int Music_Emu::sample_rate() const { return sample_rate_; } +inline int Music_Emu::voice_count() const { return voice_count_; } +inline int Music_Emu::current_track() const { return current_track_; } +inline bool Music_Emu::track_ended() const { return track_filter.track_ended(); } +inline const Music_Emu::equalizer_t& Music_Emu::equalizer() const { return equalizer_; } + +inline void Music_Emu::ignore_silence( bool b ) { track_filter.ignore_silence( b ); } +inline void Music_Emu::set_tempo_( double t ) { tempo_ = t; } +inline void Music_Emu::remute_voices() { mute_voices( mute_mask_ ); } + +inline void Music_Emu::set_voice_names( const char* const p [] ) { voice_names_ = p; } + +inline void Music_Emu::mute_voices_( int ) { } + +inline void Music_Emu::set_gain( double g ) +{ + assert( !sample_rate() ); // you must set gain before setting sample rate + gain_ = g; +} + +inline blargg_err_t Music_Emu::start_track_( int ) { return blargg_ok; } + +inline blargg_err_t Music_Emu::set_sample_rate_( int ) { return blargg_ok; } + +inline blargg_err_t Music_Emu::play_( int, sample_t [] ) { return blargg_ok; } + +inline blargg_err_t Music_Emu::hash_( Hash_Function& ) const { return BLARGG_ERR( BLARGG_ERR_CALLER, "no hashing function defined" ); } + +inline void Music_Emu::Hash_Function::hash_( byte const*, size_t ) { } + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nes_Cpu_run.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nes_Cpu_run.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nes_Cpu_run.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nes_Cpu_run.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,1121 +1,1121 @@ -// NES 6502 CPU emulator run function - -#if 0 -/* Define these macros in the source file before #including this file. -- Parameters might be expressions, so they are best evaluated only once, -though they NEVER have side-effects, so multiple evaluation is OK. -- Output parameters might be a multiple-assignment expression like "a=x", -so they must NOT be parenthesized. -- Except where noted, time() and related functions will NOT work -correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and -CACHE_TIME() allow the time changing functions to work. -- Macros "returning" void may use a {} statement block. */ - - // 0 <= addr <= 0xFFFF + page_size - // time functions can be used - int READ_MEM( addr_t ); - void WRITE_MEM( addr_t, int data ); - // 0 <= READ_MEM() <= 0xFF - - // 0 <= addr <= 0x1FF - int READ_LOW( addr_t ); - void WRITE_LOW( addr_t, int data ); - // 0 <= READ_LOW() <= 0xFF - - // Often-used instructions attempt these before using a normal memory access. - // Optional; defaults to READ_MEM() and WRITE_MEM() - bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST - void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST - bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM - void WRITE_FAST( addr_t, int data ); - - // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs). - // Optional; defaults to READ_MEM. - void READ_PPU( addr_t, int& out ); - // 0 <= out <= 0xFF - -// The following can be used within macros: - - // Current time - time_t TIME(); - - // Allows use of time functions - void FLUSH_TIME(); - - // Must be used before end of macro if FLUSH_TIME() was used earlier - void CACHE_TIME(); - -// Configuration (optional; commented behavior if defined) - - // Emulates dummy reads for indexed instructions - #define NES_CPU_DUMMY_READS 1 - - // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect - #define FLAT_MEM my_mem_array - - // Expanded just before beginning of code, to help debugger - #define CPU_BEGIN void my_run_cpu() { - -#endif - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -// Allows MWCW debugger to step through code properly -#ifdef CPU_BEGIN - CPU_BEGIN -#endif - -// Time -#define TIME() (s_time + s.base) -#define FLUSH_TIME() {s.time = s_time - time_offset;} -#define CACHE_TIME() {s_time = s.time + time_offset;} - -// Defaults -#ifndef CAN_WRITE_FAST - #define CAN_WRITE_FAST( addr ) 0 - #define WRITE_FAST( addr, data ) -#endif - -#ifndef CAN_READ_FAST - #define CAN_READ_FAST( addr ) 0 - #define READ_FAST( addr, out ) -#endif - -#ifndef READ_PPU - #define READ_PPU( addr, out )\ - {\ - FLUSH_TIME();\ - out = READ_MEM( addr );\ - CACHE_TIME();\ - } -#endif - -#define READ_STACK READ_LOW -#define WRITE_STACK WRITE_LOW - -// Dummy reads -#if NES_CPU_DUMMY_READS - // TODO: optimize time handling - #define DUMMY_READ( addr, idx ) \ - if ( (addr & 0xFF) < idx )\ - {\ - int const time_offset = 1;\ - FLUSH_TIME();\ - READ_MEM( (addr - 0x100) );\ - CACHE_TIME();\ - } -#else - #define DUMMY_READ( addr, idx ) -#endif - -// Code -#ifdef FLAT_MEM - #define CODE_PAGE( addr ) (FLAT_MEM) - #define CODE_OFFSET( addr ) (addr) -#else - #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )]) - #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr ) -#endif -#define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )]) - -// Stack -#define SET_SP( v ) (sp = ((v) + 1) | 0x100) -#define GET_SP() ((sp - 1) & 0xFF) -#define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) - -// Truncation -#define BYTE( n ) ((BOOST::uint8_t ) (n)) /* (unsigned) n & 0xFF */ -#define SBYTE( n ) ((BOOST::int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ -#define WORD( n ) ((BOOST::uint16_t) (n)) /* (unsigned) n & 0xFFFF */ - -// Flags with hex value for clarity when used as mask. -// Stored in indicated variable during emulation. -int const n80 = 0x80; // nz -int const v40 = 0x40; // flags -int const r20 = 0x20; -int const b10 = 0x10; -int const d08 = 0x08; // flags -int const i04 = 0x04; // flags -int const z02 = 0x02; // nz -int const c01 = 0x01; // c - -#define IS_NEG (nz & 0x8080) - -#define GET_FLAGS( out ) \ -{\ - out = flags & (v40 | d08 | i04);\ - out += ((nz >> 8) | nz) & n80;\ - out += c >> 8 & c01;\ - if ( !BYTE( nz ) )\ - out += z02;\ -} - -#define SET_FLAGS( in ) \ -{\ - flags = in & (v40 | d08 | i04);\ - c = nz = in << 8;\ - nz += ~in & z02;\ -} - -{ - int const time_offset = 0; - - // Local state - Nes_Cpu::cpu_state_t s; - #ifdef FLAT_MEM - s.base = CPU.cpu_state_.base; - #else - s = CPU.cpu_state_; - #endif - CPU.cpu_state = &s; - int s_time = CPU.cpu_state_.time; // helps even on x86 - - // Registers - int pc = CPU.r.pc; - int a = CPU.r.a; - int x = CPU.r.x; - int y = CPU.r.y; - int sp; - SET_SP( CPU.r.sp ); - - // Flags - int flags; - int c; // carry set if (c & 0x100) != 0 - int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 - { - int temp = CPU.r.flags; - SET_FLAGS( temp ); - } - -loop: - - // Check all values - check( (unsigned) sp - 0x100 < 0x100 ); - check( (unsigned) pc < 0x10000 ); - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - - // Read instruction - byte const* instr = CODE_PAGE( pc ); - int opcode; - - if ( CODE_OFFSET(~0) == ~0 ) - { - opcode = instr [pc]; - pc++; - instr += pc; - } - else - { - instr += CODE_OFFSET( pc ); - opcode = *instr++; - pc++; - } - - // local to function in case it helps optimizer - static byte const clock_table [256] = - {// 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 - 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 - 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 - 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 - 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 - 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 - 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A - 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E - 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F - }; // 0x00 was 7 and 0x22 was 2 - - // Update time - if ( s_time >= 0 ) - goto out_of_time; - - #ifdef CPU_INSTR_HOOK - { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); } - #endif - - s_time += clock_table [opcode]; - - int data; - data = *instr; - - switch ( opcode ) - { - -// Macros - -#define GET_MSB() (instr [1]) -#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()) -#define GET_ADDR() GET_LE16( instr ) - -#define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8; - -#define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; - -#define IND_Y( cross, out ) {\ - int temp = READ_LOW( data ) + y;\ - out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ - cross( temp );\ - } - -#define IND_X( out ) {\ - int temp = data + x;\ - out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\ - } - -#define ARITH_ADDR_MODES( op )\ -case op - 0x04: /* (ind,x) */\ - IND_X( data )\ - goto ptr##op;\ -case op + 0x0C: /* (ind),y */\ - IND_Y( PAGE_PENALTY, data )\ - goto ptr##op;\ -case op + 0x10: /* zp,X */\ - data = BYTE( data + x );\ -case op + 0x00: /* zp */\ - data = READ_LOW( data );\ - goto imm##op;\ -case op + 0x14: /* abs,Y */\ - data += y;\ - goto ind##op;\ -case op + 0x18: /* abs,X */\ - data += x;\ -ind##op:\ - PAGE_PENALTY( data );\ -case op + 0x08: /* abs */\ - ADD_PAGE( data );\ -ptr##op:\ - FLUSH_TIME();\ - data = READ_MEM( data );\ - CACHE_TIME();\ -case op + 0x04: /* imm */\ -imm##op: - -// TODO: more efficient way to handle negative branch that wraps PC around -#define BRANCH( cond )\ -{\ - ++pc;\ - if ( !(cond) ) goto loop;\ - s_time++;\ - int offset = SBYTE( data );\ - s_time += (BYTE(pc) + offset) >> 8 & 1;\ - pc = WORD( pc + offset );\ - goto loop;\ -} - -// Often-Used - - case 0xB5: // LDA zp,x - a = nz = READ_LOW( BYTE( data + x ) ); - pc++; - goto loop; - - case 0xA5: // LDA zp - a = nz = READ_LOW( data ); - pc++; - goto loop; - - case 0xD0: // BNE - BRANCH( BYTE( nz ) ); - - case 0x20: { // JSR - int temp = pc + 1; - pc = GET_ADDR(); - WRITE_STACK( SP( -1 ), temp >> 8 ); - sp = SP( -2 ); - WRITE_STACK( sp, temp ); - goto loop; - } - - case 0x4C: // JMP abs - pc = GET_ADDR(); - goto loop; - - case 0xE8: // INX - INC_DEC( x, 1 ) - - case 0x10: // BPL - BRANCH( !IS_NEG ) - - ARITH_ADDR_MODES( 0xC5 ) // CMP - nz = a - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x30: // BMI - BRANCH( IS_NEG ) - - case 0xF0: // BEQ - BRANCH( !BYTE( nz ) ); - - case 0x95: // STA zp,x - data = BYTE( data + x ); - case 0x85: // STA zp - pc++; - WRITE_LOW( data, a ); - goto loop; - - case 0xC8: // INY - INC_DEC( y, 1 ) - - case 0xA8: // TAY - y = a; - nz = a; - goto loop; - - case 0x98: // TYA - a = y; - nz = y; - goto loop; - - case 0xAD:{// LDA abs - int addr = GET_ADDR(); - pc += 2; - READ_PPU( addr, a = nz ); - goto loop; - } - - case 0x60: // RTS - pc = 1 + READ_STACK( sp ); - pc += 0x100 * READ_STACK( SP( 1 ) ); - sp = SP( 2 ); - goto loop; - - { - int addr; - - case 0x8D: // STA abs - addr = GET_ADDR(); - pc += 2; - if ( CAN_WRITE_FAST( addr ) ) - { - WRITE_FAST( addr, a ); - goto loop; - } - sta_ptr: - FLUSH_TIME(); - WRITE_MEM( addr, a ); - CACHE_TIME(); - goto loop; - - case 0x99: // STA abs,Y - addr = y + GET_ADDR(); - pc += 2; - if ( CAN_WRITE_FAST( addr ) ) - { - WRITE_FAST( addr, a ); - goto loop; - } - goto sta_abs_x; - - case 0x9D: // STA abs,X (slightly more common than STA abs) - addr = x + GET_ADDR(); - pc += 2; - if ( CAN_WRITE_FAST( addr ) ) - { - WRITE_FAST( addr, a ); - goto loop; - } - DUMMY_READ( addr, x ); - sta_abs_x: - FLUSH_TIME(); - WRITE_MEM( addr, a ); - CACHE_TIME(); - goto loop; - - case 0x91: // STA (ind),Y - #define NO_PAGE_PENALTY( lsb ) - IND_Y( NO_PAGE_PENALTY, addr ) - pc++; - DUMMY_READ( addr, y ); - goto sta_ptr; - - case 0x81: // STA (ind,X) - IND_X( addr ) - pc++; - goto sta_ptr; - - } - - case 0xA9: // LDA #imm - pc++; - a = data; - nz = data; - goto loop; - - // common read instructions - { - int addr; - - case 0xA1: // LDA (ind,X) - IND_X( addr ) - pc++; - goto a_nz_read_addr; - - case 0xB1:// LDA (ind),Y - addr = READ_LOW( data ) + y; - PAGE_PENALTY( addr ); - addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); - pc++; - READ_FAST( addr, a = nz ); - if ( CAN_READ_FAST( addr ) ) - goto loop; - DUMMY_READ( addr, y ); - goto a_nz_read_addr; - - case 0xB9: // LDA abs,Y - PAGE_PENALTY( data + y ); - addr = GET_ADDR() + y; - pc += 2; - READ_FAST( addr, a = nz ); - if ( CAN_READ_FAST( addr ) ) - goto loop; - goto a_nz_read_addr; - - case 0xBD: // LDA abs,X - PAGE_PENALTY( data + x ); - addr = GET_ADDR() + x; - pc += 2; - READ_FAST( addr, a = nz ); - if ( CAN_READ_FAST( addr ) ) - goto loop; - DUMMY_READ( addr, x ); - a_nz_read_addr: - FLUSH_TIME(); - a = nz = READ_MEM( addr ); - CACHE_TIME(); - goto loop; - - } - -// Branch - - case 0x50: // BVC - BRANCH( !(flags & v40) ) - - case 0x70: // BVS - BRANCH( flags & v40 ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - -// Load/store - - case 0x94: // STY zp,x - data = BYTE( data + x ); - case 0x84: // STY zp - pc++; - WRITE_LOW( data, y ); - goto loop; - - case 0x96: // STX zp,y - data = BYTE( data + y ); - case 0x86: // STX zp - pc++; - WRITE_LOW( data, x ); - goto loop; - - case 0xB6: // LDX zp,y - data = BYTE( data + y ); - case 0xA6: // LDX zp - data = READ_LOW( data ); - case 0xA2: // LDX #imm - pc++; - x = data; - nz = data; - goto loop; - - case 0xB4: // LDY zp,x - data = BYTE( data + x ); - case 0xA4: // LDY zp - data = READ_LOW( data ); - case 0xA0: // LDY #imm - pc++; - y = data; - nz = data; - goto loop; - - case 0xBC: // LDY abs,X - data += x; - PAGE_PENALTY( data ); - case 0xAC:{// LDY abs - int addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - y = nz = READ_MEM( addr ); - CACHE_TIME(); - goto loop; - } - - case 0xBE: // LDX abs,y - data += y; - PAGE_PENALTY( data ); - case 0xAE:{// LDX abs - int addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - x = nz = READ_MEM( addr ); - CACHE_TIME(); - goto loop; - } - - { - int temp; - case 0x8C: // STY abs - temp = y; - goto store_abs; - - case 0x8E: // STX abs - temp = x; - store_abs: - int addr = GET_ADDR(); - pc += 2; - if ( CAN_WRITE_FAST( addr ) ) - { - WRITE_FAST( addr, temp ); - goto loop; - } - FLUSH_TIME(); - WRITE_MEM( addr, temp ); - CACHE_TIME(); - goto loop; - } - -// Compare - - case 0xEC:{// CPX abs - int addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ_MEM( addr ); - CACHE_TIME(); - goto cpx_data; - } - - case 0xE4: // CPX zp - data = READ_LOW( data ); - case 0xE0: // CPX #imm - cpx_data: - nz = x - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0xCC:{// CPY abs - int addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ_MEM( addr ); - CACHE_TIME(); - goto cpy_data; - } - - case 0xC4: // CPY zp - data = READ_LOW( data ); - case 0xC0: // CPY #imm - cpy_data: - nz = y - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - -// Logical - - ARITH_ADDR_MODES( 0x25 ) // AND - nz = (a &= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x45 ) // EOR - nz = (a ^= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x05 ) // ORA - nz = (a |= data); - pc++; - goto loop; - - case 0x2C:{// BIT abs - int addr = GET_ADDR(); - pc += 2; - READ_PPU( addr, nz ); - flags = (flags & ~v40) + (nz & v40); - if ( a & nz ) - goto loop; - nz <<= 8; // result must be zero, even if N bit is set - goto loop; - } - - case 0x24: // BIT zp - nz = READ_LOW( data ); - pc++; - flags = (flags & ~v40) + (nz & v40); - if ( a & nz ) - goto loop; // Z should be clear, and nz must be non-zero if nz & a is - nz <<= 8; // set Z flag without affecting N flag - goto loop; - -// Add/subtract - - ARITH_ADDR_MODES( 0xE5 ) // SBC - case 0xEB: // unofficial equivalent - data ^= 0xFF; - goto adc_imm; - - ARITH_ADDR_MODES( 0x65 ) // ADC - adc_imm: { - int carry = c >> 8 & 1; - int ov = (a ^ 0x80) + carry + SBYTE( data ); - flags = (flags & ~v40) + (ov >> 2 & v40); - c = nz = a + data + carry; - pc++; - a = BYTE( nz ); - goto loop; - } - -// Shift/rotate - - case 0x4A: // LSR A - c = 0; - case 0x6A: // ROR A - nz = c >> 1 & 0x80; - c = a << 8; - nz += a >> 1; - a = nz; - goto loop; - - case 0x0A: // ASL A - nz = a << 1; - c = nz; - a = BYTE( nz ); - goto loop; - - case 0x2A: { // ROL A - nz = a << 1; - int temp = c >> 8 & 1; - c = nz; - nz += temp; - a = BYTE( nz ); - goto loop; - } - - case 0x5E: // LSR abs,X - data += x; - case 0x4E: // LSR abs - c = 0; - case 0x6E: // ROR abs - ror_abs: { - ADD_PAGE( data ); - FLUSH_TIME(); - int temp = READ_MEM( data ); - nz = (c >> 1 & 0x80) + (temp >> 1); - c = temp << 8; - goto rotate_common; - } - - case 0x3E: // ROL abs,X - data += x; - goto rol_abs; - - case 0x1E: // ASL abs,X - data += x; - case 0x0E: // ASL abs - c = 0; - case 0x2E: // ROL abs - rol_abs: - ADD_PAGE( data ); - nz = c >> 8 & 1; - FLUSH_TIME(); - nz += (c = READ_MEM( data ) << 1); - rotate_common: - pc++; - WRITE_MEM( data, BYTE( nz ) ); - CACHE_TIME(); - goto loop; - - case 0x7E: // ROR abs,X - data += x; - goto ror_abs; - - case 0x76: // ROR zp,x - data = BYTE( data + x ); - goto ror_zp; - - case 0x56: // LSR zp,x - data = BYTE( data + x ); - case 0x46: // LSR zp - c = 0; - case 0x66: // ROR zp - ror_zp: { - int temp = READ_LOW( data ); - nz = (c >> 1 & 0x80) + (temp >> 1); - c = temp << 8; - goto write_nz_zp; - } - - case 0x36: // ROL zp,x - data = BYTE( data + x ); - goto rol_zp; - - case 0x16: // ASL zp,x - data = BYTE( data + x ); - case 0x06: // ASL zp - c = 0; - case 0x26: // ROL zp - rol_zp: - nz = c >> 8 & 1; - nz += (c = READ_LOW( data ) << 1); - goto write_nz_zp; - -// Increment/decrement - - case 0xCA: // DEX - INC_DEC( x, -1 ) - - case 0x88: // DEY - INC_DEC( y, -1 ) - - case 0xF6: // INC zp,x - data = BYTE( data + x ); - case 0xE6: // INC zp - nz = 1; - goto add_nz_zp; - - case 0xD6: // DEC zp,x - data = BYTE( data + x ); - case 0xC6: // DEC zp - nz = -1; - add_nz_zp: - nz += READ_LOW( data ); - write_nz_zp: - pc++; - WRITE_LOW( data, nz ); - goto loop; - - case 0xFE: // INC abs,x - data = x + GET_ADDR(); - goto inc_ptr; - - case 0xEE: // INC abs - data = GET_ADDR(); - inc_ptr: - nz = 1; - goto inc_common; - - case 0xDE: // DEC abs,x - data = x + GET_ADDR(); - goto dec_ptr; - - case 0xCE: // DEC abs - data = GET_ADDR(); - dec_ptr: - nz = -1; - inc_common: - FLUSH_TIME(); - pc += 2; - nz += READ_MEM( data ); - WRITE_MEM( data, BYTE( nz ) ); - CACHE_TIME(); - goto loop; - -// Transfer - - case 0xAA: // TAX - x = nz = a; - goto loop; - - case 0x8A: // TXA - a = nz = x; - goto loop; - - case 0x9A: // TXS - SET_SP( x ); // verified (no flag change) - goto loop; - - case 0xBA: // TSX - x = nz = GET_SP(); - goto loop; - -// Stack - - case 0x48: // PHA - sp = SP( -1 ); - WRITE_STACK( sp, a ); - goto loop; - - case 0x68: // PLA - a = nz = READ_STACK( sp ); - sp = SP( 1 ); - goto loop; - - case 0x40:{// RTI - pc = READ_STACK( SP( 1 ) ); - pc += READ_STACK( SP( 2 ) ) * 0x100; - int temp = READ_STACK( sp ); - sp = SP( 3 ); - data = flags; - SET_FLAGS( temp ); - CPU.r.flags = flags; // update externally-visible I flag - int delta = s.base - CPU.irq_time_; - if ( delta <= 0 ) goto loop; // end_time < irq_time - if ( flags & i04 ) goto loop; - s_time += delta; - s.base = CPU.irq_time_; - goto loop; - } - - case 0x28:{// PLP - int temp = READ_STACK( sp ); - sp = SP( 1 ); - int changed = flags ^ temp; - SET_FLAGS( temp ); - if ( !(changed & i04) ) - goto loop; // I flag didn't change - if ( flags & i04 ) - goto handle_sei; - goto handle_cli; - } - - case 0x08:{// PHP - int temp; - GET_FLAGS( temp ); - sp = SP( -1 ); - WRITE_STACK( sp, temp | (b10 | r20) ); - goto loop; - } - - case 0x6C:{// JMP (ind) - data = GET_ADDR(); - byte const* page = CODE_PAGE( data ); - pc = page [CODE_OFFSET( data )]; - data = (data & 0xFF00) + ((data + 1) & 0xFF); - pc += page [CODE_OFFSET( data )] * 0x100; - goto loop; - } - - case 0x00: // BRK - goto handle_brk; - -// Flags - - case 0x38: // SEC - c = 0x100; - goto loop; - - case 0x18: // CLC - c = 0; - goto loop; - - case 0xB8: // CLV - flags &= ~v40; - goto loop; - - case 0xD8: // CLD - flags &= ~d08; - goto loop; - - case 0xF8: // SED - flags |= d08; - goto loop; - - case 0x58: // CLI - if ( !(flags & i04) ) - goto loop; - flags &= ~i04; - handle_cli: { - //dprintf( "CLI at %d\n", TIME ); - CPU.r.flags = flags; // update externally-visible I flag - int delta = s.base - CPU.irq_time_; - if ( delta <= 0 ) - { - if ( TIME() < CPU.irq_time_ ) - goto loop; - goto delayed_cli; - } - s.base = CPU.irq_time_; - s_time += delta; - if ( s_time < 0 ) - goto loop; - - if ( delta >= s_time + 1 ) - { - // delayed irq until after next instruction - s.base += s_time + 1; - s_time = -1; - goto loop; - } - - // TODO: implement - delayed_cli: - dprintf( "Delayed CLI not emulated\n" ); - goto loop; - } - - case 0x78: // SEI - if ( flags & i04 ) - goto loop; - flags |= i04; - handle_sei: { - CPU.r.flags = flags; // update externally-visible I flag - int delta = s.base - CPU.end_time_; - s.base = CPU.end_time_; - s_time += delta; - if ( s_time < 0 ) - goto loop; - - dprintf( "Delayed SEI not emulated\n" ); - goto loop; - } - -// Unofficial - - // SKW - skip word - case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: - PAGE_PENALTY( data + x ); - case 0x0C: - pc++; - // SKB - skip byte - case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: - case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: - pc++; - goto loop; - - // NOP - case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: - goto loop; - - case Nes_Cpu::halt_opcode: // HLT - halt processor - if ( pc-- > 0x10000 ) - { - // handle wrap-around (assumes caller has put page of HLT at 0x10000) - pc = WORD( pc ); - goto loop; - } - case 0x02: case 0x12: case 0x32: case 0x42: case 0x52: - case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: - goto stop; - -// Unimplemented - - case 0xFF: // force 256-entry jump table for optimization purposes - c |= 1; // compiler doesn't know that this won't affect anything - default: - check( (unsigned) opcode < 0x100 ); - - #ifdef UNIMPL_INSTR - UNIMPL_INSTR(); - #endif - - // At least skip over proper number of bytes instruction uses - static unsigned char const illop_lens [8] = { - 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 - }; - int opcode = instr [-1]; - int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; - if ( opcode == 0x9C ) - len = 2; - pc += len; - CPU.error_count_++; - - // Account for extra clock - if ( (opcode >> 4) == 0x0B ) - { - if ( opcode == 0xB3 ) - data = READ_LOW( data ); - if ( opcode != 0xB7 ) - PAGE_PENALTY( data + y ); - } - goto loop; - } - assert( false ); // catch missing 'goto loop' or accidental 'break' - - int result_; -handle_brk: - pc++; - result_ = b10 | 4; - -#ifdef CPU_DONE -interrupt: -#endif - { - s_time += 7; - - // Save PC and read vector - WRITE_STACK( SP( -1 ), pc >> 8 ); - WRITE_STACK( SP( -2 ), pc ); - pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) ); - - // Save flags - int temp; - GET_FLAGS( temp ); - temp |= r20 + (result_ & b10); // B flag set for BRK - sp = SP( -3 ); - WRITE_STACK( sp, temp ); - - // Update I flag in externally-visible flags - CPU.r.flags = (flags |= i04); - - // Update time - int delta = s.base - CPU.end_time_; - if ( delta >= 0 ) - goto loop; - s_time += delta; - s.base = CPU.end_time_; - goto loop; - } - -out_of_time: - pc--; - - // Optional action that triggers interrupt or changes irq/end time - #ifdef CPU_DONE - { - CPU_DONE( result_ ); - if ( result_ >= 0 ) - goto interrupt; - if ( s_time < 0 ) - goto loop; - } - #endif -stop: - - // Flush cached state - CPU.r.pc = pc; - CPU.r.sp = GET_SP(); - CPU.r.a = a; - CPU.r.x = x; - CPU.r.y = y; - - int temp; - GET_FLAGS( temp ); - CPU.r.flags = temp; - - CPU.cpu_state_.base = s.base; - CPU.cpu_state_.time = s_time; - CPU.cpu_state = &CPU.cpu_state_; -} +// NES 6502 CPU emulator run function + +#if 0 +/* Define these macros in the source file before #including this file. +- Parameters might be expressions, so they are best evaluated only once, +though they NEVER have side-effects, so multiple evaluation is OK. +- Output parameters might be a multiple-assignment expression like "a=x", +so they must NOT be parenthesized. +- Except where noted, time() and related functions will NOT work +correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and +CACHE_TIME() allow the time changing functions to work. +- Macros "returning" void may use a {} statement block. */ + + // 0 <= addr <= 0xFFFF + page_size + // time functions can be used + int READ_MEM( addr_t ); + void WRITE_MEM( addr_t, int data ); + // 0 <= READ_MEM() <= 0xFF + + // 0 <= addr <= 0x1FF + int READ_LOW( addr_t ); + void WRITE_LOW( addr_t, int data ); + // 0 <= READ_LOW() <= 0xFF + + // Often-used instructions attempt these before using a normal memory access. + // Optional; defaults to READ_MEM() and WRITE_MEM() + bool CAN_READ_FAST( addr_t ); // if true, uses result of READ_FAST + void READ_FAST( addr_t, int& out ); // ALWAYS called BEFORE CAN_READ_FAST + bool CAN_WRITE_FAST( addr_t ); // if true, uses WRITE_FAST instead of WRITE_MEM + void WRITE_FAST( addr_t, int data ); + + // Used by instructions most often used to access the NES PPU (LDA abs and BIT abs). + // Optional; defaults to READ_MEM. + void READ_PPU( addr_t, int& out ); + // 0 <= out <= 0xFF + +// The following can be used within macros: + + // Current time + time_t TIME(); + + // Allows use of time functions + void FLUSH_TIME(); + + // Must be used before end of macro if FLUSH_TIME() was used earlier + void CACHE_TIME(); + +// Configuration (optional; commented behavior if defined) + + // Emulates dummy reads for indexed instructions + #define NES_CPU_DUMMY_READS 1 + + // Optimizes as if map_code( 0, 0x10000 + cpu_padding, FLAT_MEM ) is always in effect + #define FLAT_MEM my_mem_array + + // Expanded just before beginning of code, to help debugger + #define CPU_BEGIN void my_run_cpu() { + +#endif + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +// Allows MWCW debugger to step through code properly +#ifdef CPU_BEGIN + CPU_BEGIN +#endif + +// Time +#define TIME() (s_time + s.base) +#define FLUSH_TIME() {s.time = s_time - time_offset;} +#define CACHE_TIME() {s_time = s.time + time_offset;} + +// Defaults +#ifndef CAN_WRITE_FAST + #define CAN_WRITE_FAST( addr ) 0 + #define WRITE_FAST( addr, data ) +#endif + +#ifndef CAN_READ_FAST + #define CAN_READ_FAST( addr ) 0 + #define READ_FAST( addr, out ) +#endif + +#ifndef READ_PPU + #define READ_PPU( addr, out )\ + {\ + FLUSH_TIME();\ + out = READ_MEM( addr );\ + CACHE_TIME();\ + } +#endif + +#define READ_STACK READ_LOW +#define WRITE_STACK WRITE_LOW + +// Dummy reads +#if NES_CPU_DUMMY_READS + // TODO: optimize time handling + #define DUMMY_READ( addr, idx ) \ + if ( (addr & 0xFF) < idx )\ + {\ + int const time_offset = 1;\ + FLUSH_TIME();\ + READ_MEM( (addr - 0x100) );\ + CACHE_TIME();\ + } +#else + #define DUMMY_READ( addr, idx ) +#endif + +// Code +#ifdef FLAT_MEM + #define CODE_PAGE( addr ) (FLAT_MEM) + #define CODE_OFFSET( addr ) (addr) +#else + #define CODE_PAGE( addr ) (s.code_map [NES_CPU_PAGE( addr )]) + #define CODE_OFFSET( addr ) NES_CPU_OFFSET( addr ) +#endif +#define READ_CODE( addr ) (CODE_PAGE( addr ) [CODE_OFFSET( addr )]) + +// Stack +#define SET_SP( v ) (sp = ((v) + 1) | 0x100) +#define GET_SP() ((sp - 1) & 0xFF) +#define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) + +// Truncation +#define BYTE( n ) ((BOOST::uint8_t ) (n)) /* (unsigned) n & 0xFF */ +#define SBYTE( n ) ((BOOST::int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ +#define WORD( n ) ((BOOST::uint16_t) (n)) /* (unsigned) n & 0xFFFF */ + +// Flags with hex value for clarity when used as mask. +// Stored in indicated variable during emulation. +int const n80 = 0x80; // nz +int const v40 = 0x40; // flags +int const r20 = 0x20; +int const b10 = 0x10; +int const d08 = 0x08; // flags +int const i04 = 0x04; // flags +int const z02 = 0x02; // nz +int const c01 = 0x01; // c + +#define IS_NEG (nz & 0x8080) + +#define GET_FLAGS( out ) \ +{\ + out = flags & (v40 | d08 | i04);\ + out += ((nz >> 8) | nz) & n80;\ + out += c >> 8 & c01;\ + if ( !BYTE( nz ) )\ + out += z02;\ +} + +#define SET_FLAGS( in ) \ +{\ + flags = in & (v40 | d08 | i04);\ + c = nz = in << 8;\ + nz += ~in & z02;\ +} + +{ + int const time_offset = 0; + + // Local state + Nes_Cpu::cpu_state_t s; + #ifdef FLAT_MEM + s.base = CPU.cpu_state_.base; + #else + s = CPU.cpu_state_; + #endif + CPU.cpu_state = &s; + int s_time = CPU.cpu_state_.time; // helps even on x86 + + // Registers + int pc = CPU.r.pc; + int a = CPU.r.a; + int x = CPU.r.x; + int y = CPU.r.y; + int sp; + SET_SP( CPU.r.sp ); + + // Flags + int flags; + int c; // carry set if (c & 0x100) != 0 + int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 + { + int temp = CPU.r.flags; + SET_FLAGS( temp ); + } + +loop: + + // Check all values + check( (unsigned) sp - 0x100 < 0x100 ); + check( (unsigned) pc < 0x10000 ); + check( (unsigned) a < 0x100 ); + check( (unsigned) x < 0x100 ); + check( (unsigned) y < 0x100 ); + + // Read instruction + byte const* instr = CODE_PAGE( pc ); + int opcode; + + if ( CODE_OFFSET(~0) == ~0 ) + { + opcode = instr [pc]; + pc++; + instr += pc; + } + else + { + instr += CODE_OFFSET( pc ); + opcode = *instr++; + pc++; + } + + // local to function in case it helps optimizer + static byte const clock_table [256] = + {// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 + 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 + 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 + 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 + 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 + 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 + 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A + 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B + 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D + 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E + 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F + }; // 0x00 was 7 and 0x22 was 2 + + // Update time + if ( s_time >= 0 ) + goto out_of_time; + + #ifdef CPU_INSTR_HOOK + { CPU_INSTR_HOOK( (pc-1), (&instr [-1]), a, x, y, GET_SP(), TIME() ); } + #endif + + s_time += clock_table [opcode]; + + int data; + data = *instr; + + switch ( opcode ) + { + +// Macros + +#define GET_MSB() (instr [1]) +#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()) +#define GET_ADDR() GET_LE16( instr ) + +#define PAGE_PENALTY( lsb ) s_time += (lsb) >> 8; + +#define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; + +#define IND_Y( cross, out ) {\ + int temp = READ_LOW( data ) + y;\ + out = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ + cross( temp );\ + } + +#define IND_X( out ) {\ + int temp = data + x;\ + out = 0x100 * READ_LOW( BYTE( temp + 1 ) ) + READ_LOW( BYTE( temp ) );\ + } + +#define ARITH_ADDR_MODES( op )\ +case op - 0x04: /* (ind,x) */\ + IND_X( data )\ + goto ptr##op;\ +case op + 0x0C: /* (ind),y */\ + IND_Y( PAGE_PENALTY, data )\ + goto ptr##op;\ +case op + 0x10: /* zp,X */\ + data = BYTE( data + x );\ +case op + 0x00: /* zp */\ + data = READ_LOW( data );\ + goto imm##op;\ +case op + 0x14: /* abs,Y */\ + data += y;\ + goto ind##op;\ +case op + 0x18: /* abs,X */\ + data += x;\ +ind##op:\ + PAGE_PENALTY( data );\ +case op + 0x08: /* abs */\ + ADD_PAGE( data );\ +ptr##op:\ + FLUSH_TIME();\ + data = READ_MEM( data );\ + CACHE_TIME();\ +case op + 0x04: /* imm */\ +imm##op: + +// TODO: more efficient way to handle negative branch that wraps PC around +#define BRANCH( cond )\ +{\ + ++pc;\ + if ( !(cond) ) goto loop;\ + s_time++;\ + int offset = SBYTE( data );\ + s_time += (BYTE(pc) + offset) >> 8 & 1;\ + pc = WORD( pc + offset );\ + goto loop;\ +} + +// Often-Used + + case 0xB5: // LDA zp,x + a = nz = READ_LOW( BYTE( data + x ) ); + pc++; + goto loop; + + case 0xA5: // LDA zp + a = nz = READ_LOW( data ); + pc++; + goto loop; + + case 0xD0: // BNE + BRANCH( BYTE( nz ) ); + + case 0x20: { // JSR + int temp = pc + 1; + pc = GET_ADDR(); + WRITE_STACK( SP( -1 ), temp >> 8 ); + sp = SP( -2 ); + WRITE_STACK( sp, temp ); + goto loop; + } + + case 0x4C: // JMP abs + pc = GET_ADDR(); + goto loop; + + case 0xE8: // INX + INC_DEC( x, 1 ) + + case 0x10: // BPL + BRANCH( !IS_NEG ) + + ARITH_ADDR_MODES( 0xC5 ) // CMP + nz = a - data; + pc++; + c = ~nz; + nz &= 0xFF; + goto loop; + + case 0x30: // BMI + BRANCH( IS_NEG ) + + case 0xF0: // BEQ + BRANCH( !BYTE( nz ) ); + + case 0x95: // STA zp,x + data = BYTE( data + x ); + case 0x85: // STA zp + pc++; + WRITE_LOW( data, a ); + goto loop; + + case 0xC8: // INY + INC_DEC( y, 1 ) + + case 0xA8: // TAY + y = a; + nz = a; + goto loop; + + case 0x98: // TYA + a = y; + nz = y; + goto loop; + + case 0xAD:{// LDA abs + int addr = GET_ADDR(); + pc += 2; + READ_PPU( addr, a = nz ); + goto loop; + } + + case 0x60: // RTS + pc = 1 + READ_STACK( sp ); + pc += 0x100 * READ_STACK( SP( 1 ) ); + sp = SP( 2 ); + goto loop; + + { + int addr; + + case 0x8D: // STA abs + addr = GET_ADDR(); + pc += 2; + if ( CAN_WRITE_FAST( addr ) ) + { + WRITE_FAST( addr, a ); + goto loop; + } + sta_ptr: + FLUSH_TIME(); + WRITE_MEM( addr, a ); + CACHE_TIME(); + goto loop; + + case 0x99: // STA abs,Y + addr = y + GET_ADDR(); + pc += 2; + if ( CAN_WRITE_FAST( addr ) ) + { + WRITE_FAST( addr, a ); + goto loop; + } + goto sta_abs_x; + + case 0x9D: // STA abs,X (slightly more common than STA abs) + addr = x + GET_ADDR(); + pc += 2; + if ( CAN_WRITE_FAST( addr ) ) + { + WRITE_FAST( addr, a ); + goto loop; + } + DUMMY_READ( addr, x ); + sta_abs_x: + FLUSH_TIME(); + WRITE_MEM( addr, a ); + CACHE_TIME(); + goto loop; + + case 0x91: // STA (ind),Y + #define NO_PAGE_PENALTY( lsb ) + IND_Y( NO_PAGE_PENALTY, addr ) + pc++; + DUMMY_READ( addr, y ); + goto sta_ptr; + + case 0x81: // STA (ind,X) + IND_X( addr ) + pc++; + goto sta_ptr; + + } + + case 0xA9: // LDA #imm + pc++; + a = data; + nz = data; + goto loop; + + // common read instructions + { + int addr; + + case 0xA1: // LDA (ind,X) + IND_X( addr ) + pc++; + goto a_nz_read_addr; + + case 0xB1:// LDA (ind),Y + addr = READ_LOW( data ) + y; + PAGE_PENALTY( addr ); + addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); + pc++; + READ_FAST( addr, a = nz ); + if ( CAN_READ_FAST( addr ) ) + goto loop; + DUMMY_READ( addr, y ); + goto a_nz_read_addr; + + case 0xB9: // LDA abs,Y + PAGE_PENALTY( data + y ); + addr = GET_ADDR() + y; + pc += 2; + READ_FAST( addr, a = nz ); + if ( CAN_READ_FAST( addr ) ) + goto loop; + goto a_nz_read_addr; + + case 0xBD: // LDA abs,X + PAGE_PENALTY( data + x ); + addr = GET_ADDR() + x; + pc += 2; + READ_FAST( addr, a = nz ); + if ( CAN_READ_FAST( addr ) ) + goto loop; + DUMMY_READ( addr, x ); + a_nz_read_addr: + FLUSH_TIME(); + a = nz = READ_MEM( addr ); + CACHE_TIME(); + goto loop; + + } + +// Branch + + case 0x50: // BVC + BRANCH( !(flags & v40) ) + + case 0x70: // BVS + BRANCH( flags & v40 ) + + case 0xB0: // BCS + BRANCH( c & 0x100 ) + + case 0x90: // BCC + BRANCH( !(c & 0x100) ) + +// Load/store + + case 0x94: // STY zp,x + data = BYTE( data + x ); + case 0x84: // STY zp + pc++; + WRITE_LOW( data, y ); + goto loop; + + case 0x96: // STX zp,y + data = BYTE( data + y ); + case 0x86: // STX zp + pc++; + WRITE_LOW( data, x ); + goto loop; + + case 0xB6: // LDX zp,y + data = BYTE( data + y ); + case 0xA6: // LDX zp + data = READ_LOW( data ); + case 0xA2: // LDX #imm + pc++; + x = data; + nz = data; + goto loop; + + case 0xB4: // LDY zp,x + data = BYTE( data + x ); + case 0xA4: // LDY zp + data = READ_LOW( data ); + case 0xA0: // LDY #imm + pc++; + y = data; + nz = data; + goto loop; + + case 0xBC: // LDY abs,X + data += x; + PAGE_PENALTY( data ); + case 0xAC:{// LDY abs + int addr = data + 0x100 * GET_MSB(); + pc += 2; + FLUSH_TIME(); + y = nz = READ_MEM( addr ); + CACHE_TIME(); + goto loop; + } + + case 0xBE: // LDX abs,y + data += y; + PAGE_PENALTY( data ); + case 0xAE:{// LDX abs + int addr = data + 0x100 * GET_MSB(); + pc += 2; + FLUSH_TIME(); + x = nz = READ_MEM( addr ); + CACHE_TIME(); + goto loop; + } + + { + int temp; + case 0x8C: // STY abs + temp = y; + goto store_abs; + + case 0x8E: // STX abs + temp = x; + store_abs: + int addr = GET_ADDR(); + pc += 2; + if ( CAN_WRITE_FAST( addr ) ) + { + WRITE_FAST( addr, temp ); + goto loop; + } + FLUSH_TIME(); + WRITE_MEM( addr, temp ); + CACHE_TIME(); + goto loop; + } + +// Compare + + case 0xEC:{// CPX abs + int addr = GET_ADDR(); + pc++; + FLUSH_TIME(); + data = READ_MEM( addr ); + CACHE_TIME(); + goto cpx_data; + } + + case 0xE4: // CPX zp + data = READ_LOW( data ); + case 0xE0: // CPX #imm + cpx_data: + nz = x - data; + pc++; + c = ~nz; + nz &= 0xFF; + goto loop; + + case 0xCC:{// CPY abs + int addr = GET_ADDR(); + pc++; + FLUSH_TIME(); + data = READ_MEM( addr ); + CACHE_TIME(); + goto cpy_data; + } + + case 0xC4: // CPY zp + data = READ_LOW( data ); + case 0xC0: // CPY #imm + cpy_data: + nz = y - data; + pc++; + c = ~nz; + nz &= 0xFF; + goto loop; + +// Logical + + ARITH_ADDR_MODES( 0x25 ) // AND + nz = (a &= data); + pc++; + goto loop; + + ARITH_ADDR_MODES( 0x45 ) // EOR + nz = (a ^= data); + pc++; + goto loop; + + ARITH_ADDR_MODES( 0x05 ) // ORA + nz = (a |= data); + pc++; + goto loop; + + case 0x2C:{// BIT abs + int addr = GET_ADDR(); + pc += 2; + READ_PPU( addr, nz ); + flags = (flags & ~v40) + (nz & v40); + if ( a & nz ) + goto loop; + nz <<= 8; // result must be zero, even if N bit is set + goto loop; + } + + case 0x24: // BIT zp + nz = READ_LOW( data ); + pc++; + flags = (flags & ~v40) + (nz & v40); + if ( a & nz ) + goto loop; // Z should be clear, and nz must be non-zero if nz & a is + nz <<= 8; // set Z flag without affecting N flag + goto loop; + +// Add/subtract + + ARITH_ADDR_MODES( 0xE5 ) // SBC + case 0xEB: // unofficial equivalent + data ^= 0xFF; + goto adc_imm; + + ARITH_ADDR_MODES( 0x65 ) // ADC + adc_imm: { + int carry = c >> 8 & 1; + int ov = (a ^ 0x80) + carry + SBYTE( data ); + flags = (flags & ~v40) + (ov >> 2 & v40); + c = nz = a + data + carry; + pc++; + a = BYTE( nz ); + goto loop; + } + +// Shift/rotate + + case 0x4A: // LSR A + c = 0; + case 0x6A: // ROR A + nz = c >> 1 & 0x80; + c = a << 8; + nz += a >> 1; + a = nz; + goto loop; + + case 0x0A: // ASL A + nz = a << 1; + c = nz; + a = BYTE( nz ); + goto loop; + + case 0x2A: { // ROL A + nz = a << 1; + int temp = c >> 8 & 1; + c = nz; + nz += temp; + a = BYTE( nz ); + goto loop; + } + + case 0x5E: // LSR abs,X + data += x; + case 0x4E: // LSR abs + c = 0; + case 0x6E: // ROR abs + ror_abs: { + ADD_PAGE( data ); + FLUSH_TIME(); + int temp = READ_MEM( data ); + nz = (c >> 1 & 0x80) + (temp >> 1); + c = temp << 8; + goto rotate_common; + } + + case 0x3E: // ROL abs,X + data += x; + goto rol_abs; + + case 0x1E: // ASL abs,X + data += x; + case 0x0E: // ASL abs + c = 0; + case 0x2E: // ROL abs + rol_abs: + ADD_PAGE( data ); + nz = c >> 8 & 1; + FLUSH_TIME(); + nz += (c = READ_MEM( data ) << 1); + rotate_common: + pc++; + WRITE_MEM( data, BYTE( nz ) ); + CACHE_TIME(); + goto loop; + + case 0x7E: // ROR abs,X + data += x; + goto ror_abs; + + case 0x76: // ROR zp,x + data = BYTE( data + x ); + goto ror_zp; + + case 0x56: // LSR zp,x + data = BYTE( data + x ); + case 0x46: // LSR zp + c = 0; + case 0x66: // ROR zp + ror_zp: { + int temp = READ_LOW( data ); + nz = (c >> 1 & 0x80) + (temp >> 1); + c = temp << 8; + goto write_nz_zp; + } + + case 0x36: // ROL zp,x + data = BYTE( data + x ); + goto rol_zp; + + case 0x16: // ASL zp,x + data = BYTE( data + x ); + case 0x06: // ASL zp + c = 0; + case 0x26: // ROL zp + rol_zp: + nz = c >> 8 & 1; + nz += (c = READ_LOW( data ) << 1); + goto write_nz_zp; + +// Increment/decrement + + case 0xCA: // DEX + INC_DEC( x, -1 ) + + case 0x88: // DEY + INC_DEC( y, -1 ) + + case 0xF6: // INC zp,x + data = BYTE( data + x ); + case 0xE6: // INC zp + nz = 1; + goto add_nz_zp; + + case 0xD6: // DEC zp,x + data = BYTE( data + x ); + case 0xC6: // DEC zp + nz = -1; + add_nz_zp: + nz += READ_LOW( data ); + write_nz_zp: + pc++; + WRITE_LOW( data, nz ); + goto loop; + + case 0xFE: // INC abs,x + data = x + GET_ADDR(); + goto inc_ptr; + + case 0xEE: // INC abs + data = GET_ADDR(); + inc_ptr: + nz = 1; + goto inc_common; + + case 0xDE: // DEC abs,x + data = x + GET_ADDR(); + goto dec_ptr; + + case 0xCE: // DEC abs + data = GET_ADDR(); + dec_ptr: + nz = -1; + inc_common: + FLUSH_TIME(); + pc += 2; + nz += READ_MEM( data ); + WRITE_MEM( data, BYTE( nz ) ); + CACHE_TIME(); + goto loop; + +// Transfer + + case 0xAA: // TAX + x = nz = a; + goto loop; + + case 0x8A: // TXA + a = nz = x; + goto loop; + + case 0x9A: // TXS + SET_SP( x ); // verified (no flag change) + goto loop; + + case 0xBA: // TSX + x = nz = GET_SP(); + goto loop; + +// Stack + + case 0x48: // PHA + sp = SP( -1 ); + WRITE_STACK( sp, a ); + goto loop; + + case 0x68: // PLA + a = nz = READ_STACK( sp ); + sp = SP( 1 ); + goto loop; + + case 0x40:{// RTI + pc = READ_STACK( SP( 1 ) ); + pc += READ_STACK( SP( 2 ) ) * 0x100; + int temp = READ_STACK( sp ); + sp = SP( 3 ); + data = flags; + SET_FLAGS( temp ); + CPU.r.flags = flags; // update externally-visible I flag + int delta = s.base - CPU.irq_time_; + if ( delta <= 0 ) goto loop; // end_time < irq_time + if ( flags & i04 ) goto loop; + s_time += delta; + s.base = CPU.irq_time_; + goto loop; + } + + case 0x28:{// PLP + int temp = READ_STACK( sp ); + sp = SP( 1 ); + int changed = flags ^ temp; + SET_FLAGS( temp ); + if ( !(changed & i04) ) + goto loop; // I flag didn't change + if ( flags & i04 ) + goto handle_sei; + goto handle_cli; + } + + case 0x08:{// PHP + int temp; + GET_FLAGS( temp ); + sp = SP( -1 ); + WRITE_STACK( sp, temp | (b10 | r20) ); + goto loop; + } + + case 0x6C:{// JMP (ind) + data = GET_ADDR(); + byte const* page = CODE_PAGE( data ); + pc = page [CODE_OFFSET( data )]; + data = (data & 0xFF00) + ((data + 1) & 0xFF); + pc += page [CODE_OFFSET( data )] * 0x100; + goto loop; + } + + case 0x00: // BRK + goto handle_brk; + +// Flags + + case 0x38: // SEC + c = 0x100; + goto loop; + + case 0x18: // CLC + c = 0; + goto loop; + + case 0xB8: // CLV + flags &= ~v40; + goto loop; + + case 0xD8: // CLD + flags &= ~d08; + goto loop; + + case 0xF8: // SED + flags |= d08; + goto loop; + + case 0x58: // CLI + if ( !(flags & i04) ) + goto loop; + flags &= ~i04; + handle_cli: { + //dprintf( "CLI at %d\n", TIME ); + CPU.r.flags = flags; // update externally-visible I flag + int delta = s.base - CPU.irq_time_; + if ( delta <= 0 ) + { + if ( TIME() < CPU.irq_time_ ) + goto loop; + goto delayed_cli; + } + s.base = CPU.irq_time_; + s_time += delta; + if ( s_time < 0 ) + goto loop; + + if ( delta >= s_time + 1 ) + { + // delayed irq until after next instruction + s.base += s_time + 1; + s_time = -1; + goto loop; + } + + // TODO: implement + delayed_cli: + dprintf( "Delayed CLI not emulated\n" ); + goto loop; + } + + case 0x78: // SEI + if ( flags & i04 ) + goto loop; + flags |= i04; + handle_sei: { + CPU.r.flags = flags; // update externally-visible I flag + int delta = s.base - CPU.end_time_; + s.base = CPU.end_time_; + s_time += delta; + if ( s_time < 0 ) + goto loop; + + dprintf( "Delayed SEI not emulated\n" ); + goto loop; + } + +// Unofficial + + // SKW - skip word + case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: + PAGE_PENALTY( data + x ); + case 0x0C: + pc++; + // SKB - skip byte + case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: + case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: + pc++; + goto loop; + + // NOP + case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: + goto loop; + + case Nes_Cpu::halt_opcode: // HLT - halt processor + if ( pc-- > 0x10000 ) + { + // handle wrap-around (assumes caller has put page of HLT at 0x10000) + pc = WORD( pc ); + goto loop; + } + case 0x02: case 0x12: case 0x32: case 0x42: case 0x52: + case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: + goto stop; + +// Unimplemented + + case 0xFF: // force 256-entry jump table for optimization purposes + c |= 1; // compiler doesn't know that this won't affect anything + default: + check( (unsigned) opcode < 0x100 ); + + #ifdef UNIMPL_INSTR + UNIMPL_INSTR(); + #endif + + // At least skip over proper number of bytes instruction uses + static unsigned char const illop_lens [8] = { + 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 + }; + int opcode = instr [-1]; + int len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; + if ( opcode == 0x9C ) + len = 2; + pc += len; + CPU.error_count_++; + + // Account for extra clock + if ( (opcode >> 4) == 0x0B ) + { + if ( opcode == 0xB3 ) + data = READ_LOW( data ); + if ( opcode != 0xB7 ) + PAGE_PENALTY( data + y ); + } + goto loop; + } + assert( false ); // catch missing 'goto loop' or accidental 'break' + + int result_; +handle_brk: + pc++; + result_ = b10 | 4; + +#ifdef CPU_DONE +interrupt: +#endif + { + s_time += 7; + + // Save PC and read vector + WRITE_STACK( SP( -1 ), pc >> 8 ); + WRITE_STACK( SP( -2 ), pc ); + pc = GET_LE16( &READ_CODE( 0xFFFA ) + (result_ & 4) ); + + // Save flags + int temp; + GET_FLAGS( temp ); + temp |= r20 + (result_ & b10); // B flag set for BRK + sp = SP( -3 ); + WRITE_STACK( sp, temp ); + + // Update I flag in externally-visible flags + CPU.r.flags = (flags |= i04); + + // Update time + int delta = s.base - CPU.end_time_; + if ( delta >= 0 ) + goto loop; + s_time += delta; + s.base = CPU.end_time_; + goto loop; + } + +out_of_time: + pc--; + + // Optional action that triggers interrupt or changes irq/end time + #ifdef CPU_DONE + { + CPU_DONE( result_ ); + if ( result_ >= 0 ) + goto interrupt; + if ( s_time < 0 ) + goto loop; + } + #endif +stop: + + // Flush cached state + CPU.r.pc = pc; + CPU.r.sp = GET_SP(); + CPU.r.a = a; + CPU.r.x = x; + CPU.r.y = y; + + int temp; + GET_FLAGS( temp ); + CPU.r.flags = temp; + + CPU.cpu_state_.base = s.base; + CPU.cpu_state_.time = s_time; + CPU.cpu_state = &CPU.cpu_state_; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nes_Namco_Apu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nes_Namco_Apu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nes_Namco_Apu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nes_Namco_Apu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,152 +1,151 @@ -// Nes_Snd_Emu $vers. http://www.slack.net/~ant/ - -#include "Nes_Namco_Apu.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Nes_Namco_Apu::Nes_Namco_Apu() -{ - set_output( NULL ); - volume( 1.0 ); - reset(); -} - -void Nes_Namco_Apu::reset() -{ - last_time = 0; - addr_reg = 0; - - int i; - for ( i = 0; i < reg_count; i++ ) - reg [i] = 0; - - for ( i = 0; i < osc_count; i++ ) - { - Namco_Osc& osc = oscs [i]; - osc.delay = 0; - osc.last_amp = 0; - osc.wave_pos = 0; - } -} - -void Nes_Namco_Apu::set_output( Blip_Buffer* buf ) -{ - for ( int i = 0; i < osc_count; ++i ) - set_output( i, buf ); -} - -/* -void Nes_Namco_Apu::reflect_state( Tagged_Data& data ) -{ - reflect_int16( data, BLARGG_4CHAR('A','D','D','R'), &addr_reg ); - - static const char hex [17] = "0123456789ABCDEF"; - int i; - for ( i = 0; i < reg_count; i++ ) - reflect_int16( data, 'RG\0\0' + hex [i >> 4] * 0x100 + hex [i & 15], ® [i] ); - - for ( i = 0; i < osc_count; i++ ) - { - reflect_int32( data, BLARGG_4CHAR('D','L','Y','0') + i, &oscs [i].delay ); - reflect_int16( data, BLARGG_4CHAR('P','O','S','0') + i, &oscs [i].wave_pos ); - } -} -*/ - -void Nes_Namco_Apu::end_frame( blip_time_t time ) -{ - if ( time > last_time ) - run_until( time ); - - assert( last_time >= time ); - last_time -= time; -} - -void Nes_Namco_Apu::run_until( blip_time_t nes_end_time ) -{ - int active_oscs = (reg [0x7F] >> 4 & 7) + 1; - for ( int i = osc_count - active_oscs; i < osc_count; i++ ) - { - Namco_Osc& osc = oscs [i]; - Blip_Buffer* output = osc.output; - if ( !output ) - continue; - - blip_resampled_time_t time = - output->resampled_time( last_time ) + osc.delay; - blip_resampled_time_t end_time = output->resampled_time( nes_end_time ); - osc.delay = 0; - if ( time < end_time ) - { - const BOOST::uint8_t* osc_reg = ® [i * 8 + 0x40]; - if ( !(osc_reg [4] & 0xE0) ) - continue; - - int volume = osc_reg [7] & 15; - if ( !volume ) - continue; - - int freq = (osc_reg [4] & 3) * 0x10000 + osc_reg [2] * 0x100 + osc_reg [0]; - if ( freq < 64 * active_oscs ) - continue; // prevent low frequencies from excessively delaying freq changes - - int const master_clock_divider = 12; // NES time derived via divider of master clock - int const n106_divider = 45; // N106 then divides master clock by this - int const max_freq = 0x3FFFF; - int const lowest_freq_period = (max_freq + 1) * n106_divider / master_clock_divider; - // divide by 8 to avoid overflow - blip_resampled_time_t period = - output->resampled_duration( lowest_freq_period / 8 ) / freq * 8 * active_oscs; - - int wave_size = 32 - (osc_reg [4] >> 2 & 7) * 4; - if ( !wave_size ) - continue; - - int last_amp = osc.last_amp; - int wave_pos = osc.wave_pos; - - output->set_modified(); - - do - { - // read wave sample - int addr = wave_pos + osc_reg [6]; - int sample = reg [addr >> 1] >> (addr << 2 & 4); - wave_pos++; - sample = (sample & 15) * volume; - - // output impulse if amplitude changed - int delta = sample - last_amp; - if ( delta ) - { - last_amp = sample; - synth.offset_resampled( time, delta, output ); - } - - // next sample - time += period; - if ( wave_pos >= wave_size ) - wave_pos = 0; - } - while ( time < end_time ); - - osc.wave_pos = wave_pos; - osc.last_amp = last_amp; - } - osc.delay = time - end_time; - } - - last_time = nes_end_time; -} - +// Nes_Snd_Emu $vers. http://www.slack.net/~ant/ + +#include "Nes_Namco_Apu.h" + +/* Copyright (C) 2003-2006 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Nes_Namco_Apu::Nes_Namco_Apu() +{ + set_output( NULL ); + volume( 1.0 ); + reset(); +} + +void Nes_Namco_Apu::reset() +{ + last_time = 0; + addr_reg = 0; + + int i; + for ( i = 0; i < reg_count; i++ ) + reg [i] = 0; + + for ( i = 0; i < osc_count; i++ ) + { + Namco_Osc& osc = oscs [i]; + osc.delay = 0; + osc.last_amp = 0; + osc.wave_pos = 0; + } +} + +void Nes_Namco_Apu::set_output( Blip_Buffer* buf ) +{ + for ( int i = 0; i < osc_count; ++i ) + set_output( i, buf ); +} + +/* +void Nes_Namco_Apu::reflect_state( Tagged_Data& data ) +{ + reflect_int16( data, BLARGG_4CHAR('A','D','D','R'), &addr_reg ); + + static const char hex [17] = "0123456789ABCDEF"; + int i; + for ( i = 0; i < reg_count; i++ ) + reflect_int16( data, 'RG\0\0' + hex [i >> 4] * 0x100 + hex [i & 15], ® [i] ); + + for ( i = 0; i < osc_count; i++ ) + { + reflect_int32( data, BLARGG_4CHAR('D','L','Y','0') + i, &oscs [i].delay ); + reflect_int16( data, BLARGG_4CHAR('P','O','S','0') + i, &oscs [i].wave_pos ); + } +} +*/ + +void Nes_Namco_Apu::end_frame( blip_time_t time ) +{ + if ( time > last_time ) + run_until( time ); + + assert( last_time >= time ); + last_time -= time; +} + +void Nes_Namco_Apu::run_until( blip_time_t nes_end_time ) +{ + int active_oscs = (reg [0x7F] >> 4 & 7) + 1; + for ( int i = osc_count - active_oscs; i < osc_count; i++ ) + { + Namco_Osc& osc = oscs [i]; + Blip_Buffer* output = osc.output; + if ( !output ) + continue; + + blip_resampled_time_t time = + output->resampled_time( last_time ) + osc.delay; + blip_resampled_time_t end_time = output->resampled_time( nes_end_time ); + osc.delay = 0; + if ( time < end_time ) + { + const BOOST::uint8_t* osc_reg = ® [i * 8 + 0x40]; + if ( !(osc_reg [4] & 0xE0) ) + continue; + + int volume = osc_reg [7] & 15; + if ( !volume ) + continue; + + int freq = (osc_reg [4] & 3) * 0x10000 + osc_reg [2] * 0x100 + osc_reg [0]; + if ( freq < 64 * active_oscs ) + continue; // prevent low frequencies from excessively delaying freq changes + + int const master_clock_divider = 12; // NES time derived via divider of master clock + int const n106_divider = 45; // N106 then divides master clock by this + int const max_freq = 0x3FFFF; + int const lowest_freq_period = (max_freq + 1) * n106_divider / master_clock_divider; + // divide by 8 to avoid overflow + blip_resampled_time_t period = + output->resampled_duration( lowest_freq_period / 8 ) / freq * 8 * active_oscs; + + int wave_size = 32 - (osc_reg [4] >> 2 & 7) * 4; + if ( !wave_size ) + continue; + + int last_amp = osc.last_amp; + int wave_pos = osc.wave_pos; + + output->set_modified(); + + do + { + // read wave sample + int addr = wave_pos + osc_reg [6]; + int sample = reg [addr >> 1] >> (addr << 2 & 4); + wave_pos++; + sample = (sample & 15) * volume; + + // output impulse if amplitude changed + int delta = sample - last_amp; + if ( delta ) + { + last_amp = sample; + synth.offset_resampled( time, delta, output ); + } + + // next sample + time += period; + if ( wave_pos >= wave_size ) + wave_pos = 0; + } + while ( time < end_time ); + + osc.wave_pos = wave_pos; + osc.last_amp = last_amp; + } + osc.delay = time - end_time; + } + + last_time = nes_end_time; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/nestypes.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/nestypes.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/nestypes.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/nestypes.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,39 +1,39 @@ -#ifndef NESTYPES_H__ -#define NESTYPES_H__ - -#if defined(_MSC_VER) -#define NEVER_REACH __assume(0); -#define inline __inline -#elif defined(__BORLANDC__) -#define __fastcall __msfastcall -#elif defined(__GNUC__) -#define __inline __inline__ -#define __fastcall -#else -#define __inline -#define __fastcall -#endif -#ifndef NEVER_REACH -#define NEVER_REACH -#endif - -typedef int Int; -typedef unsigned int Uint; -typedef signed int Int32; -typedef unsigned int Uint32; -typedef signed short Int16; -typedef unsigned short Uint16; -typedef signed char Int8; -typedef unsigned char Uint8; -typedef char Char; - -#include - -#define XSLEEP(n) ((void)0) -#define XMALLOC(s) malloc(s) -#define XREALLOC(p,s) realloc(p,s) -#define XFREE(p) free(p) -#define XMEMCPY(d,s,n) memcpy(d,s,n) -#define XMEMSET(d,c,n) memset(d,c,n) - -#endif /* NESTYPES_H__ */ +#ifndef NESTYPES_H__ +#define NESTYPES_H__ + +#if defined(_MSC_VER) +#define NEVER_REACH __assume(0); +#define inline __inline +#elif defined(__BORLANDC__) +#define __fastcall __msfastcall +#elif defined(__GNUC__) +#define __inline __inline__ +#define __fastcall +#else +#define __inline +#define __fastcall +#endif +#ifndef NEVER_REACH +#define NEVER_REACH +#endif + +typedef int Int; +typedef unsigned int Uint; +typedef signed int Int32; +typedef unsigned int Uint32; +typedef signed short Int16; +typedef unsigned short Uint16; +typedef signed char Int8; +typedef unsigned char Uint8; +typedef char Char; + +#include + +#define XSLEEP(n) ((void)0) +#define XMALLOC(s) malloc(s) +#define XREALLOC(p,s) realloc(p,s) +#define XFREE(p) free(p) +#define XMEMCPY(d,s,n) memcpy(d,s,n) +#define XMEMSET(d,c,n) memset(d,c,n) + +#endif /* NESTYPES_H__ */ diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nes_Vrc7_Apu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nes_Vrc7_Apu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nes_Vrc7_Apu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nes_Vrc7_Apu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,206 +1,206 @@ -#include "Nes_Vrc7_Apu.h" - -#include "ym2413.h" -#include - -#include "blargg_source.h" - -int const period = 36; // NES CPU clocks per FM clock - -Nes_Vrc7_Apu::Nes_Vrc7_Apu() -{ - opll = 0; -} - -blargg_err_t Nes_Vrc7_Apu::init() -{ - CHECK_ALLOC( opll = ym2413_init( 3579545, 3579545 / 72, 1 ) ); - - set_output( 0 ); - volume( 1.0 ); - reset(); - return 0; -} - -Nes_Vrc7_Apu::~Nes_Vrc7_Apu() -{ - if ( opll ) - ym2413_shutdown( opll ); -} - -void Nes_Vrc7_Apu::set_output( Blip_Buffer* buf ) -{ - for ( int i = 0; i < osc_count; ++i ) - oscs [i].output = buf; - output_changed(); -} - -void Nes_Vrc7_Apu::output_changed() -{ - mono.output = oscs [0].output; - for ( int i = osc_count; --i; ) - { - if ( mono.output != oscs [i].output ) - { - mono.output = 0; - break; - } - } - - if ( mono.output ) - { - for ( int i = osc_count; --i; ) - { - mono.last_amp += oscs [i].last_amp; - oscs [i].last_amp = 0; - } - } -} - -void Nes_Vrc7_Apu::reset() -{ - addr = 0; - next_time = 0; - mono.last_amp = 0; - - for ( int i = osc_count; --i >= 0; ) - { - Vrc7_Osc& osc = oscs [i]; - osc.last_amp = 0; - for ( int j = 0; j < 3; ++j ) - osc.regs [j] = 0; - } - - ym2413_reset_chip( opll ); -} - -void Nes_Vrc7_Apu::write_reg( int data ) -{ - addr = data; -} - -void Nes_Vrc7_Apu::write_data( blip_time_t time, int data ) -{ - int type = (addr >> 4) - 1; - int chan = addr & 15; - if ( (unsigned) type < 3 && chan < osc_count ) - oscs [chan].regs [type] = data; - - if ( time > next_time ) - run_until( time ); - ym2413_write( opll, 0, addr ); - ym2413_write( opll, 1, data ); -} - -void Nes_Vrc7_Apu::end_frame( blip_time_t time ) -{ - if ( time > next_time ) - run_until( time ); - - next_time -= time; - assert( next_time >= 0 ); - - for ( int i = osc_count; --i >= 0; ) - { - Blip_Buffer* output = oscs [i].output; - if ( output ) - output->set_modified(); - } -} - -void Nes_Vrc7_Apu::save_snapshot( vrc7_snapshot_t* out ) const -{ - out->latch = addr; - out->delay = next_time; - for ( int i = osc_count; --i >= 0; ) - { - for ( int j = 0; j < 3; ++j ) - out->regs [i] [j] = oscs [i].regs [j]; - } - memcpy( out->inst, ym2413_get_inst0( opll ), 8 ); -} - -void Nes_Vrc7_Apu::load_snapshot( vrc7_snapshot_t const& in ) -{ - assert( offsetof (vrc7_snapshot_t,delay) == 28 - 1 ); - - reset(); - next_time = in.delay; - write_reg( in.latch ); - int i; - for ( i = 0; i < osc_count; ++i ) - { - for ( int j = 0; j < 3; ++j ) - oscs [i].regs [j] = in.regs [i] [j]; - } - - for ( i = 0; i < 8; ++i ) - { - ym2413_write( opll, 0, i ); - ym2413_write( opll, 1, in.inst [i] ); - } - - for ( i = 0; i < 3; ++i ) - { - for ( int j = 0; j < 6; ++j ) - { - ym2413_write( opll, 0, 0x10 + i * 0x10 + j ); - ym2413_write( opll, 1, oscs [j].regs [i] ); - } - } -} - -void Nes_Vrc7_Apu::run_until( blip_time_t end_time ) -{ - require( end_time > next_time ); - - blip_time_t time = next_time; - void* opll = this->opll; // cache - Blip_Buffer* const mono_output = mono.output; - if ( mono_output ) - { - // optimal case - do - { - ym2413_advance_lfo( opll ); - int amp = 0; - for ( int i = 0; i < osc_count; i++ ) - amp += ym2413_calcch( opll, i ); - ym2413_advance( opll ); - int delta = amp - mono.last_amp; - if ( delta ) - { - mono.last_amp = amp; - synth.offset_inline( time, delta, mono_output ); - } - time += period; - } - while ( time < end_time ); - } - else - { - mono.last_amp = 0; - do - { - ym2413_advance_lfo( opll ); - for ( int i = 0; i < osc_count; ++i ) - { - Vrc7_Osc& osc = oscs [i]; - if ( osc.output ) - { - int amp = ym2413_calcch( opll, i ); - int delta = amp - osc.last_amp; - if ( delta ) - { - osc.last_amp = amp; - synth.offset( time, delta, osc.output ); - } - } - } - ym2413_advance( opll ); - time += period; - } - while ( time < end_time ); - } - next_time = time; -} +#include "Nes_Vrc7_Apu.h" + +#include "ym2413.h" +#include + +#include "blargg_source.h" + +int const period = 36; // NES CPU clocks per FM clock + +Nes_Vrc7_Apu::Nes_Vrc7_Apu() +{ + opll = 0; +} + +blargg_err_t Nes_Vrc7_Apu::init() +{ + CHECK_ALLOC( opll = ym2413_init( 3579545, 3579545 / 72, 1 ) ); + + set_output( 0 ); + volume( 1.0 ); + reset(); + return 0; +} + +Nes_Vrc7_Apu::~Nes_Vrc7_Apu() +{ + if ( opll ) + ym2413_shutdown( opll ); +} + +void Nes_Vrc7_Apu::set_output( Blip_Buffer* buf ) +{ + for ( int i = 0; i < osc_count; ++i ) + oscs [i].output = buf; + output_changed(); +} + +void Nes_Vrc7_Apu::output_changed() +{ + mono.output = oscs [0].output; + for ( int i = osc_count; --i; ) + { + if ( mono.output != oscs [i].output ) + { + mono.output = 0; + break; + } + } + + if ( mono.output ) + { + for ( int i = osc_count; --i; ) + { + mono.last_amp += oscs [i].last_amp; + oscs [i].last_amp = 0; + } + } +} + +void Nes_Vrc7_Apu::reset() +{ + addr = 0; + next_time = 0; + mono.last_amp = 0; + + for ( int i = osc_count; --i >= 0; ) + { + Vrc7_Osc& osc = oscs [i]; + osc.last_amp = 0; + for ( int j = 0; j < 3; ++j ) + osc.regs [j] = 0; + } + + ym2413_reset_chip( opll ); +} + +void Nes_Vrc7_Apu::write_reg( int data ) +{ + addr = data; +} + +void Nes_Vrc7_Apu::write_data( blip_time_t time, int data ) +{ + int type = (addr >> 4) - 1; + int chan = addr & 15; + if ( (unsigned) type < 3 && chan < osc_count ) + oscs [chan].regs [type] = data; + + if ( time > next_time ) + run_until( time ); + ym2413_write( opll, 0, addr ); + ym2413_write( opll, 1, data ); +} + +void Nes_Vrc7_Apu::end_frame( blip_time_t time ) +{ + if ( time > next_time ) + run_until( time ); + + next_time -= time; + assert( next_time >= 0 ); + + for ( int i = osc_count; --i >= 0; ) + { + Blip_Buffer* output = oscs [i].output; + if ( output ) + output->set_modified(); + } +} + +void Nes_Vrc7_Apu::save_snapshot( vrc7_snapshot_t* out ) const +{ + out->latch = addr; + out->delay = next_time; + for ( int i = osc_count; --i >= 0; ) + { + for ( int j = 0; j < 3; ++j ) + out->regs [i] [j] = oscs [i].regs [j]; + } + memcpy( out->inst, ym2413_get_inst0( opll ), 8 ); +} + +void Nes_Vrc7_Apu::load_snapshot( vrc7_snapshot_t const& in ) +{ + assert( offsetof (vrc7_snapshot_t,delay) == 28 - 1 ); + + reset(); + next_time = in.delay; + write_reg( in.latch ); + int i; + for ( i = 0; i < osc_count; ++i ) + { + for ( int j = 0; j < 3; ++j ) + oscs [i].regs [j] = in.regs [i] [j]; + } + + for ( i = 0; i < 8; ++i ) + { + ym2413_write( opll, 0, i ); + ym2413_write( opll, 1, in.inst [i] ); + } + + for ( i = 0; i < 3; ++i ) + { + for ( int j = 0; j < 6; ++j ) + { + ym2413_write( opll, 0, 0x10 + i * 0x10 + j ); + ym2413_write( opll, 1, oscs [j].regs [i] ); + } + } +} + +void Nes_Vrc7_Apu::run_until( blip_time_t end_time ) +{ + require( end_time > next_time ); + + blip_time_t time = next_time; + void* opll = this->opll; // cache + Blip_Buffer* const mono_output = mono.output; + if ( mono_output ) + { + // optimal case + do + { + ym2413_advance_lfo( opll ); + int amp = 0; + for ( int i = 0; i < osc_count; i++ ) + amp += ym2413_calcch( opll, i ); + ym2413_advance( opll ); + int delta = amp - mono.last_amp; + if ( delta ) + { + mono.last_amp = amp; + synth.offset_inline( time, delta, mono_output ); + } + time += period; + } + while ( time < end_time ); + } + else + { + mono.last_amp = 0; + do + { + ym2413_advance_lfo( opll ); + for ( int i = 0; i < osc_count; ++i ) + { + Vrc7_Osc& osc = oscs [i]; + if ( osc.output ) + { + int amp = ym2413_calcch( opll, i ); + int delta = amp - osc.last_amp; + if ( delta ) + { + osc.last_amp = amp; + synth.offset( time, delta, osc.output ); + } + } + } + ym2413_advance( opll ); + time += period; + } + while ( time < end_time ); + } + next_time = time; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nsfe_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nsfe_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nsfe_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nsfe_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,329 +1,329 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Nsfe_Emu.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2005-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Nsfe_Info::Nsfe_Info() { playlist_disabled = false; } - -Nsfe_Info::~Nsfe_Info() { } - -inline void Nsfe_Info::unload() -{ - data.clear(); - track_name_data.clear(); - track_names.clear(); - playlist.clear(); - track_times.clear(); -} - -// TODO: if no playlist, treat as if there is a playlist that is just 1,2,3,4,5... ? -void Nsfe_Info::disable_playlist( bool b ) -{ - playlist_disabled = b; - info.track_count = playlist.size(); - if ( !info.track_count || playlist_disabled ) - info.track_count = actual_track_count_; -} - -int Nsfe_Info::remap_track( int track ) const -{ - if ( !playlist_disabled && (unsigned) track < playlist.size() ) - track = playlist [track]; - return track; -} - -// Read multiple strings and separate into individual strings -static blargg_err_t read_strs( Data_Reader& in, int size, blargg_vector& chars, - blargg_vector& strs ) -{ - RETURN_ERR( chars.resize( size + 1 ) ); - chars [size] = 0; // in case last string doesn't have terminator - RETURN_ERR( in.read( &chars [0], size ) ); - - RETURN_ERR( strs.resize( 128 ) ); - int count = 0; - for ( int i = 0; i < size; i++ ) - { - if ( (int) strs.size() <= count ) - RETURN_ERR( strs.resize( count * 2 ) ); - strs [count++] = &chars [i]; - while ( i < size && chars [i] ) - i++; - } - - return strs.resize( count ); -} - -// Copy in to out, where out has out_max characters allocated. Truncate to -// out_max - 1 characters. -static void copy_str( const char in [], char out [], int out_max ) -{ - out [out_max - 1] = 0; - strncpy( out, in, out_max - 1 ); -} - -struct nsfe_info_t -{ - byte load_addr [2]; - byte init_addr [2]; - byte play_addr [2]; - byte speed_flags; - byte chip_flags; - byte track_count; - byte first_track; - byte unused [6]; -}; - -blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsfe_Emu* nsf_emu ) -{ - int const nsfe_info_size = 16; - assert( offsetof (nsfe_info_t,unused [6]) == nsfe_info_size ); - - // check header - byte signature [4]; - blargg_err_t err = in.read( signature, sizeof signature ); - if ( err ) - return (blargg_is_err_type( err, blargg_err_file_eof ) ? blargg_err_file_type : err); - if ( memcmp( signature, "NSFE", 4 ) ) - return blargg_err_file_type; - - // free previous info - track_name_data.clear(); - track_names.clear(); - playlist.clear(); - track_times.clear(); - - // default nsf header - static const Nsf_Emu::header_t base_header = - { - {'N','E','S','M','\x1A'},// tag - 1, // version - 1, 1, // track count, first track - {0,0},{0,0},{0,0}, // addresses - "","","", // strings - {0x1A, 0x41}, // NTSC rate - {0,0,0,0,0,0,0,0}, // banks - {0x20, 0x4E}, // PAL rate - 0, 0, // flags - {0,0,0,0} // unused - }; - Nsf_Emu::header_t& header = info; - header = base_header; - - // parse tags - int phase = 0; - while ( phase != 3 ) - { - // read size and tag - byte block_header [2] [4]; - RETURN_ERR( in.read( block_header, sizeof block_header ) ); - int size = get_le32( block_header [0] ); - int tag = get_le32( block_header [1] ); - - //dprintf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) ); - - switch ( tag ) - { - case BLARGG_4CHAR('O','F','N','I'): { - check( phase == 0 ); - if ( size < 8 ) - return blargg_err_file_corrupt; - - nsfe_info_t finfo; - finfo.track_count = 1; - finfo.first_track = 0; - - RETURN_ERR( in.read( &finfo, min( size, (int) nsfe_info_size ) ) ); - if ( size > nsfe_info_size ) - RETURN_ERR( in.skip( size - nsfe_info_size ) ); - phase = 1; - info.speed_flags = finfo.speed_flags; - info.chip_flags = finfo.chip_flags; - info.track_count = finfo.track_count; - this->actual_track_count_ = finfo.track_count; - info.first_track = finfo.first_track; - memcpy( info.load_addr, finfo.load_addr, 2 * 3 ); - break; - } - - case BLARGG_4CHAR('K','N','A','B'): - if ( size > (int) sizeof info.banks ) - return blargg_err_file_corrupt; - RETURN_ERR( in.read( info.banks, size ) ); - break; - - case BLARGG_4CHAR('h','t','u','a'): { - blargg_vector chars; - blargg_vector strs; - RETURN_ERR( read_strs( in, size, chars, strs ) ); - int n = strs.size(); - - if ( n > 3 ) - copy_str( strs [3], info.dumper, sizeof info.dumper ); - - if ( n > 2 ) - copy_str( strs [2], info.copyright, sizeof info.copyright ); - - if ( n > 1 ) - copy_str( strs [1], info.author, sizeof info.author ); - - if ( n > 0 ) - copy_str( strs [0], info.game, sizeof info.game ); - - break; - } - - case BLARGG_4CHAR('e','m','i','t'): - RETURN_ERR( track_times.resize( size / 4 ) ); - RETURN_ERR( in.read( track_times.begin(), track_times.size() * 4 ) ); - break; - - case BLARGG_4CHAR('l','b','l','t'): - RETURN_ERR( read_strs( in, size, track_name_data, track_names ) ); - break; - - case BLARGG_4CHAR('t','s','l','p'): - RETURN_ERR( playlist.resize( size ) ); - RETURN_ERR( in.read( &playlist [0], size ) ); - break; - - case BLARGG_4CHAR('A','T','A','D'): { - check( phase == 1 ); - phase = 2; - if ( !nsf_emu ) - { - RETURN_ERR( data.resize( size ) ); - RETURN_ERR( in.read( data.begin(), size ) ); - } - else - { - Subset_Reader sub( &in, size ); // limit emu to nsf data - Remaining_Reader rem( &header, header.size, &sub ); - RETURN_ERR( nsf_emu->Nsf_Emu::load_( rem ) ); - check( rem.remain() == 0 ); - } - break; - } - - case BLARGG_4CHAR('D','N','E','N'): - check( phase == 2 ); - phase = 3; - break; - - default: - // tags that can be skipped start with a lowercase character - check( islower( (tag >> 24) & 0xFF ) ); - RETURN_ERR( in.skip( size ) ); - break; - } - } - - return blargg_ok; -} - -blargg_err_t Nsfe_Info::track_info_( track_info_t* out, int track ) const -{ - int remapped = remap_track( track ); - if ( (unsigned) remapped < track_times.size() ) - { - int length = (BOOST::int32_t) get_le32( track_times [remapped] ); - if ( length > 0 ) - out->length = length; - } - if ( (unsigned) remapped < track_names.size() ) - Gme_File::copy_field_( out->song, track_names [remapped] ); - - GME_COPY_FIELD( info, out, game ); - GME_COPY_FIELD( info, out, author ); - GME_COPY_FIELD( info, out, copyright ); - GME_COPY_FIELD( info, out, dumper ); - return blargg_ok; -} - -Nsfe_Emu::Nsfe_Emu() -{ - set_type( gme_nsfe_type ); -} - -Nsfe_Emu::~Nsfe_Emu() { } - -void Nsfe_Emu::unload() -{ - info.unload(); - Nsf_Emu::unload(); -} - -blargg_err_t Nsfe_Emu::track_info_( track_info_t* out, int track ) const -{ - return info.track_info_( out, track ); -} - -struct Nsfe_File : Gme_Info_ -{ - Nsfe_Info info; - - Nsfe_File() { set_type( gme_nsfe_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - RETURN_ERR( info.load( in, 0 ) ); - info.disable_playlist( false ); - set_track_count( info.info.track_count ); - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int track ) const - { - return info.track_info_( out, track ); - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_nsf_file( info.info, info.data.begin(), info.data.end() - info.data.begin(), out ); - return blargg_ok; - } -}; - -static Music_Emu* new_nsfe_emu () { return BLARGG_NEW Nsfe_Emu ; } -static Music_Emu* new_nsfe_file() { return BLARGG_NEW Nsfe_File; } - -gme_type_t_ const gme_nsfe_type [1] = {{ "Nintendo NES", 0, &new_nsfe_emu, &new_nsfe_file, "NSFE", 1 }}; - -blargg_err_t Nsfe_Emu::load_( Data_Reader& in ) -{ - RETURN_ERR( info.load( in, this ) ); - disable_playlist_( false ); - return blargg_ok; -} - -void Nsfe_Emu::disable_playlist_( bool b ) -{ - info.disable_playlist( b ); - set_track_count( info.info.track_count ); -} - -void Nsfe_Emu::clear_playlist_() -{ - disable_playlist_( true ); - Nsf_Emu::clear_playlist_(); -} - -blargg_err_t Nsfe_Emu::start_track_( int track ) -{ - return Nsf_Emu::start_track_( info.remap_track( track ) ); -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Nsfe_Emu.h" + +#include "blargg_endian.h" +#include + +/* Copyright (C) 2005-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Nsfe_Info::Nsfe_Info() { playlist_disabled = false; } + +Nsfe_Info::~Nsfe_Info() { } + +inline void Nsfe_Info::unload() +{ + data.clear(); + track_name_data.clear(); + track_names.clear(); + playlist.clear(); + track_times.clear(); +} + +// TODO: if no playlist, treat as if there is a playlist that is just 1,2,3,4,5... ? +void Nsfe_Info::disable_playlist( bool b ) +{ + playlist_disabled = b; + info.track_count = playlist.size(); + if ( !info.track_count || playlist_disabled ) + info.track_count = actual_track_count_; +} + +int Nsfe_Info::remap_track( int track ) const +{ + if ( !playlist_disabled && (unsigned) track < playlist.size() ) + track = playlist [track]; + return track; +} + +// Read multiple strings and separate into individual strings +static blargg_err_t read_strs( Data_Reader& in, int size, blargg_vector& chars, + blargg_vector& strs ) +{ + RETURN_ERR( chars.resize( size + 1 ) ); + chars [size] = 0; // in case last string doesn't have terminator + RETURN_ERR( in.read( &chars [0], size ) ); + + RETURN_ERR( strs.resize( 128 ) ); + int count = 0; + for ( int i = 0; i < size; i++ ) + { + if ( (int) strs.size() <= count ) + RETURN_ERR( strs.resize( count * 2 ) ); + strs [count++] = &chars [i]; + while ( i < size && chars [i] ) + i++; + } + + return strs.resize( count ); +} + +// Copy in to out, where out has out_max characters allocated. Truncate to +// out_max - 1 characters. +static void copy_str( const char in [], char out [], int out_max ) +{ + out [out_max - 1] = 0; + strncpy( out, in, out_max - 1 ); +} + +struct nsfe_info_t +{ + byte load_addr [2]; + byte init_addr [2]; + byte play_addr [2]; + byte speed_flags; + byte chip_flags; + byte track_count; + byte first_track; + byte unused [6]; +}; + +blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsfe_Emu* nsf_emu ) +{ + int const nsfe_info_size = 16; + assert( offsetof (nsfe_info_t,unused [6]) == nsfe_info_size ); + + // check header + byte signature [4]; + blargg_err_t err = in.read( signature, sizeof signature ); + if ( err ) + return (blargg_is_err_type( err, blargg_err_file_eof ) ? blargg_err_file_type : err); + if ( memcmp( signature, "NSFE", 4 ) ) + return blargg_err_file_type; + + // free previous info + track_name_data.clear(); + track_names.clear(); + playlist.clear(); + track_times.clear(); + + // default nsf header + static const Nsf_Emu::header_t base_header = + { + {'N','E','S','M','\x1A'},// tag + 1, // version + 1, 1, // track count, first track + {0,0},{0,0},{0,0}, // addresses + "","","", // strings + {0x1A, 0x41}, // NTSC rate + {0,0,0,0,0,0,0,0}, // banks + {0x20, 0x4E}, // PAL rate + 0, 0, // flags + {0,0,0,0} // unused + }; + Nsf_Emu::header_t& header = info; + header = base_header; + + // parse tags + int phase = 0; + while ( phase != 3 ) + { + // read size and tag + byte block_header [2] [4]; + RETURN_ERR( in.read( block_header, sizeof block_header ) ); + int size = get_le32( block_header [0] ); + int tag = get_le32( block_header [1] ); + + //dprintf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) ); + + switch ( tag ) + { + case BLARGG_4CHAR('O','F','N','I'): { + check( phase == 0 ); + if ( size < 8 ) + return blargg_err_file_corrupt; + + nsfe_info_t finfo; + finfo.track_count = 1; + finfo.first_track = 0; + + RETURN_ERR( in.read( &finfo, min( size, (int) nsfe_info_size ) ) ); + if ( size > nsfe_info_size ) + RETURN_ERR( in.skip( size - nsfe_info_size ) ); + phase = 1; + info.speed_flags = finfo.speed_flags; + info.chip_flags = finfo.chip_flags; + info.track_count = finfo.track_count; + this->actual_track_count_ = finfo.track_count; + info.first_track = finfo.first_track; + memcpy( info.load_addr, finfo.load_addr, 2 * 3 ); + break; + } + + case BLARGG_4CHAR('K','N','A','B'): + if ( size > (int) sizeof info.banks ) + return blargg_err_file_corrupt; + RETURN_ERR( in.read( info.banks, size ) ); + break; + + case BLARGG_4CHAR('h','t','u','a'): { + blargg_vector chars; + blargg_vector strs; + RETURN_ERR( read_strs( in, size, chars, strs ) ); + int n = strs.size(); + + if ( n > 3 ) + copy_str( strs [3], info.dumper, sizeof info.dumper ); + + if ( n > 2 ) + copy_str( strs [2], info.copyright, sizeof info.copyright ); + + if ( n > 1 ) + copy_str( strs [1], info.author, sizeof info.author ); + + if ( n > 0 ) + copy_str( strs [0], info.game, sizeof info.game ); + + break; + } + + case BLARGG_4CHAR('e','m','i','t'): + RETURN_ERR( track_times.resize( size / 4 ) ); + RETURN_ERR( in.read( track_times.begin(), track_times.size() * 4 ) ); + break; + + case BLARGG_4CHAR('l','b','l','t'): + RETURN_ERR( read_strs( in, size, track_name_data, track_names ) ); + break; + + case BLARGG_4CHAR('t','s','l','p'): + RETURN_ERR( playlist.resize( size ) ); + RETURN_ERR( in.read( &playlist [0], size ) ); + break; + + case BLARGG_4CHAR('A','T','A','D'): { + check( phase == 1 ); + phase = 2; + if ( !nsf_emu ) + { + RETURN_ERR( data.resize( size ) ); + RETURN_ERR( in.read( data.begin(), size ) ); + } + else + { + Subset_Reader sub( &in, size ); // limit emu to nsf data + Remaining_Reader rem( &header, header.size, &sub ); + RETURN_ERR( nsf_emu->Nsf_Emu::load_( rem ) ); + check( rem.remain() == 0 ); + } + break; + } + + case BLARGG_4CHAR('D','N','E','N'): + check( phase == 2 ); + phase = 3; + break; + + default: + // tags that can be skipped start with a lowercase character + check( islower( (tag >> 24) & 0xFF ) ); + RETURN_ERR( in.skip( size ) ); + break; + } + } + + return blargg_ok; +} + +blargg_err_t Nsfe_Info::track_info_( track_info_t* out, int track ) const +{ + int remapped = remap_track( track ); + if ( (unsigned) remapped < track_times.size() ) + { + int length = (BOOST::int32_t) get_le32( track_times [remapped] ); + if ( length > 0 ) + out->length = length; + } + if ( (unsigned) remapped < track_names.size() ) + Gme_File::copy_field_( out->song, track_names [remapped] ); + + GME_COPY_FIELD( info, out, game ); + GME_COPY_FIELD( info, out, author ); + GME_COPY_FIELD( info, out, copyright ); + GME_COPY_FIELD( info, out, dumper ); + return blargg_ok; +} + +Nsfe_Emu::Nsfe_Emu() +{ + set_type( gme_nsfe_type ); +} + +Nsfe_Emu::~Nsfe_Emu() { } + +void Nsfe_Emu::unload() +{ + info.unload(); + Nsf_Emu::unload(); +} + +blargg_err_t Nsfe_Emu::track_info_( track_info_t* out, int track ) const +{ + return info.track_info_( out, track ); +} + +struct Nsfe_File : Gme_Info_ +{ + Nsfe_Info info; + + Nsfe_File() { set_type( gme_nsfe_type ); } + + blargg_err_t load_( Data_Reader& in ) + { + RETURN_ERR( info.load( in, 0 ) ); + info.disable_playlist( false ); + set_track_count( info.info.track_count ); + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int track ) const + { + return info.track_info_( out, track ); + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_nsf_file( info.info, info.data.begin(), info.data.end() - info.data.begin(), out ); + return blargg_ok; + } +}; + +static Music_Emu* new_nsfe_emu () { return BLARGG_NEW Nsfe_Emu ; } +static Music_Emu* new_nsfe_file() { return BLARGG_NEW Nsfe_File; } + +gme_type_t_ const gme_nsfe_type [1] = {{ "Nintendo NES", 0, &new_nsfe_emu, &new_nsfe_file, "NSFE", 1 }}; + +blargg_err_t Nsfe_Emu::load_( Data_Reader& in ) +{ + RETURN_ERR( info.load( in, this ) ); + disable_playlist_( false ); + return blargg_ok; +} + +void Nsfe_Emu::disable_playlist_( bool b ) +{ + info.disable_playlist( b ); + set_track_count( info.info.track_count ); +} + +void Nsfe_Emu::clear_playlist_() +{ + disable_playlist_( true ); + Nsf_Emu::clear_playlist_(); +} + +blargg_err_t Nsfe_Emu::start_track_( int track ) +{ + return Nsf_Emu::start_track_( info.remap_track( track ) ); +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nsf_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nsf_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Nsf_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Nsf_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,26 +1,26 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Nsf_Emu.h" - -#if !NSF_EMU_APU_ONLY - #include "Nes_Namco_Apu.h" - #include "Nes_Vrc6_Apu.h" - #include "Nes_Fme7_Apu.h" - #include "Nes_Fds_Apu.h" - #include "Nes_Mmc5_Apu.h" - #include "Nes_Vrc7_Apu.h" -#endif - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Nsf_Emu.h" + +#if !NSF_EMU_APU_ONLY + #include "Nes_Namco_Apu.h" + #include "Nes_Vrc6_Apu.h" + #include "Nes_Fme7_Apu.h" + #include "Nes_Fds_Apu.h" + #include "Nes_Mmc5_Apu.h" + #include "Nes_Vrc7_Apu.h" +#endif + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "blargg_source.h" @@ -29,314 +29,314 @@ Nsf_Emu::Nsf_Emu() { - set_type( gme_nsf_type ); - set_silence_lookahead( 6 ); - set_gain( 1.4 ); - set_equalizer( nes_eq ); -} - -Nsf_Emu::~Nsf_Emu() -{ - unload(); -} - -void Nsf_Emu::unload() -{ - core_.unload(); - Music_Emu::unload(); -} - -// Track info - -static void copy_nsf_fields( Nsf_Emu::header_t const& h, track_info_t* out ) -{ - GME_COPY_FIELD( h, out, game ); - GME_COPY_FIELD( h, out, author ); - GME_COPY_FIELD( h, out, copyright ); - if ( h.chip_flags ) - Music_Emu::copy_field_( out->system, "Famicom" ); -} - -void hash_nsf_file( Nsf_Core::header_t const& h, unsigned char const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( &h.vers, sizeof(h.vers) ); - out.hash_( &h.track_count, sizeof(h.track_count) ); - out.hash_( &h.first_track, sizeof(h.first_track) ); - out.hash_( &h.load_addr[0], sizeof(h.load_addr) ); - out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); - out.hash_( &h.play_addr[0], sizeof(h.play_addr) ); - out.hash_( &h.ntsc_speed[0], sizeof(h.ntsc_speed) ); - out.hash_( &h.banks[0], sizeof(h.banks) ); - out.hash_( &h.pal_speed[0], sizeof(h.pal_speed) ); - out.hash_( &h.speed_flags, sizeof(h.speed_flags) ); - out.hash_( &h.chip_flags, sizeof(h.chip_flags) ); - out.hash_( &h.unused[0], sizeof(h.unused) ); - - out.hash_( data, data_size ); -} - -blargg_err_t Nsf_Emu::track_info_( track_info_t* out, int ) const -{ - copy_nsf_fields( header(), out ); - return blargg_ok; -} - -static blargg_err_t check_nsf_header( Nsf_Emu::header_t const& h ) -{ - if ( !h.valid_tag() ) - return blargg_err_file_type; - return blargg_ok; -} - -struct Nsf_File : Gme_Info_ -{ - Nsf_Emu::header_t const* h; - - Nsf_File() { set_type( gme_nsf_type ); } - - blargg_err_t load_mem_( byte const begin [], int size ) - { - h = ( Nsf_Emu::header_t const* ) begin; - - if ( h->vers != 1 ) - set_warning( "Unknown file version" ); - - int unsupported_chips = ~Nsf_Core::chips_mask; - #if NSF_EMU_NO_VRC7 - unsupported_chips |= Nsf_Emu::header_t::vrc7_mask; - #endif - if ( h->chip_flags & unsupported_chips ) - set_warning( "Uses unsupported audio expansion hardware" ); - - set_track_count( h->track_count ); - return check_nsf_header( *h ); - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_nsf_fields( *h, out ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_nsf_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out ); - return blargg_ok; - } -}; - -static Music_Emu* new_nsf_emu () { return BLARGG_NEW Nsf_Emu ; } -static Music_Emu* new_nsf_file() { return BLARGG_NEW Nsf_File; } - -gme_type_t_ const gme_nsf_type [1] = {{ "Nintendo NES", 0, &new_nsf_emu, &new_nsf_file, "NSF", 1 }}; - -// Setup - -void Nsf_Emu::set_tempo_( double t ) -{ - core_.set_tempo( t ); -} - -void Nsf_Emu::append_voices( const char* const names [], int const types [], int count ) -{ - assert( voice_count_ + count < max_voices ); - for ( int i = 0; i < count; i++ ) - { - voice_names_ [voice_count_ + i] = names [i]; - voice_types_ [voice_count_ + i] = types [i]; - } - voice_count_ += count; - set_voice_count( voice_count_ ); - set_voice_types( voice_types_ ); -} - -blargg_err_t Nsf_Emu::init_sound() -{ - voice_count_ = 0; - set_voice_names( voice_names_ ); - - { - int const count = Nes_Apu::osc_count; - static const char* const names [Nes_Apu::osc_count] = { - "Square 1", "Square 2", "Triangle", "Noise", "DMC" - }; - static int const types [count] = { - wave_type+1, wave_type+2, mixed_type+1, noise_type+0, mixed_type+1 - }; - append_voices( names, types, count ); - } - - // Make adjusted_gain * 0.75 = 1.0 so usual APU and one sound chip uses 1.0 - double adjusted_gain = 1.0 / 0.75 * gain(); - -#if !NSF_EMU_APU_ONLY - // TODO: order of chips here must match that in set_voice() - - if ( core_.vrc6_apu() ) - { - int const count = Nes_Vrc6_Apu::osc_count; - static const char* const names [count] = { - "Square 3", "Square 4", "Saw Wave" - }; - static int const types [count] = { - wave_type+3, wave_type+4, wave_type+5, - }; - append_voices( names, types, count ); - adjusted_gain *= 0.75; - } - - if ( core_.fme7_apu() ) - { - int const count = Nes_Fme7_Apu::osc_count; - static const char* const names [count] = { - "Square 3", "Square 4", "Square 5" - }; - static int const types [count] = { - wave_type+3, wave_type+4, wave_type+5, - }; - append_voices( names, types, count ); - adjusted_gain *= 0.75; - } - - if ( core_.mmc5_apu() ) - { - int const count = Nes_Mmc5_Apu::osc_count; - static const char* const names [count] = { - "Square 3", "Square 4", "PCM" - }; - static int const types [count] = { - wave_type+3, wave_type+4, mixed_type+2 - }; - append_voices( names, types, count ); - adjusted_gain *= 0.75; - } - - if ( core_.fds_apu() ) - { - int const count = Nes_Fds_Apu::osc_count; - static const char* const names [count] = { - "FM" - }; - static int const types [count] = { - wave_type+0 - }; - append_voices( names, types, count ); - adjusted_gain *= 0.75; - } - - if ( core_.namco_apu() ) - { - int const count = Nes_Namco_Apu::osc_count; - static const char* const names [count] = { - "Wave 1", "Wave 2", "Wave 3", "Wave 4", - "Wave 5", "Wave 6", "Wave 7", "Wave 8" - }; - static int const types [count] = { - wave_type+3, wave_type+4, wave_type+5, wave_type+ 6, - wave_type+7, wave_type+8, wave_type+9, wave_type+10, - }; - append_voices( names, types, count ); - adjusted_gain *= 0.75; - } - - if ( core_.vrc7_apu() ) - { - int const count = Nes_Vrc7_Apu::osc_count; - static const char* const names [count] = { - "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6" - }; - static int const types [count] = { - wave_type+3, wave_type+4, wave_type+5, wave_type+6, - wave_type+7, wave_type+8 - }; - append_voices( names, types, count ); - adjusted_gain *= 0.75; - } - - if ( core_.vrc7_apu() ) core_.vrc7_apu() ->volume( adjusted_gain ); - if ( core_.namco_apu() ) core_.namco_apu()->volume( adjusted_gain ); - if ( core_.vrc6_apu() ) core_.vrc6_apu() ->volume( adjusted_gain ); - if ( core_.fme7_apu() ) core_.fme7_apu() ->volume( adjusted_gain ); - if ( core_.mmc5_apu() ) core_.mmc5_apu() ->volume( adjusted_gain ); - if ( core_.fds_apu() ) core_.fds_apu() ->volume( adjusted_gain ); -#endif - - if ( adjusted_gain > gain() ) - adjusted_gain = gain(); // only occurs if no other sound chips - - core_.nes_apu()->volume( adjusted_gain ); - - return blargg_ok; -} - -blargg_err_t Nsf_Emu::load_( Data_Reader& in ) -{ - RETURN_ERR( core_.load( in ) ); - set_track_count( header().track_count ); - RETURN_ERR( check_nsf_header( header() ) ); - set_warning( core_.warning() ); - RETURN_ERR( init_sound() ); - set_tempo( tempo() ); - return setup_buffer( (int) (header().clock_rate() + 0.5) ); -} - -void Nsf_Emu::update_eq( blip_eq_t const& eq ) -{ - core_.nes_apu()->treble_eq( eq ); - - #if !NSF_EMU_APU_ONLY - { - if ( core_.namco_apu() ) core_.namco_apu()->treble_eq( eq ); - if ( core_.vrc6_apu() ) core_.vrc6_apu() ->treble_eq( eq ); - if ( core_.fme7_apu() ) core_.fme7_apu() ->treble_eq( eq ); - if ( core_.mmc5_apu() ) core_.mmc5_apu() ->treble_eq( eq ); - if ( core_.fds_apu() ) core_.fds_apu() ->treble_eq( eq ); - if ( core_.vrc7_apu() ) core_.vrc7_apu() ->treble_eq( eq ); - } - #endif -} - -void Nsf_Emu::set_voice( int i, Blip_Buffer* buf, Blip_Buffer*, Blip_Buffer* ) -{ - #define HANDLE_CHIP( chip ) \ - if ( chip && (i -= chip->osc_count) < 0 )\ - {\ - chip->set_output( i + chip->osc_count, buf );\ - return;\ - }\ - - HANDLE_CHIP( core_.nes_apu() ); - - #if !NSF_EMU_APU_ONLY - { - // TODO: order of chips here must match that in init_sound() - HANDLE_CHIP( core_.vrc6_apu() ); - HANDLE_CHIP( core_.fme7_apu() ); - HANDLE_CHIP( core_.mmc5_apu() ); - HANDLE_CHIP( core_.fds_apu() ); - HANDLE_CHIP( core_.namco_apu() ); - HANDLE_CHIP( core_.vrc7_apu() ); - } - #endif -} - -blargg_err_t Nsf_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - return core_.start_track( track ); -} - -blargg_err_t Nsf_Emu::run_clocks( blip_time_t& duration, int ) -{ - core_.end_frame( duration ); - const char* w = core_.warning(); - if ( w ) - set_warning( w ); - return blargg_ok; -} - -blargg_err_t Nsf_Emu::hash_( Hash_Function& out ) const -{ - hash_nsf_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out ); - return blargg_ok; + set_type( gme_nsf_type ); + set_silence_lookahead( 6 ); + set_gain( 1.4 ); + set_equalizer( nes_eq ); +} + +Nsf_Emu::~Nsf_Emu() +{ + unload(); +} + +void Nsf_Emu::unload() +{ + core_.unload(); + Music_Emu::unload(); +} + +// Track info + +static void copy_nsf_fields( Nsf_Emu::header_t const& h, track_info_t* out ) +{ + GME_COPY_FIELD( h, out, game ); + GME_COPY_FIELD( h, out, author ); + GME_COPY_FIELD( h, out, copyright ); + if ( h.chip_flags ) + Music_Emu::copy_field_( out->system, "Famicom" ); +} + +void hash_nsf_file( Nsf_Core::header_t const& h, unsigned char const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( &h.vers, sizeof(h.vers) ); + out.hash_( &h.track_count, sizeof(h.track_count) ); + out.hash_( &h.first_track, sizeof(h.first_track) ); + out.hash_( &h.load_addr[0], sizeof(h.load_addr) ); + out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); + out.hash_( &h.play_addr[0], sizeof(h.play_addr) ); + out.hash_( &h.ntsc_speed[0], sizeof(h.ntsc_speed) ); + out.hash_( &h.banks[0], sizeof(h.banks) ); + out.hash_( &h.pal_speed[0], sizeof(h.pal_speed) ); + out.hash_( &h.speed_flags, sizeof(h.speed_flags) ); + out.hash_( &h.chip_flags, sizeof(h.chip_flags) ); + out.hash_( &h.unused[0], sizeof(h.unused) ); + + out.hash_( data, data_size ); +} + +blargg_err_t Nsf_Emu::track_info_( track_info_t* out, int ) const +{ + copy_nsf_fields( header(), out ); + return blargg_ok; +} + +static blargg_err_t check_nsf_header( Nsf_Emu::header_t const& h ) +{ + if ( !h.valid_tag() ) + return blargg_err_file_type; + return blargg_ok; +} + +struct Nsf_File : Gme_Info_ +{ + Nsf_Emu::header_t const* h; + + Nsf_File() { set_type( gme_nsf_type ); } + + blargg_err_t load_mem_( byte const begin [], int size ) + { + h = ( Nsf_Emu::header_t const* ) begin; + + if ( h->vers != 1 ) + set_warning( "Unknown file version" ); + + int unsupported_chips = ~Nsf_Core::chips_mask; + #if NSF_EMU_NO_VRC7 + unsupported_chips |= Nsf_Emu::header_t::vrc7_mask; + #endif + if ( h->chip_flags & unsupported_chips ) + set_warning( "Uses unsupported audio expansion hardware" ); + + set_track_count( h->track_count ); + return check_nsf_header( *h ); + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + copy_nsf_fields( *h, out ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_nsf_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out ); + return blargg_ok; + } +}; + +static Music_Emu* new_nsf_emu () { return BLARGG_NEW Nsf_Emu ; } +static Music_Emu* new_nsf_file() { return BLARGG_NEW Nsf_File; } + +gme_type_t_ const gme_nsf_type [1] = {{ "Nintendo NES", 0, &new_nsf_emu, &new_nsf_file, "NSF", 1 }}; + +// Setup + +void Nsf_Emu::set_tempo_( double t ) +{ + core_.set_tempo( t ); +} + +void Nsf_Emu::append_voices( const char* const names [], int const types [], int count ) +{ + assert( voice_count_ + count < max_voices ); + for ( int i = 0; i < count; i++ ) + { + voice_names_ [voice_count_ + i] = names [i]; + voice_types_ [voice_count_ + i] = types [i]; + } + voice_count_ += count; + set_voice_count( voice_count_ ); + set_voice_types( voice_types_ ); +} + +blargg_err_t Nsf_Emu::init_sound() +{ + voice_count_ = 0; + set_voice_names( voice_names_ ); + + { + int const count = Nes_Apu::osc_count; + static const char* const names [Nes_Apu::osc_count] = { + "Square 1", "Square 2", "Triangle", "Noise", "DMC" + }; + static int const types [count] = { + wave_type+1, wave_type+2, mixed_type+1, noise_type+0, mixed_type+1 + }; + append_voices( names, types, count ); + } + + // Make adjusted_gain * 0.75 = 1.0 so usual APU and one sound chip uses 1.0 + double adjusted_gain = 1.0 / 0.75 * gain(); + +#if !NSF_EMU_APU_ONLY + // TODO: order of chips here must match that in set_voice() + + if ( core_.vrc6_apu() ) + { + int const count = Nes_Vrc6_Apu::osc_count; + static const char* const names [count] = { + "Square 3", "Square 4", "Saw Wave" + }; + static int const types [count] = { + wave_type+3, wave_type+4, wave_type+5, + }; + append_voices( names, types, count ); + adjusted_gain *= 0.75; + } + + if ( core_.fme7_apu() ) + { + int const count = Nes_Fme7_Apu::osc_count; + static const char* const names [count] = { + "Square 3", "Square 4", "Square 5" + }; + static int const types [count] = { + wave_type+3, wave_type+4, wave_type+5, + }; + append_voices( names, types, count ); + adjusted_gain *= 0.75; + } + + if ( core_.mmc5_apu() ) + { + int const count = Nes_Mmc5_Apu::osc_count; + static const char* const names [count] = { + "Square 3", "Square 4", "PCM" + }; + static int const types [count] = { + wave_type+3, wave_type+4, mixed_type+2 + }; + append_voices( names, types, count ); + adjusted_gain *= 0.75; + } + + if ( core_.fds_apu() ) + { + int const count = Nes_Fds_Apu::osc_count; + static const char* const names [count] = { + "FM" + }; + static int const types [count] = { + wave_type+0 + }; + append_voices( names, types, count ); + adjusted_gain *= 0.75; + } + + if ( core_.namco_apu() ) + { + int const count = Nes_Namco_Apu::osc_count; + static const char* const names [count] = { + "Wave 1", "Wave 2", "Wave 3", "Wave 4", + "Wave 5", "Wave 6", "Wave 7", "Wave 8" + }; + static int const types [count] = { + wave_type+3, wave_type+4, wave_type+5, wave_type+ 6, + wave_type+7, wave_type+8, wave_type+9, wave_type+10, + }; + append_voices( names, types, count ); + adjusted_gain *= 0.75; + } + + if ( core_.vrc7_apu() ) + { + int const count = Nes_Vrc7_Apu::osc_count; + static const char* const names [count] = { + "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6" + }; + static int const types [count] = { + wave_type+3, wave_type+4, wave_type+5, wave_type+6, + wave_type+7, wave_type+8 + }; + append_voices( names, types, count ); + adjusted_gain *= 0.75; + } + + if ( core_.vrc7_apu() ) core_.vrc7_apu() ->volume( adjusted_gain ); + if ( core_.namco_apu() ) core_.namco_apu()->volume( adjusted_gain ); + if ( core_.vrc6_apu() ) core_.vrc6_apu() ->volume( adjusted_gain ); + if ( core_.fme7_apu() ) core_.fme7_apu() ->volume( adjusted_gain ); + if ( core_.mmc5_apu() ) core_.mmc5_apu() ->volume( adjusted_gain ); + if ( core_.fds_apu() ) core_.fds_apu() ->volume( adjusted_gain ); +#endif + + if ( adjusted_gain > gain() ) + adjusted_gain = gain(); // only occurs if no other sound chips + + core_.nes_apu()->volume( adjusted_gain ); + + return blargg_ok; +} + +blargg_err_t Nsf_Emu::load_( Data_Reader& in ) +{ + RETURN_ERR( core_.load( in ) ); + set_track_count( header().track_count ); + RETURN_ERR( check_nsf_header( header() ) ); + set_warning( core_.warning() ); + RETURN_ERR( init_sound() ); + set_tempo( tempo() ); + return setup_buffer( (int) (header().clock_rate() + 0.5) ); +} + +void Nsf_Emu::update_eq( blip_eq_t const& eq ) +{ + core_.nes_apu()->treble_eq( eq ); + + #if !NSF_EMU_APU_ONLY + { + if ( core_.namco_apu() ) core_.namco_apu()->treble_eq( eq ); + if ( core_.vrc6_apu() ) core_.vrc6_apu() ->treble_eq( eq ); + if ( core_.fme7_apu() ) core_.fme7_apu() ->treble_eq( eq ); + if ( core_.mmc5_apu() ) core_.mmc5_apu() ->treble_eq( eq ); + if ( core_.fds_apu() ) core_.fds_apu() ->treble_eq( eq ); + if ( core_.vrc7_apu() ) core_.vrc7_apu() ->treble_eq( eq ); + } + #endif +} + +void Nsf_Emu::set_voice( int i, Blip_Buffer* buf, Blip_Buffer*, Blip_Buffer* ) +{ + #define HANDLE_CHIP( chip ) \ + if ( chip && (i -= chip->osc_count) < 0 )\ + {\ + chip->set_output( i + chip->osc_count, buf );\ + return;\ + }\ + + HANDLE_CHIP( core_.nes_apu() ); + + #if !NSF_EMU_APU_ONLY + { + // TODO: order of chips here must match that in init_sound() + HANDLE_CHIP( core_.vrc6_apu() ); + HANDLE_CHIP( core_.fme7_apu() ); + HANDLE_CHIP( core_.mmc5_apu() ); + HANDLE_CHIP( core_.fds_apu() ); + HANDLE_CHIP( core_.namco_apu() ); + HANDLE_CHIP( core_.vrc7_apu() ); + } + #endif +} + +blargg_err_t Nsf_Emu::start_track_( int track ) +{ + RETURN_ERR( Classic_Emu::start_track_( track ) ); + return core_.start_track( track ); +} + +blargg_err_t Nsf_Emu::run_clocks( blip_time_t& duration, int ) +{ + core_.end_frame( duration ); + const char* w = core_.warning(); + if ( w ) + set_warning( w ); + return blargg_ok; +} + +blargg_err_t Nsf_Emu::hash_( Hash_Function& out ) const +{ + hash_nsf_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out ); + return blargg_ok; } \ No newline at end of file diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Opl_Apu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Opl_Apu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Opl_Apu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Opl_Apu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,242 +1,242 @@ -#include "Opl_Apu.h" - -#include "blargg_source.h" - -#include "ym2413.h" -#include "fmopl.h" - -Opl_Apu::Opl_Apu() { opl = 0; opl_memory = 0; } - -blargg_err_t Opl_Apu::init( long clock, long rate, blip_time_t period, type_t type ) -{ - type_ = type; - clock_ = clock; - rate_ = rate; - period_ = period; - set_output( 0, 0 ); - volume( 1.0 ); - switch (type) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - opl = ym2413_init( clock, rate, 0 ); - break; - - case type_vrc7: - opl = ym2413_init( clock, rate, 1 ); - break; - - case type_opl: - opl = ym3526_init( clock, rate ); - break; - - case type_msxaudio: - //logfile = fopen("c:\\temp\\msxaudio.log", "wb"); - opl = y8950_init( clock, rate ); - opl_memory = malloc( 32768 ); - y8950_set_delta_t_memory( opl, opl_memory, 32768 ); - break; - - case type_opl2: - opl = ym3812_init( clock, rate ); - break; - } - reset(); - return 0; -} - -Opl_Apu::~Opl_Apu() -{ - if (opl) - { - switch (type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - ym2413_shutdown( opl ); - break; - - case type_opl: - ym3526_shutdown( opl ); - break; - - case type_msxaudio: - y8950_shutdown( opl ); - free( opl_memory ); - //fclose( logfile ); - break; - - case type_opl2: - ym3812_shutdown( opl ); - break; - } - } -} - -void Opl_Apu::reset() -{ - addr = 0; - next_time = 0; - last_amp = 0; - - switch (type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - ym2413_reset_chip( opl ); - break; - - case type_opl: - ym3526_reset_chip( opl ); - break; - - case type_msxaudio: - y8950_reset_chip( opl ); - break; - - case type_opl2: - ym3812_reset_chip( opl ); - break; - } -} - -void Opl_Apu::write_data( blip_time_t time, int data ) -{ - run_until( time ); - switch (type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - ym2413_write( opl, 0, addr ); - ym2413_write( opl, 1, data ); - break; - - case type_opl: - ym3526_write( opl, 0, addr ); - ym3526_write( opl, 1, data ); - break; - - case type_msxaudio: - /*if ( addr >= 7 && addr <= 7 + 11 ) - { - unsigned char temp [2] = { addr - 7, data }; - fwrite( &temp, 1, 2, logfile ); - }*/ - y8950_write( opl, 0, addr ); - y8950_write( opl, 1, data ); - break; - - case type_opl2: - ym3812_write( opl, 0, addr ); - ym3812_write( opl, 1, data ); - break; - } -} - -int Opl_Apu::read( blip_time_t time, int port ) -{ - run_until( time ); - switch (type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - return ym2413_read( opl, port ); - - case type_opl: - return ym3526_read( opl, port ); - - case type_msxaudio: - { - int ret = y8950_read( opl, port ); - /*unsigned char temp [2] = { port + 0x80, ret }; - fwrite( &temp, 1, 2, logfile );*/ - return ret; - } - - case type_opl2: - return ym3812_read( opl, port ); - } - - return 0; -} - -void Opl_Apu::end_frame( blip_time_t time ) -{ - run_until( time ); - next_time -= time; - - if ( output_ ) - output_->set_modified(); -} - -void Opl_Apu::run_until( blip_time_t end_time ) -{ - if ( end_time > next_time ) - { - blip_time_t time_delta = end_time - next_time; - blip_time_t time = next_time; - unsigned count = time_delta / period_ + 1; - switch (type_) - { - case type_opll: - case type_msxmusic: - case type_smsfmunit: - case type_vrc7: - { - SAMP bufMO[ 1024 ]; - SAMP bufRO[ 1024 ]; - SAMP * buffers[2] = { bufMO, bufRO }; - - while ( count > 0 ) - { - unsigned todo = count; - if ( todo > 1024 ) todo = 1024; - ym2413_update_one( opl, buffers, todo ); - - if ( output_ ) - { - int last_amp = this->last_amp; - for ( unsigned i = 0; i < todo; i++ ) - { - int amp = bufMO [i] + bufRO [i]; - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth.offset_inline( time, delta, output_ ); - } - time += period_; - } - this->last_amp = last_amp; - } - else time += period_ * todo; - - count -= todo; - } - } - break; - - case type_opl: - case type_msxaudio: - case type_opl2: - { - OPLSAMPLE buffer[ 1024 ]; - - while ( count > 0 ) - { - unsigned todo = count; - if ( todo > 1024 ) todo = 1024; - switch (type_) - { +#include "Opl_Apu.h" + +#include "blargg_source.h" + +#include "ym2413.h" +#include "fmopl.h" + +Opl_Apu::Opl_Apu() { opl = 0; opl_memory = 0; } + +blargg_err_t Opl_Apu::init( long clock, long rate, blip_time_t period, type_t type ) +{ + type_ = type; + clock_ = clock; + rate_ = rate; + period_ = period; + set_output( 0, 0 ); + volume( 1.0 ); + switch (type) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + opl = ym2413_init( clock, rate, 0 ); + break; + + case type_vrc7: + opl = ym2413_init( clock, rate, 1 ); + break; + + case type_opl: + opl = ym3526_init( clock, rate ); + break; + + case type_msxaudio: + //logfile = fopen("c:\\temp\\msxaudio.log", "wb"); + opl = y8950_init( clock, rate ); + opl_memory = malloc( 32768 ); + y8950_set_delta_t_memory( opl, opl_memory, 32768 ); + break; + + case type_opl2: + opl = ym3812_init( clock, rate ); + break; + } + reset(); + return 0; +} + +Opl_Apu::~Opl_Apu() +{ + if (opl) + { + switch (type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + ym2413_shutdown( opl ); + break; + + case type_opl: + ym3526_shutdown( opl ); + break; + + case type_msxaudio: + y8950_shutdown( opl ); + free( opl_memory ); + //fclose( logfile ); + break; + + case type_opl2: + ym3812_shutdown( opl ); + break; + } + } +} + +void Opl_Apu::reset() +{ + addr = 0; + next_time = 0; + last_amp = 0; + + switch (type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + ym2413_reset_chip( opl ); + break; + + case type_opl: + ym3526_reset_chip( opl ); + break; + + case type_msxaudio: + y8950_reset_chip( opl ); + break; + + case type_opl2: + ym3812_reset_chip( opl ); + break; + } +} + +void Opl_Apu::write_data( blip_time_t time, int data ) +{ + run_until( time ); + switch (type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + ym2413_write( opl, 0, addr ); + ym2413_write( opl, 1, data ); + break; + + case type_opl: + ym3526_write( opl, 0, addr ); + ym3526_write( opl, 1, data ); + break; + + case type_msxaudio: + /*if ( addr >= 7 && addr <= 7 + 11 ) + { + unsigned char temp [2] = { addr - 7, data }; + fwrite( &temp, 1, 2, logfile ); + }*/ + y8950_write( opl, 0, addr ); + y8950_write( opl, 1, data ); + break; + + case type_opl2: + ym3812_write( opl, 0, addr ); + ym3812_write( opl, 1, data ); + break; + } +} + +int Opl_Apu::read( blip_time_t time, int port ) +{ + run_until( time ); + switch (type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + return ym2413_read( opl, port ); + + case type_opl: + return ym3526_read( opl, port ); + + case type_msxaudio: + { + int ret = y8950_read( opl, port ); + /*unsigned char temp [2] = { port + 0x80, ret }; + fwrite( &temp, 1, 2, logfile );*/ + return ret; + } + + case type_opl2: + return ym3812_read( opl, port ); + } + + return 0; +} + +void Opl_Apu::end_frame( blip_time_t time ) +{ + run_until( time ); + next_time -= time; + + if ( output_ ) + output_->set_modified(); +} + +void Opl_Apu::run_until( blip_time_t end_time ) +{ + if ( end_time > next_time ) + { + blip_time_t time_delta = end_time - next_time; + blip_time_t time = next_time; + unsigned count = time_delta / period_ + 1; + switch (type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + { + SAMP bufMO[ 1024 ]; + SAMP bufRO[ 1024 ]; + SAMP * buffers[2] = { bufMO, bufRO }; + + while ( count > 0 ) + { + unsigned todo = count; + if ( todo > 1024 ) todo = 1024; + ym2413_update_one( opl, buffers, todo ); + + if ( output_ ) + { + int last_amp = this->last_amp; + for ( unsigned i = 0; i < todo; i++ ) + { + int amp = bufMO [i] + bufRO [i]; + int delta = amp - last_amp; + if ( delta ) + { + last_amp = amp; + synth.offset_inline( time, delta, output_ ); + } + time += period_; + } + this->last_amp = last_amp; + } + else time += period_ * todo; + + count -= todo; + } + } + break; + + case type_opl: + case type_msxaudio: + case type_opl2: + { + OPLSAMPLE buffer[ 1024 ]; + + while ( count > 0 ) + { + unsigned todo = count; + if ( todo > 1024 ) todo = 1024; + switch (type_) + { case type_opl: ym3526_update_one( opl, buffer, todo ); break; case type_msxaudio: y8950_update_one( opl, buffer, todo ); break; case type_opl2: ym3812_update_one( opl, buffer, todo ); break; @@ -244,28 +244,28 @@ } if ( output_ ) - { - int last_amp = this->last_amp; - for ( unsigned i = 0; i < todo; i++ ) - { - int amp = buffer [i]; - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth.offset_inline( time, delta, output_ ); - } - time += period_; - } - this->last_amp = last_amp; - } - else time += period_ * todo; - - count -= todo; - } - } - break; - } - next_time = time; - } + { + int last_amp = this->last_amp; + for ( unsigned i = 0; i < todo; i++ ) + { + int amp = buffer [i]; + int delta = amp - last_amp; + if ( delta ) + { + last_amp = amp; + synth.offset_inline( time, delta, output_ ); + } + time += period_; + } + this->last_amp = last_amp; + } + else time += period_ * todo; + + count -= todo; + } + } + break; + } + next_time = time; + } } \ No newline at end of file diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Opl_Apu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Opl_Apu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Opl_Apu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Opl_Apu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,63 +1,63 @@ -#ifndef OPL_APU_H -#define OPL_APU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -#include - -class Opl_Apu { -public: - Opl_Apu(); - ~Opl_Apu(); - - enum type_t { type_opll = 0x10, type_msxmusic = 0x11, type_smsfmunit = 0x12, - type_vrc7 = 0x13, type_opl = 0x20, type_msxaudio = 0x21, type_opl2 = 0x22 }; - blargg_err_t init( long clock, long rate, blip_time_t period, type_t ); - - void reset(); - void volume( double v ) { synth.volume( 1.0 / (4096 * 6) * v ); } - void treble_eq( blip_eq_t const& eq ) { synth.treble_eq( eq ); } - enum { osc_count = 1 }; - void osc_output( int index, Blip_Buffer* ); - void set_output( int i, Blip_Buffer* buf, Blip_Buffer* = NULL, Blip_Buffer* = NULL ) { osc_output( 0, buf ); } - void end_frame( blip_time_t ); - - void write_addr( int data ) { addr = data; } - void write_data( blip_time_t, int data ); - - int read( blip_time_t, int port ); - - static bool supported() { return true; } - -private: - // noncopyable - Opl_Apu( const Opl_Apu& ); - Opl_Apu& operator = ( const Opl_Apu& ); - - Blip_Buffer* output_; - type_t type_; - void* opl; - void* opl_memory; - //FILE* logfile; - unsigned char regs[ 0x100 ]; - blip_time_t next_time; - int last_amp; - int addr; - - long clock_; - long rate_; - blip_time_t period_; - - Blip_Synth_Fast synth; - - void run_until( blip_time_t ); -}; - -inline void Opl_Apu::osc_output( int i, Blip_Buffer* buf ) -{ - assert( (unsigned) i < osc_count ); - output_ = buf; -} - -#endif +#ifndef OPL_APU_H +#define OPL_APU_H + +#include "blargg_common.h" +#include "Blip_Buffer.h" + +#include + +class Opl_Apu { +public: + Opl_Apu(); + ~Opl_Apu(); + + enum type_t { type_opll = 0x10, type_msxmusic = 0x11, type_smsfmunit = 0x12, + type_vrc7 = 0x13, type_opl = 0x20, type_msxaudio = 0x21, type_opl2 = 0x22 }; + blargg_err_t init( long clock, long rate, blip_time_t period, type_t ); + + void reset(); + void volume( double v ) { synth.volume( 1.0 / (4096 * 6) * v ); } + void treble_eq( blip_eq_t const& eq ) { synth.treble_eq( eq ); } + enum { osc_count = 1 }; + void osc_output( int index, Blip_Buffer* ); + void set_output( int i, Blip_Buffer* buf, Blip_Buffer* = NULL, Blip_Buffer* = NULL ) { osc_output( 0, buf ); } + void end_frame( blip_time_t ); + + void write_addr( int data ) { addr = data; } + void write_data( blip_time_t, int data ); + + int read( blip_time_t, int port ); + + static bool supported() { return true; } + +private: + // noncopyable + Opl_Apu( const Opl_Apu& ); + Opl_Apu& operator = ( const Opl_Apu& ); + + Blip_Buffer* output_; + type_t type_; + void* opl; + void* opl_memory; + //FILE* logfile; + unsigned char regs[ 0x100 ]; + blip_time_t next_time; + int last_amp; + int addr; + + long clock_; + long rate_; + blip_time_t period_; + + Blip_Synth_Fast synth; + + void run_until( blip_time_t ); +}; + +inline void Opl_Apu::osc_output( int i, Blip_Buffer* buf ) +{ + assert( (unsigned) i < osc_count ); + output_ = buf; +} + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/pwm.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/pwm.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/pwm.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/pwm.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,27 +1,27 @@ -/*************************************************************************** - * Gens: PWM audio emulator. * - * * - * Copyright (c) 1999-2002 by Stphane Dallongeville * - * Copyright (c) 2003-2004 by Stphane Akhoun * - * Copyright (c) 2008-2009 by David Korth * - * * - * This program is free software; you can redistribute it and/or modify it * - * under the terms of the GNU General Public License as published by the * - * Free Software Foundation; either version 2 of the License, or (at your * - * option) any later version. * - * * - * This program is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#include "pwm.h" - +/*************************************************************************** + * Gens: PWM audio emulator. * + * * + * Copyright (c) 1999-2002 by Stphane Dallongeville * + * Copyright (c) 2003-2004 by Stphane Akhoun * + * Copyright (c) 2008-2009 by David Korth * + * * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; either version 2 of the License, or (at your * + * option) any later version. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "pwm.h" + #include #include @@ -31,251 +31,251 @@ //#include "gens_core/mem/mem_sh2.h" //#include "gens_core/cpu/sh2/sh2.h" - -#define CHILLY_WILLY_SCALE 1 - -#if PWM_BUF_SIZE == 8 -unsigned char PWM_FULL_TAB[PWM_BUF_SIZE * PWM_BUF_SIZE] = -{ - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, -}; -#elif PWM_BUF_SIZE == 4 -unsigned char PWM_FULL_TAB[PWM_BUF_SIZE * PWM_BUF_SIZE] = -{ - 0x40, 0x00, 0x00, 0x80, - 0x80, 0x40, 0x00, 0x00, - 0x00, 0x80, 0x40, 0x00, - 0x00, 0x00, 0x80, 0x40, -}; -#else -#error PWM_BUF_SIZE must equal 4 or 8. -#endif /* PWM_BUF_SIZE */ - -typedef struct _pwm_chip -{ - unsigned short PWM_FIFO_R[8]; - unsigned short PWM_FIFO_L[8]; - unsigned int PWM_RP_R; - unsigned int PWM_WP_R; - unsigned int PWM_RP_L; - unsigned int PWM_WP_L; - unsigned int PWM_Cycles; - unsigned int PWM_Cycle; - unsigned int PWM_Cycle_Cnt; - unsigned int PWM_Int; - unsigned int PWM_Int_Cnt; - unsigned int PWM_Mode; - //unsigned int PWM_Enable; - unsigned int PWM_Out_R; - unsigned int PWM_Out_L; - - unsigned int PWM_Cycle_Tmp; - unsigned int PWM_Cycles_Tmp; - unsigned int PWM_Int_Tmp; - unsigned int PWM_FIFO_L_Tmp; - unsigned int PWM_FIFO_R_Tmp; - -#if CHILLY_WILLY_SCALE -// TODO: Fix Chilly Willy's new scaling algorithm. - /* PWM scaling variables. */ - int PWM_Offset; - int PWM_Scale; - //int PWM_Loudness; -#endif - - int clock; -} pwm_chip; -#if CHILLY_WILLY_SCALE -// TODO: Fix Chilly Willy's new scaling algorithm. -#define PWM_Loudness 0 -#endif - -void PWM_Init(pwm_chip* chip); -void PWM_Recalc_Scale(pwm_chip* chip); - -void PWM_Set_Cycle(pwm_chip* chip, unsigned int cycle); -void PWM_Set_Int(pwm_chip* chip, unsigned int int_time); - -void PWM_Update(pwm_chip* chip, int **buf, int length); - - -/** - * PWM_Init(): Initialize the PWM audio emulator. - */ -void PWM_Init(pwm_chip* chip) -{ - chip->PWM_Mode = 0; - chip->PWM_Out_R = 0; - chip->PWM_Out_L = 0; - - memset(chip->PWM_FIFO_R, 0x00, sizeof(chip->PWM_FIFO_R)); - memset(chip->PWM_FIFO_L, 0x00, sizeof(chip->PWM_FIFO_L)); - - chip->PWM_RP_R = 0; - chip->PWM_WP_R = 0; - chip->PWM_RP_L = 0; - chip->PWM_WP_L = 0; - chip->PWM_Cycle_Tmp = 0; - chip->PWM_Int_Tmp = 0; - chip->PWM_FIFO_L_Tmp = 0; - chip->PWM_FIFO_R_Tmp = 0; - - //PWM_Loudness = 0; - PWM_Set_Cycle(chip, 0); - PWM_Set_Int(chip, 0); -} - - -#if CHILLY_WILLY_SCALE -// TODO: Fix Chilly Willy's new scaling algorithm. -void PWM_Recalc_Scale(pwm_chip* chip) -{ - chip->PWM_Offset = (chip->PWM_Cycle / 2) + 1; - chip->PWM_Scale = 0x7FFF00 / chip->PWM_Offset; -} -#endif - - -void PWM_Set_Cycle(pwm_chip* chip, unsigned int cycle) -{ - cycle--; - chip->PWM_Cycle = (cycle & 0xFFF); - chip->PWM_Cycle_Cnt = chip->PWM_Cycles; - -#if CHILLY_WILLY_SCALE - // TODO: Fix Chilly Willy's new scaling algorithm. - PWM_Recalc_Scale(chip); -#endif -} - - -void PWM_Set_Int(pwm_chip* chip, unsigned int int_time) -{ - int_time &= 0x0F; - if (int_time) - chip->PWM_Int = chip->PWM_Int_Cnt = int_time; - else - chip->PWM_Int = chip->PWM_Int_Cnt = 16; -} - - -void PWM_Clear_Timer(pwm_chip* chip) -{ - chip->PWM_Cycle_Cnt = 0; -} - - -/** - * PWM_SHIFT(): Shift PWM data. - * @param src: Channel (L or R) with the source data. - * @param dest Channel (L or R) for the destination. - */ -#define PWM_SHIFT(src, dest) \ -{ \ - /* Make sure the source FIFO isn't empty. */ \ - if (PWM_RP_##src != PWM_WP_##src) \ - { \ - /* Get destination channel output from the source channel FIFO. */ \ - PWM_Out_##dest = PWM_FIFO_##src[PWM_RP_##src]; \ - \ - /* Increment the source channel read pointer, resetting to 0 if it overflows. */ \ - PWM_RP_##src = (PWM_RP_##src + 1) & (PWM_BUF_SIZE - 1); \ - } \ -} - - -/*static void PWM_Shift_Data(void) -{ - switch (PWM_Mode & 0x0F) - { - case 0x01: - case 0x0D: - // Rx_LL: Right -> Ignore, Left -> Left - PWM_SHIFT(L, L); - break; - - case 0x02: - case 0x0E: - // Rx_LR: Right -> Ignore, Left -> Right - PWM_SHIFT(L, R); - break; - - case 0x04: - case 0x07: - // RL_Lx: Right -> Left, Left -> Ignore - PWM_SHIFT(R, L); - break; - - case 0x05: - case 0x09: - // RR_LL: Right -> Right, Left -> Left - PWM_SHIFT(L, L); - PWM_SHIFT(R, R); - break; - - case 0x06: - case 0x0A: - // RL_LR: Right -> Left, Left -> Right - PWM_SHIFT(L, R); - PWM_SHIFT(R, L); - break; - - case 0x08: - case 0x0B: - // RR_Lx: Right -> Right, Left -> Ignore - PWM_SHIFT(R, R); - break; - - case 0x00: - case 0x03: - case 0x0C: - case 0x0F: - default: - // Rx_Lx: Right -> Ignore, Left -> Ignore - break; - } -} - - -void PWM_Update_Timer(unsigned int cycle) -{ - // Don't do anything if PWM is disabled in the Sound menu. - - // Don't do anything if PWM isn't active. - if ((PWM_Mode & 0x0F) == 0x00) - return; - - if (PWM_Cycle == 0x00 || (PWM_Cycle_Cnt > cycle)) - return; - - PWM_Shift_Data(); - - PWM_Cycle_Cnt += PWM_Cycle; - - PWM_Int_Cnt--; - if (PWM_Int_Cnt == 0) - { - PWM_Int_Cnt = PWM_Int; - - if (PWM_Mode & 0x0080) - { - // RPT => generate DREQ1 as well as INT - SH2_DMA1_Request(&M_SH2, 1); - SH2_DMA1_Request(&S_SH2, 1); - } - - if (_32X_MINT & 1) - SH2_Interrupt(&M_SH2, 6); - if (_32X_SINT & 1) - SH2_Interrupt(&S_SH2, 6); - } + +#define CHILLY_WILLY_SCALE 1 + +#if PWM_BUF_SIZE == 8 +unsigned char PWM_FULL_TAB[PWM_BUF_SIZE * PWM_BUF_SIZE] = +{ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, +}; +#elif PWM_BUF_SIZE == 4 +unsigned char PWM_FULL_TAB[PWM_BUF_SIZE * PWM_BUF_SIZE] = +{ + 0x40, 0x00, 0x00, 0x80, + 0x80, 0x40, 0x00, 0x00, + 0x00, 0x80, 0x40, 0x00, + 0x00, 0x00, 0x80, 0x40, +}; +#else +#error PWM_BUF_SIZE must equal 4 or 8. +#endif /* PWM_BUF_SIZE */ + +typedef struct _pwm_chip +{ + unsigned short PWM_FIFO_R[8]; + unsigned short PWM_FIFO_L[8]; + unsigned int PWM_RP_R; + unsigned int PWM_WP_R; + unsigned int PWM_RP_L; + unsigned int PWM_WP_L; + unsigned int PWM_Cycles; + unsigned int PWM_Cycle; + unsigned int PWM_Cycle_Cnt; + unsigned int PWM_Int; + unsigned int PWM_Int_Cnt; + unsigned int PWM_Mode; + //unsigned int PWM_Enable; + unsigned int PWM_Out_R; + unsigned int PWM_Out_L; + + unsigned int PWM_Cycle_Tmp; + unsigned int PWM_Cycles_Tmp; + unsigned int PWM_Int_Tmp; + unsigned int PWM_FIFO_L_Tmp; + unsigned int PWM_FIFO_R_Tmp; + +#if CHILLY_WILLY_SCALE +// TODO: Fix Chilly Willy's new scaling algorithm. + /* PWM scaling variables. */ + int PWM_Offset; + int PWM_Scale; + //int PWM_Loudness; +#endif + + int clock; +} pwm_chip; +#if CHILLY_WILLY_SCALE +// TODO: Fix Chilly Willy's new scaling algorithm. +#define PWM_Loudness 0 +#endif + +void PWM_Init(pwm_chip* chip); +void PWM_Recalc_Scale(pwm_chip* chip); + +void PWM_Set_Cycle(pwm_chip* chip, unsigned int cycle); +void PWM_Set_Int(pwm_chip* chip, unsigned int int_time); + +void PWM_Update(pwm_chip* chip, int **buf, int length); + + +/** + * PWM_Init(): Initialize the PWM audio emulator. + */ +void PWM_Init(pwm_chip* chip) +{ + chip->PWM_Mode = 0; + chip->PWM_Out_R = 0; + chip->PWM_Out_L = 0; + + memset(chip->PWM_FIFO_R, 0x00, sizeof(chip->PWM_FIFO_R)); + memset(chip->PWM_FIFO_L, 0x00, sizeof(chip->PWM_FIFO_L)); + + chip->PWM_RP_R = 0; + chip->PWM_WP_R = 0; + chip->PWM_RP_L = 0; + chip->PWM_WP_L = 0; + chip->PWM_Cycle_Tmp = 0; + chip->PWM_Int_Tmp = 0; + chip->PWM_FIFO_L_Tmp = 0; + chip->PWM_FIFO_R_Tmp = 0; + + //PWM_Loudness = 0; + PWM_Set_Cycle(chip, 0); + PWM_Set_Int(chip, 0); +} + + +#if CHILLY_WILLY_SCALE +// TODO: Fix Chilly Willy's new scaling algorithm. +void PWM_Recalc_Scale(pwm_chip* chip) +{ + chip->PWM_Offset = (chip->PWM_Cycle / 2) + 1; + chip->PWM_Scale = 0x7FFF00 / chip->PWM_Offset; +} +#endif + + +void PWM_Set_Cycle(pwm_chip* chip, unsigned int cycle) +{ + cycle--; + chip->PWM_Cycle = (cycle & 0xFFF); + chip->PWM_Cycle_Cnt = chip->PWM_Cycles; + +#if CHILLY_WILLY_SCALE + // TODO: Fix Chilly Willy's new scaling algorithm. + PWM_Recalc_Scale(chip); +#endif +} + + +void PWM_Set_Int(pwm_chip* chip, unsigned int int_time) +{ + int_time &= 0x0F; + if (int_time) + chip->PWM_Int = chip->PWM_Int_Cnt = int_time; + else + chip->PWM_Int = chip->PWM_Int_Cnt = 16; +} + + +void PWM_Clear_Timer(pwm_chip* chip) +{ + chip->PWM_Cycle_Cnt = 0; +} + + +/** + * PWM_SHIFT(): Shift PWM data. + * @param src: Channel (L or R) with the source data. + * @param dest Channel (L or R) for the destination. + */ +#define PWM_SHIFT(src, dest) \ +{ \ + /* Make sure the source FIFO isn't empty. */ \ + if (PWM_RP_##src != PWM_WP_##src) \ + { \ + /* Get destination channel output from the source channel FIFO. */ \ + PWM_Out_##dest = PWM_FIFO_##src[PWM_RP_##src]; \ + \ + /* Increment the source channel read pointer, resetting to 0 if it overflows. */ \ + PWM_RP_##src = (PWM_RP_##src + 1) & (PWM_BUF_SIZE - 1); \ + } \ +} + + +/*static void PWM_Shift_Data(void) +{ + switch (PWM_Mode & 0x0F) + { + case 0x01: + case 0x0D: + // Rx_LL: Right -> Ignore, Left -> Left + PWM_SHIFT(L, L); + break; + + case 0x02: + case 0x0E: + // Rx_LR: Right -> Ignore, Left -> Right + PWM_SHIFT(L, R); + break; + + case 0x04: + case 0x07: + // RL_Lx: Right -> Left, Left -> Ignore + PWM_SHIFT(R, L); + break; + + case 0x05: + case 0x09: + // RR_LL: Right -> Right, Left -> Left + PWM_SHIFT(L, L); + PWM_SHIFT(R, R); + break; + + case 0x06: + case 0x0A: + // RL_LR: Right -> Left, Left -> Right + PWM_SHIFT(L, R); + PWM_SHIFT(R, L); + break; + + case 0x08: + case 0x0B: + // RR_Lx: Right -> Right, Left -> Ignore + PWM_SHIFT(R, R); + break; + + case 0x00: + case 0x03: + case 0x0C: + case 0x0F: + default: + // Rx_Lx: Right -> Ignore, Left -> Ignore + break; + } +} + + +void PWM_Update_Timer(unsigned int cycle) +{ + // Don't do anything if PWM is disabled in the Sound menu. + + // Don't do anything if PWM isn't active. + if ((PWM_Mode & 0x0F) == 0x00) + return; + + if (PWM_Cycle == 0x00 || (PWM_Cycle_Cnt > cycle)) + return; + + PWM_Shift_Data(); + + PWM_Cycle_Cnt += PWM_Cycle; + + PWM_Int_Cnt--; + if (PWM_Int_Cnt == 0) + { + PWM_Int_Cnt = PWM_Int; + + if (PWM_Mode & 0x0080) + { + // RPT => generate DREQ1 as well as INT + SH2_DMA1_Request(&M_SH2, 1); + SH2_DMA1_Request(&S_SH2, 1); + } + + if (_32X_MINT & 1) + SH2_Interrupt(&M_SH2, 6); + if (_32X_SINT & 1) + SH2_Interrupt(&S_SH2, 6); + } }*/ @@ -283,162 +283,162 @@ { if (PWM_In == 0) return 0; - - // TODO: Chilly Willy's new scaling algorithm breaks drx's Sonic 1 32X (with PWM drums). -#ifdef CHILLY_WILLY_SCALE - //return (((PWM_In & 0xFFF) - chip->PWM_Offset) * chip->PWM_Scale) >> (8 - PWM_Loudness); - // Knuckles' Chaotix: Tachy Touch uses the values 0xF?? for negative values - // This small modification fixes the terrible pops. - PWM_In &= 0xFFF; - if (PWM_In & 0x800) - PWM_In |= ~0xFFF; - return ((PWM_In - chip->PWM_Offset) * chip->PWM_Scale) >> (8 - PWM_Loudness); -#else - const int PWM_adjust = ((chip->PWM_Cycle >> 1) + 1); - int PWM_Ret = ((chip->PWM_In & 0xFFF) - PWM_adjust); - - // Increase PWM volume so it's audible. - PWM_Ret <<= (5+2); - - // Make sure the PWM isn't oversaturated. - if (PWM_Ret > 32767) - PWM_Ret = 32767; - else if (PWM_Ret < -32768) - PWM_Ret = -32768; - - return PWM_Ret; -#endif -} - - -void PWM_Update(pwm_chip* chip, int **buf, int length) -{ - int tmpOutL; - int tmpOutR; - int i; - - //if (!PWM_Enable) - // return; - - if (chip->PWM_Out_L == 0 && chip->PWM_Out_R == 0) - { - memset(buf[0], 0x00, length * sizeof(int)); - memset(buf[1], 0x00, length * sizeof(int)); - return; - } - - // New PWM scaling algorithm provided by Chilly Willy on the Sonic Retro forums. - tmpOutL = PWM_Update_Scale(chip, (int)chip->PWM_Out_L); - tmpOutR = PWM_Update_Scale(chip, (int)chip->PWM_Out_R); - - for (i = 0; i < length; i ++) - { - buf[0][i] = tmpOutL; - buf[1][i] = tmpOutR; - } -} - - -void pwm_update(void *_chip, stream_sample_t **outputs, int samples) -{ - pwm_chip *chip = (pwm_chip *) _chip; - - PWM_Update(chip, outputs, samples); -} - -void * device_start_pwm(int clock) -{ - /* allocate memory for the chip */ - //pwm_state *chip = get_safe_token(device); - pwm_chip *chip; - int rate; - - chip = (pwm_chip *) malloc(sizeof(pwm_chip)); - if (!chip) return chip; - - rate = 22020; // that's the rate the PWM is mostly used - chip->clock = clock; - - PWM_Init(chip); - /* allocate the stream */ - //chip->stream = stream_create(device, 0, 2, device->clock / 384, chip, rf5c68_update); - - return chip; -} - -void device_stop_pwm(void *chip) -{ - //pwm_chip *chip = &PWM_Chip[ChipID]; - //free(chip->ram); - free(chip); -} - -void device_reset_pwm(void *_chip) -{ - pwm_chip *chip = (pwm_chip *) _chip; - PWM_Init(chip); -} - -void pwm_chn_w(void *_chip, UINT8 Channel, UINT16 data) -{ - pwm_chip *chip = (pwm_chip *) _chip; - - if (chip->clock == 1) - { // old-style commands - switch(Channel) - { - case 0x00: - chip->PWM_Out_L = data; - break; - case 0x01: - chip->PWM_Out_R = data; - break; - case 0x02: - PWM_Set_Cycle(chip, data); - break; - case 0x03: - chip->PWM_Out_L = data; - chip->PWM_Out_R = data; - break; - } - } - else - { - switch(Channel) - { - case 0x00/2: // control register - PWM_Set_Int(chip, data >> 8); - break; - case 0x02/2: // cycle register - PWM_Set_Cycle(chip, data); - break; - case 0x04/2: // l ch - chip->PWM_Out_L = data; - break; - case 0x06/2: // r ch - chip->PWM_Out_R = data; - if (! chip->PWM_Mode) - { - if (chip->PWM_Out_L == chip->PWM_Out_R) - { - // fixes these terrible pops when - // starting/stopping/pausing the song - chip->PWM_Offset = data; - chip->PWM_Mode = 0x01; - } - } - break; - case 0x08/2: // mono ch - chip->PWM_Out_L = data; - chip->PWM_Out_R = data; - if (! chip->PWM_Mode) - { - chip->PWM_Offset = data; - chip->PWM_Mode = 0x01; - } - break; - } - } - - return; -} + + // TODO: Chilly Willy's new scaling algorithm breaks drx's Sonic 1 32X (with PWM drums). +#ifdef CHILLY_WILLY_SCALE + //return (((PWM_In & 0xFFF) - chip->PWM_Offset) * chip->PWM_Scale) >> (8 - PWM_Loudness); + // Knuckles' Chaotix: Tachy Touch uses the values 0xF?? for negative values + // This small modification fixes the terrible pops. + PWM_In &= 0xFFF; + if (PWM_In & 0x800) + PWM_In |= ~0xFFF; + return ((PWM_In - chip->PWM_Offset) * chip->PWM_Scale) >> (8 - PWM_Loudness); +#else + const int PWM_adjust = ((chip->PWM_Cycle >> 1) + 1); + int PWM_Ret = ((chip->PWM_In & 0xFFF) - PWM_adjust); + + // Increase PWM volume so it's audible. + PWM_Ret <<= (5+2); + + // Make sure the PWM isn't oversaturated. + if (PWM_Ret > 32767) + PWM_Ret = 32767; + else if (PWM_Ret < -32768) + PWM_Ret = -32768; + + return PWM_Ret; +#endif +} + + +void PWM_Update(pwm_chip* chip, int **buf, int length) +{ + int tmpOutL; + int tmpOutR; + int i; + + //if (!PWM_Enable) + // return; + + if (chip->PWM_Out_L == 0 && chip->PWM_Out_R == 0) + { + memset(buf[0], 0x00, length * sizeof(int)); + memset(buf[1], 0x00, length * sizeof(int)); + return; + } + + // New PWM scaling algorithm provided by Chilly Willy on the Sonic Retro forums. + tmpOutL = PWM_Update_Scale(chip, (int)chip->PWM_Out_L); + tmpOutR = PWM_Update_Scale(chip, (int)chip->PWM_Out_R); + + for (i = 0; i < length; i ++) + { + buf[0][i] = tmpOutL; + buf[1][i] = tmpOutR; + } +} + + +void pwm_update(void *_chip, stream_sample_t **outputs, int samples) +{ + pwm_chip *chip = (pwm_chip *) _chip; + + PWM_Update(chip, outputs, samples); +} + +void * device_start_pwm(int clock) +{ + /* allocate memory for the chip */ + //pwm_state *chip = get_safe_token(device); + pwm_chip *chip; + int rate; + + chip = (pwm_chip *) malloc(sizeof(pwm_chip)); + if (!chip) return chip; + + rate = 22020; // that's the rate the PWM is mostly used + chip->clock = clock; + + PWM_Init(chip); + /* allocate the stream */ + //chip->stream = stream_create(device, 0, 2, device->clock / 384, chip, rf5c68_update); + + return chip; +} + +void device_stop_pwm(void *chip) +{ + //pwm_chip *chip = &PWM_Chip[ChipID]; + //free(chip->ram); + free(chip); +} + +void device_reset_pwm(void *_chip) +{ + pwm_chip *chip = (pwm_chip *) _chip; + PWM_Init(chip); +} + +void pwm_chn_w(void *_chip, UINT8 Channel, UINT16 data) +{ + pwm_chip *chip = (pwm_chip *) _chip; + + if (chip->clock == 1) + { // old-style commands + switch(Channel) + { + case 0x00: + chip->PWM_Out_L = data; + break; + case 0x01: + chip->PWM_Out_R = data; + break; + case 0x02: + PWM_Set_Cycle(chip, data); + break; + case 0x03: + chip->PWM_Out_L = data; + chip->PWM_Out_R = data; + break; + } + } + else + { + switch(Channel) + { + case 0x00/2: // control register + PWM_Set_Int(chip, data >> 8); + break; + case 0x02/2: // cycle register + PWM_Set_Cycle(chip, data); + break; + case 0x04/2: // l ch + chip->PWM_Out_L = data; + break; + case 0x06/2: // r ch + chip->PWM_Out_R = data; + if (! chip->PWM_Mode) + { + if (chip->PWM_Out_L == chip->PWM_Out_R) + { + // fixes these terrible pops when + // starting/stopping/pausing the song + chip->PWM_Offset = data; + chip->PWM_Mode = 0x01; + } + } + break; + case 0x08/2: // mono ch + chip->PWM_Out_L = data; + chip->PWM_Out_R = data; + if (! chip->PWM_Mode) + { + chip->PWM_Offset = data; + chip->PWM_Mode = 0x01; + } + break; + } + } + + return; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Pwm_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Pwm_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Pwm_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Pwm_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,66 +1,66 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Pwm_Emu.h" -#include "pwm.h" - -Pwm_Emu::Pwm_Emu() { chip = 0; } - -Pwm_Emu::~Pwm_Emu() -{ - if ( chip ) device_stop_pwm( chip ); -} - -int Pwm_Emu::set_rate( int clock ) -{ - if ( chip ) - { - device_stop_pwm( chip ); - chip = 0; - } - - chip = device_start_pwm( clock ); - if ( !chip ) - return 1; - - reset(); - return 0; -} - -void Pwm_Emu::reset() -{ - device_reset_pwm( chip ); -} - -void Pwm_Emu::write( int channel, int data ) -{ - pwm_chn_w( chip, channel, data ); -} - -void Pwm_Emu::run( int pair_count, sample_t* out ) -{ - stream_sample_t bufL[ 1024 ]; - stream_sample_t bufR[ 1024 ]; - stream_sample_t * buffers[2] = { bufL, bufR }; - - while (pair_count > 0) - { - int todo = pair_count; - if (todo > 1024) todo = 1024; - pwm_update( chip, buffers, todo ); - - for (int i = 0; i < todo; i++) - { - int output_l = bufL [i]; - int output_r = bufR [i]; - output_l += out [0]; - output_r += out [1]; - if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); - if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); - out [0] = output_l; - out [1] = output_r; - out += 2; - } - - pair_count -= todo; - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Pwm_Emu.h" +#include "pwm.h" + +Pwm_Emu::Pwm_Emu() { chip = 0; } + +Pwm_Emu::~Pwm_Emu() +{ + if ( chip ) device_stop_pwm( chip ); +} + +int Pwm_Emu::set_rate( int clock ) +{ + if ( chip ) + { + device_stop_pwm( chip ); + chip = 0; + } + + chip = device_start_pwm( clock ); + if ( !chip ) + return 1; + + reset(); + return 0; +} + +void Pwm_Emu::reset() +{ + device_reset_pwm( chip ); +} + +void Pwm_Emu::write( int channel, int data ) +{ + pwm_chn_w( chip, channel, data ); +} + +void Pwm_Emu::run( int pair_count, sample_t* out ) +{ + stream_sample_t bufL[ 1024 ]; + stream_sample_t bufR[ 1024 ]; + stream_sample_t * buffers[2] = { bufL, bufR }; + + while (pair_count > 0) + { + int todo = pair_count; + if (todo > 1024) todo = 1024; + pwm_update( chip, buffers, todo ); + + for (int i = 0; i < todo; i++) + { + int output_l = bufL [i]; + int output_r = bufR [i]; + output_l += out [0]; + output_r += out [1]; + if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); + if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); + out [0] = output_l; + out [1] = output_r; + out += 2; + } + + pair_count -= todo; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Pwm_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Pwm_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Pwm_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Pwm_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,33 +1,34 @@ -// PWM sound chip emulator interface - -// Game_Music_Emu $vers -#ifndef PWM_EMU_H -#define PWM_EMU_H - -class Pwm_Emu { - void* chip; -public: - Pwm_Emu(); - ~Pwm_Emu(); - - // Sets output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - int set_rate( int clock ); - - // Resets to power-up state - void reset(); - - // Mutes voice n if bit n (1 << n) of mask is set - enum { channel_count = 24 }; - void mute_voices( int mask ); - - // Writes data to channel - void write( int channel, int data ); - - // Runs and writes pair_count*2 samples to output - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif +// PWM sound chip emulator interface + +// Game_Music_Emu $vers +#ifndef PWM_EMU_H +#define PWM_EMU_H + +class Pwm_Emu { + void* chip; +public: + Pwm_Emu(); + ~Pwm_Emu(); + + // Sets output sample rate and chip clock rates, in Hz. Returns non-zero + // if error. + int set_rate( int clock ); + + // Resets to power-up state + void reset(); + + // Mutes voice n if bit n (1 << n) of mask is set + enum { channel_count = 24 }; + void mute_voices( int mask ); + + // Writes data to channel + void write( int channel, int data ); + + // Runs and writes pair_count*2 samples to output + typedef short sample_t; + enum { out_chan_count = 2 }; // stereo + void run( int pair_count, sample_t* out ); +}; + +#endif + diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/pwm.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/pwm.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/pwm.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/pwm.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,71 +1,71 @@ -/*************************************************************************** - * Gens: PWM audio emulator. * - * * - * Copyright (c) 1999-2002 by Stphane Dallongeville * - * Copyright (c) 2003-2004 by Stphane Akhoun * - * Copyright (c) 2008 by David Korth * - * * - * This program is free software; you can redistribute it and/or modify it * - * under the terms of the GNU General Public License as published by the * - * Free Software Foundation; either version 2 of the License, or (at your * - * option) any later version. * - * * - * This program is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#define PWM_BUF_SIZE 4 - -#include "mamedef.h" - -/*extern unsigned char PWM_FULL_TAB[PWM_BUF_SIZE * PWM_BUF_SIZE]; - -extern unsigned short PWM_FIFO_R[8]; -extern unsigned short PWM_FIFO_L[8]; -extern unsigned int PWM_RP_R; -extern unsigned int PWM_WP_R; -extern unsigned int PWM_RP_L; -extern unsigned int PWM_WP_L; -extern unsigned int PWM_Cycles; -extern unsigned int PWM_Cycle; -extern unsigned int PWM_Cycle_Cnt; -extern unsigned int PWM_Int; -extern unsigned int PWM_Int_Cnt; -extern unsigned int PWM_Mode; -extern unsigned int PWM_Enable; -extern unsigned int PWM_Out_R; -extern unsigned int PWM_Out_L;*/ - -//void PWM_Init(void); -//void PWM_Recalc_Scale(void); - -/* Functions called by x86 asm. */ -//void PWM_Set_Cycle(unsigned int cycle); -//void PWM_Set_Int(unsigned int int_time); - -/* Functions called by C/C++ code only. */ -//void PWM_Clear_Timer(void); -//void PWM_Update_Timer(unsigned int cycle); -//void PWM_Update(int **buf, int length); - -#ifdef __cplusplus -extern "C" { -#endif - -void pwm_update(void *chip, stream_sample_t **outputs, int samples); - -void * device_start_pwm(int clock); -void device_stop_pwm(void *chip); -void device_reset_pwm(void *chip); - -void pwm_chn_w(void *chip, UINT8 Channel, UINT16 data); - -#ifdef __cplusplus -} -#endif +/*************************************************************************** + * Gens: PWM audio emulator. * + * * + * Copyright (c) 1999-2002 by Stphane Dallongeville * + * Copyright (c) 2003-2004 by Stphane Akhoun * + * Copyright (c) 2008 by David Korth * + * * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; either version 2 of the License, or (at your * + * option) any later version. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#define PWM_BUF_SIZE 4 + +#include "mamedef.h" + +/*extern unsigned char PWM_FULL_TAB[PWM_BUF_SIZE * PWM_BUF_SIZE]; + +extern unsigned short PWM_FIFO_R[8]; +extern unsigned short PWM_FIFO_L[8]; +extern unsigned int PWM_RP_R; +extern unsigned int PWM_WP_R; +extern unsigned int PWM_RP_L; +extern unsigned int PWM_WP_L; +extern unsigned int PWM_Cycles; +extern unsigned int PWM_Cycle; +extern unsigned int PWM_Cycle_Cnt; +extern unsigned int PWM_Int; +extern unsigned int PWM_Int_Cnt; +extern unsigned int PWM_Mode; +extern unsigned int PWM_Enable; +extern unsigned int PWM_Out_R; +extern unsigned int PWM_Out_L;*/ + +//void PWM_Init(void); +//void PWM_Recalc_Scale(void); + +/* Functions called by x86 asm. */ +//void PWM_Set_Cycle(unsigned int cycle); +//void PWM_Set_Int(unsigned int int_time); + +/* Functions called by C/C++ code only. */ +//void PWM_Clear_Timer(void); +//void PWM_Update_Timer(unsigned int cycle); +//void PWM_Update(int **buf, int length); + +#ifdef __cplusplus +extern "C" { +#endif + +void pwm_update(void *chip, stream_sample_t **outputs, int samples); + +void * device_start_pwm(int clock); +void device_stop_pwm(void *chip); +void device_reset_pwm(void *chip); + +void pwm_chn_w(void *chip, UINT8 Channel, UINT16 data); + +#ifdef __cplusplus +} +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/qmix.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/qmix.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/qmix.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/qmix.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,462 +1,462 @@ -///////////////////////////////////////////////////////////////////////////// -// -// qmix - QSound mixer -// -///////////////////////////////////////////////////////////////////////////// - -#include "qmix.h" - -///////////////////////////////////////////////////////////////////////////// - -#define ANTICLICK_TIME (64) -#define ANTICLICK_THRESHHOLD (32) - -///////////////////////////////////////////////////////////////////////////// - -#define RENDERMAX (200) - -///////////////////////////////////////////////////////////////////////////// - -static const sint32 gauss_shuffled_reverse_table[1024] = { - 366,1305, 374, 0, 362,1304, 378, 0, 358,1304, 381, 0, 354,1304, 385, 0, 351,1304, 389, 0, 347,1304, 393, 0, 343,1303, 397, 0, 339,1303, 401, 0, - 336,1303, 405, 0, 332,1302, 410, 0, 328,1302, 414, 0, 325,1301, 418, 0, 321,1300, 422, 0, 318,1300, 426, 0, 314,1299, 430, 0, 311,1298, 434, 0, - 307,1297, 439, 1, 304,1297, 443, 1, 300,1296, 447, 1, 297,1295, 451, 1, 293,1294, 456, 1, 290,1293, 460, 1, 286,1292, 464, 1, 283,1291, 469, 1, - 280,1290, 473, 1, 276,1288, 477, 1, 273,1287, 482, 1, 270,1286, 486, 2, 267,1284, 491, 2, 263,1283, 495, 2, 260,1282, 499, 2, 257,1280, 504, 2, - 254,1279, 508, 2, 251,1277, 513, 2, 248,1275, 517, 3, 245,1274, 522, 3, 242,1272, 527, 3, 239,1270, 531, 3, 236,1269, 536, 3, 233,1267, 540, 4, - 230,1265, 545, 4, 227,1263, 550, 4, 224,1261, 554, 4, 221,1259, 559, 4, 218,1257, 563, 5, 215,1255, 568, 5, 212,1253, 573, 5, 210,1251, 577, 5, - 207,1248, 582, 6, 204,1246, 587, 6, 201,1244, 592, 6, 199,1241, 596, 6, 196,1239, 601, 7, 193,1237, 606, 7, 191,1234, 611, 7, 188,1232, 615, 8, - 186,1229, 620, 8, 183,1227, 625, 8, 180,1224, 630, 9, 178,1221, 635, 9, 175,1219, 640, 9, 173,1216, 644, 10, 171,1213, 649, 10, 168,1210, 654, 10, - 166,1207, 659, 11, 163,1205, 664, 11, 161,1202, 669, 11, 159,1199, 674, 12, 156,1196, 678, 12, 154,1193, 683, 13, 152,1190, 688, 13, 150,1186, 693, 14, - 147,1183, 698, 14, 145,1180, 703, 15, 143,1177, 708, 15, 141,1174, 713, 15, 139,1170, 718, 16, 137,1167, 723, 16, 134,1164, 728, 17, 132,1160, 732, 17, - 130,1157, 737, 18, 128,1153, 742, 19, 126,1150, 747, 19, 124,1146, 752, 20, 122,1143, 757, 20, 120,1139, 762, 21, 118,1136, 767, 21, 117,1132, 772, 22, - 115,1128, 777, 23, 113,1125, 782, 23, 111,1121, 787, 24, 109,1117, 792, 24, 107,1113, 797, 25, 106,1109, 802, 26, 104,1106, 806, 27, 102,1102, 811, 27, - 100,1098, 816, 28, 99,1094, 821, 29, 97,1090, 826, 29, 95,1086, 831, 30, 94,1082, 836, 31, 92,1078, 841, 32, 90,1074, 846, 32, 89,1070, 851, 33, - 87,1066, 855, 34, 86,1061, 860, 35, 84,1057, 865, 36, 83,1053, 870, 36, 81,1049, 875, 37, 80,1045, 880, 38, 78,1040, 884, 39, 77,1036, 889, 40, - 76,1032, 894, 41, 74,1027, 899, 42, 73,1023, 904, 43, 71,1019, 908, 44, 70,1014, 913, 45, 69,1010, 918, 46, 67,1005, 923, 47, 66,1001, 927, 48, - 65, 997, 932, 49, 64, 992, 937, 50, 62, 988, 941, 51, 61, 983, 946, 52, 60, 978, 951, 53, 59, 974, 955, 54, 58, 969, 960, 55, 56, 965, 965, 56, - 55, 960, 969, 58, 54, 955, 974, 59, 53, 951, 978, 60, 52, 946, 983, 61, 51, 941, 988, 62, 50, 937, 992, 64, 49, 932, 997, 65, 48, 927,1001, 66, - 47, 923,1005, 67, 46, 918,1010, 69, 45, 913,1014, 70, 44, 908,1019, 71, 43, 904,1023, 73, 42, 899,1027, 74, 41, 894,1032, 76, 40, 889,1036, 77, - 39, 884,1040, 78, 38, 880,1045, 80, 37, 875,1049, 81, 36, 870,1053, 83, 36, 865,1057, 84, 35, 860,1061, 86, 34, 855,1066, 87, 33, 851,1070, 89, - 32, 846,1074, 90, 32, 841,1078, 92, 31, 836,1082, 94, 30, 831,1086, 95, 29, 826,1090, 97, 29, 821,1094, 99, 28, 816,1098, 100, 27, 811,1102, 102, - 27, 806,1106, 104, 26, 802,1109, 106, 25, 797,1113, 107, 24, 792,1117, 109, 24, 787,1121, 111, 23, 782,1125, 113, 23, 777,1128, 115, 22, 772,1132, 117, - 21, 767,1136, 118, 21, 762,1139, 120, 20, 757,1143, 122, 20, 752,1146, 124, 19, 747,1150, 126, 19, 742,1153, 128, 18, 737,1157, 130, 17, 732,1160, 132, - 17, 728,1164, 134, 16, 723,1167, 137, 16, 718,1170, 139, 15, 713,1174, 141, 15, 708,1177, 143, 15, 703,1180, 145, 14, 698,1183, 147, 14, 693,1186, 150, - 13, 688,1190, 152, 13, 683,1193, 154, 12, 678,1196, 156, 12, 674,1199, 159, 11, 669,1202, 161, 11, 664,1205, 163, 11, 659,1207, 166, 10, 654,1210, 168, - 10, 649,1213, 171, 10, 644,1216, 173, 9, 640,1219, 175, 9, 635,1221, 178, 9, 630,1224, 180, 8, 625,1227, 183, 8, 620,1229, 186, 8, 615,1232, 188, - 7, 611,1234, 191, 7, 606,1237, 193, 7, 601,1239, 196, 6, 596,1241, 199, 6, 592,1244, 201, 6, 587,1246, 204, 6, 582,1248, 207, 5, 577,1251, 210, - 5, 573,1253, 212, 5, 568,1255, 215, 5, 563,1257, 218, 4, 559,1259, 221, 4, 554,1261, 224, 4, 550,1263, 227, 4, 545,1265, 230, 4, 540,1267, 233, - 3, 536,1269, 236, 3, 531,1270, 239, 3, 527,1272, 242, 3, 522,1274, 245, 3, 517,1275, 248, 2, 513,1277, 251, 2, 508,1279, 254, 2, 504,1280, 257, - 2, 499,1282, 260, 2, 495,1283, 263, 2, 491,1284, 267, 2, 486,1286, 270, 1, 482,1287, 273, 1, 477,1288, 276, 1, 473,1290, 280, 1, 469,1291, 283, - 1, 464,1292, 286, 1, 460,1293, 290, 1, 456,1294, 293, 1, 451,1295, 297, 1, 447,1296, 300, 1, 443,1297, 304, 1, 439,1297, 307, 0, 434,1298, 311, - 0, 430,1299, 314, 0, 426,1300, 318, 0, 422,1300, 321, 0, 418,1301, 325, 0, 414,1302, 328, 0, 410,1302, 332, 0, 405,1303, 336, 0, 401,1303, 339, - 0, 397,1303, 343, 0, 393,1304, 347, 0, 389,1304, 351, 0, 385,1304, 354, 0, 381,1304, 358, 0, 378,1304, 362, 0, 374,1305, 366, 0, 370,1305, 370, -}; - -static const sint32 pan_table[33] = { - 0, 724,1024,1254,1448,1619,1774,1916, -2048,2172,2290,2401,2508,2611,2709,2804, -2896,2985,3072,3156,3238,3318,3396,3473, -3547,3620,3692,3762,3831,3899,3966,4031, -4096}; - -///////////////////////////////////////////////////////////////////////////// -// -// Static information -// -sint32 EMU_CALL _qmix_init(void) { return 0; } - -///////////////////////////////////////////////////////////////////////////// -// -// State information -// -#define QMIXSTATE ((struct QMIX_STATE*)(state)) - -struct QMIX_CHAN { - uint32 on; - uint32 startbank; - uint32 startaddr; - uint32 curbank; - uint32 curaddr; - uint32 startloop; - uint32 startend; - uint32 curloop; - uint32 curend; - uint32 phase; - uint32 pitch; - uint32 vol; - uint32 pan; - sint32 current_mix_l; - sint32 current_mix_r; - sint32 sample[4]; - sint32 sample_last_l; - sint32 sample_last_r; - sint32 sample_anticlick_l; - sint32 sample_anticlick_r; - sint32 sample_anticlick_remaining_l; - sint32 sample_anticlick_remaining_r; -}; - -///////////////////////////////////////////////////////////////////////////// - -static EMU_INLINE void get_anticlicked_samples( - struct QMIX_CHAN *chan, sint32 *l, sint32 *r -) { - sint32 out, remain; - remain = chan->sample_anticlick_remaining_l; - if(remain) { - sint32 diff = chan->sample_last_l - chan->sample_anticlick_l; - if(diff < 0) { diff = -diff; } - if(diff < ANTICLICK_THRESHHOLD) { - out = chan->sample_last_l; - chan->sample_anticlick_remaining_l = 0; - } else { - out = ( - chan->sample_last_l * (ANTICLICK_TIME-remain) + - chan->sample_anticlick_l * (remain) - ) / ANTICLICK_TIME; - chan->sample_anticlick_remaining_l--; - } - } else { - out = chan->sample_last_l; - } - *l = out; - - remain = chan->sample_anticlick_remaining_r; - if(remain) { - sint32 diff = chan->sample_last_r - chan->sample_anticlick_r; - if(diff < 0) { diff = -diff; } - if(diff < ANTICLICK_THRESHHOLD) { - out = chan->sample_last_r; - chan->sample_anticlick_remaining_r = 0; - } else { - out = ( - chan->sample_last_r * (ANTICLICK_TIME-remain) + - chan->sample_anticlick_r * (remain) - ) / ANTICLICK_TIME; - chan->sample_anticlick_remaining_r--; - } - } else { - out = chan->sample_last_r; - } - *r = out; - -} - -///////////////////////////////////////////////////////////////////////////// - -static EMU_INLINE void anticlick(struct QMIX_CHAN *chan) { - sint32 l, r; - get_anticlicked_samples(chan, &l, &r); - chan->sample_anticlick_l = l; - chan->sample_anticlick_r = r; - chan->sample_anticlick_remaining_l = ANTICLICK_TIME; - chan->sample_anticlick_remaining_r = ANTICLICK_TIME; -} - -///////////////////////////////////////////////////////////////////////////// - -struct QMIX_STATE { - uint8 *sample_rom; - uint32 sample_rom_size; - uint32 pitchscaler; - struct QMIX_CHAN chan[16]; - sint32 last_in_l; - sint32 last_in_r; - sint32 last_out_l; - sint32 last_out_r; - sint32 acc_l; - sint32 acc_r; -}; - -uint32 EMU_CALL _qmix_get_state_size(void) { - return sizeof(struct QMIX_STATE); -} - -void EMU_CALL _qmix_clear_state(void *state) { - memset(state, 0, sizeof(struct QMIX_STATE)); - - -} - -void EMU_CALL _qmix_set_sample_rom(void *state, void *rom, uint32 size) { - QMIXSTATE->sample_rom = rom; - QMIXSTATE->sample_rom_size = size; -} - -///////////////////////////////////////////////////////////////////////////// - -static EMU_INLINE void chan_advance( - struct QMIX_STATE *state, - struct QMIX_CHAN *chan -) { - uint32 rom_addr = chan->curbank + chan->curaddr; - if(rom_addr >= state->sample_rom_size) rom_addr = 0; - chan->sample[0] = chan->sample[1]; - chan->sample[1] = chan->sample[2]; - chan->sample[2] = chan->sample[3]; - chan->sample[3] = (sint32)((sint8)(state->sample_rom[rom_addr])); - chan->curaddr++; -// FIXME: MAME thinks this is >=, but is it > ? - if(chan->curaddr >= chan->curend) { -// if(!chan->curloop) { -// chan->on = 0; -// chan->curaddr--; -// } else { - chan->curaddr = chan->curend - chan->curloop; -// chan->curaddr -= 1 + chan->curloop; -// } - } - chan->curaddr &= 0xFFFF; -} - -///////////////////////////////////////////////////////////////////////////// - -static EMU_INLINE sint32 chan_get_resampled( - struct QMIX_STATE *state, - struct QMIX_CHAN *chan -) { - sint32 sum; - sint32 phase = chan->phase & 0xFFF; - -// sum = chan->sample[2]; -// sum <<= 8; - - const sint32 *gauss = (sint32*) - (((sint8*)gauss_shuffled_reverse_table) + (phase & 0x0FF0)); - sum = chan->sample[0] * gauss[0]; - sum += chan->sample[1] * gauss[1]; - sum += chan->sample[2] * gauss[2]; - sum += chan->sample[3] * gauss[3]; - sum /= 8; - -// sum = chan->sample[1] * (0x1000-phase); -// sum += chan->sample[2] * ( phase); -// sum >>= 4; - - chan->phase += chan->pitch; - while(chan->phase >= 0x1000) { - chan_advance(state, chan); - chan->phase -= 0x1000; - } - - return sum; -} - -static EMU_INLINE void chan_get_stereo_anticlicked( - struct QMIX_STATE *state, - struct QMIX_CHAN *chan, - sint32 *l, - sint32 *r -) { - if(!chan->on) { - chan->sample_last_l = 0; - chan->sample_last_r = 0; - } else { - sint32 out = chan_get_resampled(state, chan); - chan->sample_last_l = (out * chan->current_mix_l) / 0x8000; - chan->sample_last_r = (out * chan->current_mix_r) / 0x8000; - // if we suddenly keyed off, perform an anticlick here - if(!chan->on) { anticlick(chan); } - } - get_anticlicked_samples(chan, l, r); -} - -///////////////////////////////////////////////////////////////////////////// - -static void recalc_mix(struct QMIX_CHAN *chan) { - sint32 realpan = (chan->pan & 0x3F) - 0x10; - sint32 realvol = chan->vol & 0xFFFF; - if(realpan < 0x00) realpan = 0x00; - if(realpan > 0x20) realpan = 0x20; - -// chan->current_mix_l = realvol << 3; -// chan->current_mix_r = realvol << 3; -// if(realpan < 0x10) { -// chan->current_mix_r *= realpan; -// chan->current_mix_r >>= 4; -// } -// if(realpan > 0x10) { -// chan->current_mix_l *= (0x20-realpan); -// chan->current_mix_l >>= 4; -// } - -// chan->current_mix_l = ((0x20-realpan) * realvol) >> 1; -// chan->current_mix_r = (( realpan) * realvol) >> 1; - - chan->current_mix_l = (realvol * pan_table[0x20-realpan]) / 0x2000; - chan->current_mix_r = (realvol * pan_table[ realpan]) / 0x2000; - - // perform anticlick - //anticlick(chan); -} - -///////////////////////////////////////////////////////////////////////////// -// -// Command handling -// -//#include - -void EMU_CALL _qmix_command(void *state, uint8 cmd, uint16 data) { - struct QMIX_CHAN *chan; - uint32 ch = 0; - uint32 reg = 99; -//printf("qmix command 0x%02X:0x%04X\n",cmd,data); - if(cmd < 0x80) { - reg = cmd & 7; - ch = cmd >> 3; - } else if(cmd < 0x90) { - reg = 8; - ch = cmd - 0x80; - } else if(cmd >= 0xBA && cmd < 0xCA) { - reg = 9; - ch = cmd - 0xBA; - } else { - reg = 99; - ch = 0; - } - chan = QMIXSTATE->chan + ch; - switch(reg) { - case 0: // bank - ch = (ch+1) & 0xF; chan = QMIXSTATE->chan + ch; - //printf("qmix: bank ch%X = %04X\n",ch,data); - chan->startbank = (((uint32)data) & 0x7F) << 16; - break; - case 1: // start - //printf("qmix: start ch%X = %04X\n",ch,data); - chan->startaddr = ((uint32)data) & 0xFFFF; - break; - case 2: // pitch - //printf("qmix: pitch ch%X = %04X\n",ch,data); - chan->pitch = (((uint32)(data & 0xFFFF)) * QMIXSTATE->pitchscaler) / 0x10000; - if (chan->pitch == 0) { - chan->on = 0; - anticlick(chan); - } - break; - case 3: // unknown - break; - case 4: // loop start - //printf("qmix: loop ch%X = %04X\n",ch,data); - chan->startloop = data; - break; - case 5: // end - //printf("qmix: end ch%X = %04X\n",ch,data); - chan->startend = data; - break; - case 6: // volume - //printf("qmix: vol ch%X = %04X\n",ch,data); -//printf("volume=%04X\n",data); -// if(!data) { -// chan->on = 0; -// } else { -// chan->on = 1; -// chan->address = chan->start; -// chan->phase = 0; -// } - //printf("qmix: unknown reg3 ch%X = %04X\n",ch,data); - if(data == 0) { - chan->on = 0; - anticlick(chan); - } else if (chan->on == 0) { - chan->on = 1; - chan->curbank = chan->startbank; - chan->curaddr = chan->startaddr; - chan->curloop = chan->startloop; - chan->curend = chan->startend; - chan->phase = 0; - chan->sample[0] = 0; - chan->sample[1] = 0; - chan->sample[2] = 0; - chan->sample[3] = 0; - anticlick(chan); - } - - chan->vol = data; - recalc_mix(chan); - break; - case 7: // unknown - //printf("qmix: unknown reg7 ch%X = %04X\n",ch,data); - break; - case 8: // pan (0x110-0x130) - //printf("qmix: pan ch%X = %04X\n",ch,data); -//printf("pan=%04X\n",data); - chan->pan = data; - recalc_mix(chan); - break; - case 9: // ADSR? - //printf("qmix: unknown reg9 ch%X = %04X\n",ch,data); - break; - default: - //printf("qmix: unknown reg %02X = %04X\n",cmd,data); - break; - } -} - -///////////////////////////////////////////////////////////////////////////// -// -// Rendering -// -static void render( - struct QMIX_STATE *state, - sint16 *buf, - uint32 samples -) { - sint32 buf_l[RENDERMAX]; - sint32 buf_r[RENDERMAX]; - sint32 l, r; - uint32 s; - int ch; - memset(buf_l, 0, 4 * samples); - memset(buf_r, 0, 4 * samples); - for(ch = 0; ch < 16; ch++) { - struct QMIX_CHAN *chan = state->chan + ch; - for(s = 0; s < samples; s++) { - chan_get_stereo_anticlicked(state, chan, &l, &r); - buf_l[s] += l; - buf_r[s] += r; - } - } - if(!buf) return; - for(s = 0; s < samples; s++) { - sint32 diff_l = buf_l[s] - state->last_in_l; - sint32 diff_r = buf_r[s] - state->last_in_r; - state->last_in_l = buf_l[s]; - state->last_in_r = buf_r[s]; - l = ((state->last_out_l * 255) / 256) + diff_l; - r = ((state->last_out_r * 255) / 256) + diff_r; - state->last_out_l = l; - state->last_out_r = r; -// l /= 2; -// r /= 2; - l *= 8; - r *= 8; - if(l > ( 32767)) l = ( 32767); - if(l < (-32768)) l = (-32768); - if(r > ( 32767)) r = ( 32767); - if(r < (-32768)) r = (-32768); - *buf++ = l; - *buf++ = r; - } -} - -///////////////////////////////////////////////////////////////////////////// - -void EMU_CALL _qmix_render(void *state, sint16 *buf, uint32 samples) { -//printf("qmix render %u samples\n",samples); - for(; samples >= RENDERMAX; samples -= RENDERMAX) { - render(QMIXSTATE, buf, RENDERMAX); - if(buf) buf += 2 * RENDERMAX; - } - if(samples) { - render(QMIXSTATE, buf, samples); - } -} - -///////////////////////////////////////////////////////////////////////////// - -void EMU_CALL _qmix_set_sample_rate(void *state, uint32 rate) { - if(rate < 1) rate = 1; - QMIXSTATE->pitchscaler = (65536 * 24000) / rate; -} - -///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// +// qmix - QSound mixer +// +///////////////////////////////////////////////////////////////////////////// + +#include "qmix.h" + +///////////////////////////////////////////////////////////////////////////// + +#define ANTICLICK_TIME (64) +#define ANTICLICK_THRESHHOLD (32) + +///////////////////////////////////////////////////////////////////////////// + +#define RENDERMAX (200) + +///////////////////////////////////////////////////////////////////////////// + +static const sint32 gauss_shuffled_reverse_table[1024] = { + 366,1305, 374, 0, 362,1304, 378, 0, 358,1304, 381, 0, 354,1304, 385, 0, 351,1304, 389, 0, 347,1304, 393, 0, 343,1303, 397, 0, 339,1303, 401, 0, + 336,1303, 405, 0, 332,1302, 410, 0, 328,1302, 414, 0, 325,1301, 418, 0, 321,1300, 422, 0, 318,1300, 426, 0, 314,1299, 430, 0, 311,1298, 434, 0, + 307,1297, 439, 1, 304,1297, 443, 1, 300,1296, 447, 1, 297,1295, 451, 1, 293,1294, 456, 1, 290,1293, 460, 1, 286,1292, 464, 1, 283,1291, 469, 1, + 280,1290, 473, 1, 276,1288, 477, 1, 273,1287, 482, 1, 270,1286, 486, 2, 267,1284, 491, 2, 263,1283, 495, 2, 260,1282, 499, 2, 257,1280, 504, 2, + 254,1279, 508, 2, 251,1277, 513, 2, 248,1275, 517, 3, 245,1274, 522, 3, 242,1272, 527, 3, 239,1270, 531, 3, 236,1269, 536, 3, 233,1267, 540, 4, + 230,1265, 545, 4, 227,1263, 550, 4, 224,1261, 554, 4, 221,1259, 559, 4, 218,1257, 563, 5, 215,1255, 568, 5, 212,1253, 573, 5, 210,1251, 577, 5, + 207,1248, 582, 6, 204,1246, 587, 6, 201,1244, 592, 6, 199,1241, 596, 6, 196,1239, 601, 7, 193,1237, 606, 7, 191,1234, 611, 7, 188,1232, 615, 8, + 186,1229, 620, 8, 183,1227, 625, 8, 180,1224, 630, 9, 178,1221, 635, 9, 175,1219, 640, 9, 173,1216, 644, 10, 171,1213, 649, 10, 168,1210, 654, 10, + 166,1207, 659, 11, 163,1205, 664, 11, 161,1202, 669, 11, 159,1199, 674, 12, 156,1196, 678, 12, 154,1193, 683, 13, 152,1190, 688, 13, 150,1186, 693, 14, + 147,1183, 698, 14, 145,1180, 703, 15, 143,1177, 708, 15, 141,1174, 713, 15, 139,1170, 718, 16, 137,1167, 723, 16, 134,1164, 728, 17, 132,1160, 732, 17, + 130,1157, 737, 18, 128,1153, 742, 19, 126,1150, 747, 19, 124,1146, 752, 20, 122,1143, 757, 20, 120,1139, 762, 21, 118,1136, 767, 21, 117,1132, 772, 22, + 115,1128, 777, 23, 113,1125, 782, 23, 111,1121, 787, 24, 109,1117, 792, 24, 107,1113, 797, 25, 106,1109, 802, 26, 104,1106, 806, 27, 102,1102, 811, 27, + 100,1098, 816, 28, 99,1094, 821, 29, 97,1090, 826, 29, 95,1086, 831, 30, 94,1082, 836, 31, 92,1078, 841, 32, 90,1074, 846, 32, 89,1070, 851, 33, + 87,1066, 855, 34, 86,1061, 860, 35, 84,1057, 865, 36, 83,1053, 870, 36, 81,1049, 875, 37, 80,1045, 880, 38, 78,1040, 884, 39, 77,1036, 889, 40, + 76,1032, 894, 41, 74,1027, 899, 42, 73,1023, 904, 43, 71,1019, 908, 44, 70,1014, 913, 45, 69,1010, 918, 46, 67,1005, 923, 47, 66,1001, 927, 48, + 65, 997, 932, 49, 64, 992, 937, 50, 62, 988, 941, 51, 61, 983, 946, 52, 60, 978, 951, 53, 59, 974, 955, 54, 58, 969, 960, 55, 56, 965, 965, 56, + 55, 960, 969, 58, 54, 955, 974, 59, 53, 951, 978, 60, 52, 946, 983, 61, 51, 941, 988, 62, 50, 937, 992, 64, 49, 932, 997, 65, 48, 927,1001, 66, + 47, 923,1005, 67, 46, 918,1010, 69, 45, 913,1014, 70, 44, 908,1019, 71, 43, 904,1023, 73, 42, 899,1027, 74, 41, 894,1032, 76, 40, 889,1036, 77, + 39, 884,1040, 78, 38, 880,1045, 80, 37, 875,1049, 81, 36, 870,1053, 83, 36, 865,1057, 84, 35, 860,1061, 86, 34, 855,1066, 87, 33, 851,1070, 89, + 32, 846,1074, 90, 32, 841,1078, 92, 31, 836,1082, 94, 30, 831,1086, 95, 29, 826,1090, 97, 29, 821,1094, 99, 28, 816,1098, 100, 27, 811,1102, 102, + 27, 806,1106, 104, 26, 802,1109, 106, 25, 797,1113, 107, 24, 792,1117, 109, 24, 787,1121, 111, 23, 782,1125, 113, 23, 777,1128, 115, 22, 772,1132, 117, + 21, 767,1136, 118, 21, 762,1139, 120, 20, 757,1143, 122, 20, 752,1146, 124, 19, 747,1150, 126, 19, 742,1153, 128, 18, 737,1157, 130, 17, 732,1160, 132, + 17, 728,1164, 134, 16, 723,1167, 137, 16, 718,1170, 139, 15, 713,1174, 141, 15, 708,1177, 143, 15, 703,1180, 145, 14, 698,1183, 147, 14, 693,1186, 150, + 13, 688,1190, 152, 13, 683,1193, 154, 12, 678,1196, 156, 12, 674,1199, 159, 11, 669,1202, 161, 11, 664,1205, 163, 11, 659,1207, 166, 10, 654,1210, 168, + 10, 649,1213, 171, 10, 644,1216, 173, 9, 640,1219, 175, 9, 635,1221, 178, 9, 630,1224, 180, 8, 625,1227, 183, 8, 620,1229, 186, 8, 615,1232, 188, + 7, 611,1234, 191, 7, 606,1237, 193, 7, 601,1239, 196, 6, 596,1241, 199, 6, 592,1244, 201, 6, 587,1246, 204, 6, 582,1248, 207, 5, 577,1251, 210, + 5, 573,1253, 212, 5, 568,1255, 215, 5, 563,1257, 218, 4, 559,1259, 221, 4, 554,1261, 224, 4, 550,1263, 227, 4, 545,1265, 230, 4, 540,1267, 233, + 3, 536,1269, 236, 3, 531,1270, 239, 3, 527,1272, 242, 3, 522,1274, 245, 3, 517,1275, 248, 2, 513,1277, 251, 2, 508,1279, 254, 2, 504,1280, 257, + 2, 499,1282, 260, 2, 495,1283, 263, 2, 491,1284, 267, 2, 486,1286, 270, 1, 482,1287, 273, 1, 477,1288, 276, 1, 473,1290, 280, 1, 469,1291, 283, + 1, 464,1292, 286, 1, 460,1293, 290, 1, 456,1294, 293, 1, 451,1295, 297, 1, 447,1296, 300, 1, 443,1297, 304, 1, 439,1297, 307, 0, 434,1298, 311, + 0, 430,1299, 314, 0, 426,1300, 318, 0, 422,1300, 321, 0, 418,1301, 325, 0, 414,1302, 328, 0, 410,1302, 332, 0, 405,1303, 336, 0, 401,1303, 339, + 0, 397,1303, 343, 0, 393,1304, 347, 0, 389,1304, 351, 0, 385,1304, 354, 0, 381,1304, 358, 0, 378,1304, 362, 0, 374,1305, 366, 0, 370,1305, 370, +}; + +static const sint32 pan_table[33] = { + 0, 724,1024,1254,1448,1619,1774,1916, +2048,2172,2290,2401,2508,2611,2709,2804, +2896,2985,3072,3156,3238,3318,3396,3473, +3547,3620,3692,3762,3831,3899,3966,4031, +4096}; + +///////////////////////////////////////////////////////////////////////////// +// +// Static information +// +sint32 EMU_CALL _qmix_init(void) { return 0; } + +///////////////////////////////////////////////////////////////////////////// +// +// State information +// +#define QMIXSTATE ((struct QMIX_STATE*)(state)) + +struct QMIX_CHAN { + uint32 on; + uint32 startbank; + uint32 startaddr; + uint32 curbank; + uint32 curaddr; + uint32 startloop; + uint32 startend; + uint32 curloop; + uint32 curend; + uint32 phase; + uint32 pitch; + uint32 vol; + uint32 pan; + sint32 current_mix_l; + sint32 current_mix_r; + sint32 sample[4]; + sint32 sample_last_l; + sint32 sample_last_r; + sint32 sample_anticlick_l; + sint32 sample_anticlick_r; + sint32 sample_anticlick_remaining_l; + sint32 sample_anticlick_remaining_r; +}; + +///////////////////////////////////////////////////////////////////////////// + +static EMU_INLINE void get_anticlicked_samples( + struct QMIX_CHAN *chan, sint32 *l, sint32 *r +) { + sint32 out, remain; + remain = chan->sample_anticlick_remaining_l; + if(remain) { + sint32 diff = chan->sample_last_l - chan->sample_anticlick_l; + if(diff < 0) { diff = -diff; } + if(diff < ANTICLICK_THRESHHOLD) { + out = chan->sample_last_l; + chan->sample_anticlick_remaining_l = 0; + } else { + out = ( + chan->sample_last_l * (ANTICLICK_TIME-remain) + + chan->sample_anticlick_l * (remain) + ) / ANTICLICK_TIME; + chan->sample_anticlick_remaining_l--; + } + } else { + out = chan->sample_last_l; + } + *l = out; + + remain = chan->sample_anticlick_remaining_r; + if(remain) { + sint32 diff = chan->sample_last_r - chan->sample_anticlick_r; + if(diff < 0) { diff = -diff; } + if(diff < ANTICLICK_THRESHHOLD) { + out = chan->sample_last_r; + chan->sample_anticlick_remaining_r = 0; + } else { + out = ( + chan->sample_last_r * (ANTICLICK_TIME-remain) + + chan->sample_anticlick_r * (remain) + ) / ANTICLICK_TIME; + chan->sample_anticlick_remaining_r--; + } + } else { + out = chan->sample_last_r; + } + *r = out; + +} + +///////////////////////////////////////////////////////////////////////////// + +static EMU_INLINE void anticlick(struct QMIX_CHAN *chan) { + sint32 l, r; + get_anticlicked_samples(chan, &l, &r); + chan->sample_anticlick_l = l; + chan->sample_anticlick_r = r; + chan->sample_anticlick_remaining_l = ANTICLICK_TIME; + chan->sample_anticlick_remaining_r = ANTICLICK_TIME; +} + +///////////////////////////////////////////////////////////////////////////// + +struct QMIX_STATE { + uint8 *sample_rom; + uint32 sample_rom_size; + uint32 pitchscaler; + struct QMIX_CHAN chan[16]; + sint32 last_in_l; + sint32 last_in_r; + sint32 last_out_l; + sint32 last_out_r; + sint32 acc_l; + sint32 acc_r; +}; + +uint32 EMU_CALL _qmix_get_state_size(void) { + return sizeof(struct QMIX_STATE); +} + +void EMU_CALL _qmix_clear_state(void *state) { + memset(state, 0, sizeof(struct QMIX_STATE)); + + +} + +void EMU_CALL _qmix_set_sample_rom(void *state, void *rom, uint32 size) { + QMIXSTATE->sample_rom = rom; + QMIXSTATE->sample_rom_size = size; +} + +///////////////////////////////////////////////////////////////////////////// + +static EMU_INLINE void chan_advance( + struct QMIX_STATE *state, + struct QMIX_CHAN *chan +) { + uint32 rom_addr = chan->curbank + chan->curaddr; + if(rom_addr >= state->sample_rom_size) rom_addr = 0; + chan->sample[0] = chan->sample[1]; + chan->sample[1] = chan->sample[2]; + chan->sample[2] = chan->sample[3]; + chan->sample[3] = (sint32)((sint8)(state->sample_rom[rom_addr])); + chan->curaddr++; +// FIXME: MAME thinks this is >=, but is it > ? + if(chan->curaddr >= chan->curend) { +// if(!chan->curloop) { +// chan->on = 0; +// chan->curaddr--; +// } else { + chan->curaddr = chan->curend - chan->curloop; +// chan->curaddr -= 1 + chan->curloop; +// } + } + chan->curaddr &= 0xFFFF; +} + +///////////////////////////////////////////////////////////////////////////// + +static EMU_INLINE sint32 chan_get_resampled( + struct QMIX_STATE *state, + struct QMIX_CHAN *chan +) { + sint32 sum; + sint32 phase = chan->phase & 0xFFF; + +// sum = chan->sample[2]; +// sum <<= 8; + + const sint32 *gauss = (sint32*) + (((sint8*)gauss_shuffled_reverse_table) + (phase & 0x0FF0)); + sum = chan->sample[0] * gauss[0]; + sum += chan->sample[1] * gauss[1]; + sum += chan->sample[2] * gauss[2]; + sum += chan->sample[3] * gauss[3]; + sum /= 8; + +// sum = chan->sample[1] * (0x1000-phase); +// sum += chan->sample[2] * ( phase); +// sum >>= 4; + + chan->phase += chan->pitch; + while(chan->phase >= 0x1000) { + chan_advance(state, chan); + chan->phase -= 0x1000; + } + + return sum; +} + +static EMU_INLINE void chan_get_stereo_anticlicked( + struct QMIX_STATE *state, + struct QMIX_CHAN *chan, + sint32 *l, + sint32 *r +) { + if(!chan->on) { + chan->sample_last_l = 0; + chan->sample_last_r = 0; + } else { + sint32 out = chan_get_resampled(state, chan); + chan->sample_last_l = (out * chan->current_mix_l) / 0x8000; + chan->sample_last_r = (out * chan->current_mix_r) / 0x8000; + // if we suddenly keyed off, perform an anticlick here + if(!chan->on) { anticlick(chan); } + } + get_anticlicked_samples(chan, l, r); +} + +///////////////////////////////////////////////////////////////////////////// + +static void recalc_mix(struct QMIX_CHAN *chan) { + sint32 realpan = (chan->pan & 0x3F) - 0x10; + sint32 realvol = chan->vol & 0xFFFF; + if(realpan < 0x00) realpan = 0x00; + if(realpan > 0x20) realpan = 0x20; + +// chan->current_mix_l = realvol << 3; +// chan->current_mix_r = realvol << 3; +// if(realpan < 0x10) { +// chan->current_mix_r *= realpan; +// chan->current_mix_r >>= 4; +// } +// if(realpan > 0x10) { +// chan->current_mix_l *= (0x20-realpan); +// chan->current_mix_l >>= 4; +// } + +// chan->current_mix_l = ((0x20-realpan) * realvol) >> 1; +// chan->current_mix_r = (( realpan) * realvol) >> 1; + + chan->current_mix_l = (realvol * pan_table[0x20-realpan]) / 0x2000; + chan->current_mix_r = (realvol * pan_table[ realpan]) / 0x2000; + + // perform anticlick + //anticlick(chan); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Command handling +// +//#include + +void EMU_CALL _qmix_command(void *state, uint8 cmd, uint16 data) { + struct QMIX_CHAN *chan; + uint32 ch = 0; + uint32 reg = 99; +//printf("qmix command 0x%02X:0x%04X\n",cmd,data); + if(cmd < 0x80) { + reg = cmd & 7; + ch = cmd >> 3; + } else if(cmd < 0x90) { + reg = 8; + ch = cmd - 0x80; + } else if(cmd >= 0xBA && cmd < 0xCA) { + reg = 9; + ch = cmd - 0xBA; + } else { + reg = 99; + ch = 0; + } + chan = QMIXSTATE->chan + ch; + switch(reg) { + case 0: // bank + ch = (ch+1) & 0xF; chan = QMIXSTATE->chan + ch; + //printf("qmix: bank ch%X = %04X\n",ch,data); + chan->startbank = (((uint32)data) & 0x7F) << 16; + break; + case 1: // start + //printf("qmix: start ch%X = %04X\n",ch,data); + chan->startaddr = ((uint32)data) & 0xFFFF; + break; + case 2: // pitch + //printf("qmix: pitch ch%X = %04X\n",ch,data); + chan->pitch = (((uint32)(data & 0xFFFF)) * QMIXSTATE->pitchscaler) / 0x10000; + if (chan->pitch == 0) { + chan->on = 0; + anticlick(chan); + } + break; + case 3: // unknown + break; + case 4: // loop start + //printf("qmix: loop ch%X = %04X\n",ch,data); + chan->startloop = data; + break; + case 5: // end + //printf("qmix: end ch%X = %04X\n",ch,data); + chan->startend = data; + break; + case 6: // volume + //printf("qmix: vol ch%X = %04X\n",ch,data); +//printf("volume=%04X\n",data); +// if(!data) { +// chan->on = 0; +// } else { +// chan->on = 1; +// chan->address = chan->start; +// chan->phase = 0; +// } + //printf("qmix: unknown reg3 ch%X = %04X\n",ch,data); + if(data == 0) { + chan->on = 0; + anticlick(chan); + } else if (chan->on == 0) { + chan->on = 1; + chan->curbank = chan->startbank; + chan->curaddr = chan->startaddr; + chan->curloop = chan->startloop; + chan->curend = chan->startend; + chan->phase = 0; + chan->sample[0] = 0; + chan->sample[1] = 0; + chan->sample[2] = 0; + chan->sample[3] = 0; + anticlick(chan); + } + + chan->vol = data; + recalc_mix(chan); + break; + case 7: // unknown + //printf("qmix: unknown reg7 ch%X = %04X\n",ch,data); + break; + case 8: // pan (0x110-0x130) + //printf("qmix: pan ch%X = %04X\n",ch,data); +//printf("pan=%04X\n",data); + chan->pan = data; + recalc_mix(chan); + break; + case 9: // ADSR? + //printf("qmix: unknown reg9 ch%X = %04X\n",ch,data); + break; + default: + //printf("qmix: unknown reg %02X = %04X\n",cmd,data); + break; + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Rendering +// +static void render( + struct QMIX_STATE *state, + sint16 *buf, + uint32 samples +) { + sint32 buf_l[RENDERMAX]; + sint32 buf_r[RENDERMAX]; + sint32 l, r; + uint32 s; + int ch; + memset(buf_l, 0, 4 * samples); + memset(buf_r, 0, 4 * samples); + for(ch = 0; ch < 16; ch++) { + struct QMIX_CHAN *chan = state->chan + ch; + for(s = 0; s < samples; s++) { + chan_get_stereo_anticlicked(state, chan, &l, &r); + buf_l[s] += l; + buf_r[s] += r; + } + } + if(!buf) return; + for(s = 0; s < samples; s++) { + sint32 diff_l = buf_l[s] - state->last_in_l; + sint32 diff_r = buf_r[s] - state->last_in_r; + state->last_in_l = buf_l[s]; + state->last_in_r = buf_r[s]; + l = ((state->last_out_l * 255) / 256) + diff_l; + r = ((state->last_out_r * 255) / 256) + diff_r; + state->last_out_l = l; + state->last_out_r = r; +// l /= 2; +// r /= 2; + l *= 8; + r *= 8; + if(l > ( 32767)) l = ( 32767); + if(l < (-32768)) l = (-32768); + if(r > ( 32767)) r = ( 32767); + if(r < (-32768)) r = (-32768); + *buf++ = l; + *buf++ = r; + } +} + +///////////////////////////////////////////////////////////////////////////// + +void EMU_CALL _qmix_render(void *state, sint16 *buf, uint32 samples) { +//printf("qmix render %u samples\n",samples); + for(; samples >= RENDERMAX; samples -= RENDERMAX) { + render(QMIXSTATE, buf, RENDERMAX); + if(buf) buf += 2 * RENDERMAX; + } + if(samples) { + render(QMIXSTATE, buf, samples); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void EMU_CALL _qmix_set_sample_rate(void *state, uint32 rate) { + if(rate < 1) rate = 1; + QMIXSTATE->pitchscaler = (65536 * 24000) / rate; +} + +///////////////////////////////////////////////////////////////////////////// diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/qmix.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/qmix.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/qmix.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/qmix.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,29 +1,29 @@ -///////////////////////////////////////////////////////////////////////////// -// -// qmix - QSound mixer -// -///////////////////////////////////////////////////////////////////////////// - -#ifndef __Q_QMIX_H__ -#define __Q_QMIX_H__ - -#include "emuconfig.h" - -#ifdef __cplusplus -extern "C" { -#endif - -sint32 EMU_CALL _qmix_init(void); -uint32 EMU_CALL _qmix_get_state_size(void); -void EMU_CALL _qmix_clear_state(void *state); - -void EMU_CALL _qmix_set_sample_rate(void *state, uint32 rate); -void EMU_CALL _qmix_set_sample_rom(void *state, void *rom, uint32 size); -void EMU_CALL _qmix_command(void *state, uint8 cmd, uint16 data); -void EMU_CALL _qmix_render(void *state, sint16 *buf, uint32 samples); - -#ifdef __cplusplus -} -#endif - -#endif +///////////////////////////////////////////////////////////////////////////// +// +// qmix - QSound mixer +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef __Q_QMIX_H__ +#define __Q_QMIX_H__ + +#include "emuconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +sint32 EMU_CALL _qmix_init(void); +uint32 EMU_CALL _qmix_get_state_size(void); +void EMU_CALL _qmix_clear_state(void *state); + +void EMU_CALL _qmix_set_sample_rate(void *state, uint32 rate); +void EMU_CALL _qmix_set_sample_rom(void *state, void *rom, uint32 size); +void EMU_CALL _qmix_command(void *state, uint8 cmd, uint16 data); +void EMU_CALL _qmix_render(void *state, sint16 *buf, uint32 samples); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rf5C164_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rf5C164_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rf5C164_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rf5C164_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,82 +1,82 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Rf5C164_Emu.h" -#include "scd_pcm.h" - -Rf5C164_Emu::Rf5C164_Emu() { chip = 0; } - -Rf5C164_Emu::~Rf5C164_Emu() -{ - if ( chip ) device_stop_rf5c164( chip ); -} - -int Rf5C164_Emu::set_rate( int clock ) -{ - if ( chip ) - { - device_stop_rf5c164( chip ); - chip = 0; - } - - chip = device_start_rf5c164( clock ); - if ( !chip ) - return 1; - - reset(); - return 0; -} - -void Rf5C164_Emu::reset() -{ - device_reset_rf5c164( chip ); - rf5c164_set_mute_mask( chip, 0 ); -} - -void Rf5C164_Emu::write( int addr, int data ) -{ - rf5c164_w( chip, addr, data ); -} - -void Rf5C164_Emu::write_mem( int addr, int data ) -{ - rf5c164_mem_w( chip, addr, data ); -} - -void Rf5C164_Emu::write_ram( int start, int length, void * data ) -{ - rf5c164_write_ram( chip, start, length, (const UINT8 *) data ); -} - -void Rf5C164_Emu::mute_voices( int mask ) -{ - rf5c164_set_mute_mask( chip, mask ); -} - -void Rf5C164_Emu::run( int pair_count, sample_t* out ) -{ - stream_sample_t bufL[ 1024 ]; - stream_sample_t bufR[ 1024 ]; - stream_sample_t * buffers[2] = { bufL, bufR }; - - while (pair_count > 0) - { - int todo = pair_count; - if (todo > 1024) todo = 1024; - rf5c164_update( chip, buffers, todo ); - - for (int i = 0; i < todo; i++) - { - int output_l = bufL [i]; - int output_r = bufR [i]; - output_l += out [0]; - output_r += out [1]; - if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); - if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); - out [0] = output_l; - out [1] = output_r; - out += 2; - } - - pair_count -= todo; - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Rf5C164_Emu.h" +#include "scd_pcm.h" + +Rf5C164_Emu::Rf5C164_Emu() { chip = 0; } + +Rf5C164_Emu::~Rf5C164_Emu() +{ + if ( chip ) device_stop_rf5c164( chip ); +} + +int Rf5C164_Emu::set_rate( int clock ) +{ + if ( chip ) + { + device_stop_rf5c164( chip ); + chip = 0; + } + + chip = device_start_rf5c164( clock ); + if ( !chip ) + return 1; + + reset(); + return 0; +} + +void Rf5C164_Emu::reset() +{ + device_reset_rf5c164( chip ); + rf5c164_set_mute_mask( chip, 0 ); +} + +void Rf5C164_Emu::write( int addr, int data ) +{ + rf5c164_w( chip, addr, data ); +} + +void Rf5C164_Emu::write_mem( int addr, int data ) +{ + rf5c164_mem_w( chip, addr, data ); +} + +void Rf5C164_Emu::write_ram( int start, int length, void * data ) +{ + rf5c164_write_ram( chip, start, length, (const UINT8 *) data ); +} + +void Rf5C164_Emu::mute_voices( int mask ) +{ + rf5c164_set_mute_mask( chip, mask ); +} + +void Rf5C164_Emu::run( int pair_count, sample_t* out ) +{ + stream_sample_t bufL[ 1024 ]; + stream_sample_t bufR[ 1024 ]; + stream_sample_t * buffers[2] = { bufL, bufR }; + + while (pair_count > 0) + { + int todo = pair_count; + if (todo > 1024) todo = 1024; + rf5c164_update( chip, buffers, todo ); + + for (int i = 0; i < todo; i++) + { + int output_l = bufL [i]; + int output_r = bufR [i]; + output_l += out [0]; + output_r += out [1]; + if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); + if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); + out [0] = output_l; + out [1] = output_r; + out += 2; + } + + pair_count -= todo; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rf5C164_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rf5C164_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rf5C164_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rf5C164_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,39 +1,39 @@ -// RF5C164 sound chip emulator interface - -// Game_Music_Emu $vers -#ifndef RF5C164_EMU_H -#define RF5C164_EMU_H - -class Rf5C164_Emu { - void* chip; -public: - Rf5C164_Emu(); - ~Rf5C164_Emu(); - - // Sets output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - int set_rate( int clock ); - - // Resets to power-up state - void reset(); - - // Mutes voice n if bit n (1 << n) of mask is set - enum { channel_count = 8 }; - void mute_voices( int mask ); - - // Writes data to addr - void write( int addr, int data ); - - // Writes to memory - void write_mem( int addr, int data ); - - // Writes length bytes from data at start offset in RAM - void write_ram( int start, int length, void * data ); - - // Runs and writes pair_count*2 samples to output - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif +// RF5C164 sound chip emulator interface + +// Game_Music_Emu $vers +#ifndef RF5C164_EMU_H +#define RF5C164_EMU_H + +class Rf5C164_Emu { + void* chip; +public: + Rf5C164_Emu(); + ~Rf5C164_Emu(); + + // Sets output sample rate and chip clock rates, in Hz. Returns non-zero + // if error. + int set_rate( int clock ); + + // Resets to power-up state + void reset(); + + // Mutes voice n if bit n (1 << n) of mask is set + enum { channel_count = 8 }; + void mute_voices( int mask ); + + // Writes data to addr + void write( int addr, int data ); + + // Writes to memory + void write_mem( int addr, int data ); + + // Writes length bytes from data at start offset in RAM + void write_ram( int start, int length, void * data ); + + // Runs and writes pair_count*2 samples to output + typedef short sample_t; + enum { out_chan_count = 2 }; // stereo + void run( int pair_count, sample_t* out ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/rf5c68.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/rf5c68.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/rf5c68.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/rf5c68.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,448 +1,448 @@ -/*********************************************************/ -/* ricoh RF5C68(or clone) PCM controller */ -/*********************************************************/ - -#include -#include -//#include "sndintrf.h" -//#include "streams.h" -#include "rf5c68.h" -#include - -#undef NULL -#define NULL ((void *)0) - - -#define NUM_CHANNELS (8) -#define WRITES_PER_SAMPLE 12 - - - -typedef struct _pcm_channel pcm_channel; -struct _pcm_channel -{ - UINT8 enable; - UINT8 env; - UINT8 pan; - UINT8 start; - UINT32 addr; - UINT16 step; - UINT16 loopst; - UINT8 Muted; -}; - -typedef struct _mem_stream mem_stream; -struct _mem_stream -{ - UINT32 BaseAddr; - UINT32 EndAddr; - UINT32 CurAddr; - const UINT8* MemPnt; -}; - - -typedef struct _rf5c68_state rf5c68_state; -struct _rf5c68_state -{ - //sound_stream * stream; - pcm_channel chan[NUM_CHANNELS]; - UINT8 cbank; - UINT8 wbank; - UINT8 enable; - UINT32 datasize; - UINT8* data; - //void (*sample_callback)(running_device* device,int channel); - mem_stream memstrm; -}; - - -static void rf5c68_mem_stream_flush(rf5c68_state *chip); - -/*INLINE rf5c68_state *get_safe_token(const device_config *device) -{ - assert(device != NULL); - assert(device->token != NULL); - assert(device->type == SOUND); - assert(sound_get_type(device) == SOUND_RF5C68); - return (rf5c68_state *)device->token; -}*/ - -/************************************************/ -/* RF5C68 stream update */ -/************************************************/ - -static void memstream_sample_check(rf5c68_state *chip, UINT32 addr) -{ - mem_stream* ms = &chip->memstrm; - - if (addr >= ms->CurAddr) - { - if (addr - ms->CurAddr <= WRITES_PER_SAMPLE * 5) - { - ms->CurAddr -= WRITES_PER_SAMPLE * 2; - if (ms->CurAddr < ms->BaseAddr) - ms->CurAddr = ms->BaseAddr; - } - } - else - { - if (ms->CurAddr - addr <= WRITES_PER_SAMPLE * 4) - { - rf5c68_mem_stream_flush(chip); - } - } - - return; -} - -//static STREAM_UPDATE( rf5c68_update ) -void rf5c68_update(void *_chip, stream_sample_t **outputs, int samples) -{ - //rf5c68_state *chip = (rf5c68_state *)param; - rf5c68_state *chip = (rf5c68_state *) _chip; - mem_stream* ms = &chip->memstrm; - stream_sample_t *left = outputs[0]; - stream_sample_t *right = outputs[1]; - int i, j; - - /* start with clean buffers */ - memset(left, 0, samples * sizeof(*left)); - memset(right, 0, samples * sizeof(*right)); - - /* bail if not enabled */ - if (!chip->enable) - return; - - /* loop over channels */ - for (i = 0; i < NUM_CHANNELS; i++) - { - pcm_channel *chan = &chip->chan[i]; - - /* if this channel is active, accumulate samples */ - if (chan->enable && ! chan->Muted) - { - int lv = (chan->pan & 0x0f) * chan->env; - int rv = ((chan->pan >> 4) & 0x0f) * chan->env; - - /* loop over the sample buffer */ - for (j = 0; j < samples; j++) - { - int sample; - - /* trigger sample callback */ - /*if(chip->sample_callback) - { - if(((chan->addr >> 11) & 0xfff) == 0xfff) - chip->sample_callback(chip->device,((chan->addr >> 11)/0x2000)); - }*/ - - memstream_sample_check(chip, (chan->addr >> 11) & 0xffff); - /* fetch the sample and handle looping */ - sample = chip->data[(chan->addr >> 11) & 0xffff]; - if (sample == 0xff) - { - chan->addr = chan->loopst << 11; - sample = chip->data[(chan->addr >> 11) & 0xffff]; - - /* if we loop to a loop point, we're effectively dead */ - if (sample == 0xff) - break; - } - chan->addr += chan->step; - - /* add to the buffer */ - if (sample & 0x80) - { - sample &= 0x7f; - left[j] += (sample * lv) >> 5; - right[j] += (sample * rv) >> 5; - } - else - { - left[j] -= (sample * lv) >> 5; - right[j] -= (sample * rv) >> 5; - } - } - } - } - - if (samples && ms->CurAddr < ms->EndAddr) - { - i = WRITES_PER_SAMPLE * samples; - if (ms->CurAddr + i > ms->EndAddr) - i = ms->EndAddr - ms->CurAddr; - - memcpy(chip->data + ms->CurAddr, ms->MemPnt + (ms->CurAddr - ms->BaseAddr), i); - ms->CurAddr += i; - } - - // I think, this is completely useless - /* now clamp and shift the result (output is only 10 bits) */ - /*for (j = 0; j < samples; j++) - { - stream_sample_t temp; - - temp = left[j]; - if (temp > 32767) temp = 32767; - else if (temp < -32768) temp = -32768; - left[j] = temp & ~0x3f; - - temp = right[j]; - if (temp > 32767) temp = 32767; - else if (temp < -32768) temp = -32768; - right[j] = temp & ~0x3f; - }*/ -} - - -/************************************************/ -/* RF5C68 start */ -/************************************************/ - -//static DEVICE_START( rf5c68 ) -void * device_start_rf5c68() -{ - //const rf5c68_interface* intf = (const rf5c68_interface*)device->baseconfig().static_config(); - - /* allocate memory for the chip */ - //rf5c68_state *chip = get_safe_token(device); - rf5c68_state *chip; - int chn; - - chip = (rf5c68_state *) malloc(sizeof(rf5c68_state)); - if (!chip) return chip; - - chip->datasize = 0x10000; - chip->data = (UINT8*)malloc(chip->datasize); - - /* allocate the stream */ - //chip->stream = stream_create(device, 0, 2, device->clock / 384, chip, rf5c68_update); - - /* set up callback */ - /*if(intf != NULL) - chip->sample_callback = intf->sample_end_callback; - else - chip->sample_callback = NULL;*/ - for (chn = 0; chn < NUM_CHANNELS; chn ++) - chip->chan[chn].Muted = 0x00; - - return chip; -} - -void device_stop_rf5c68(void *_chip) -{ - rf5c68_state *chip = (rf5c68_state *) _chip; - free(chip->data); chip->data = NULL; - free(chip); -} - -void device_reset_rf5c68(void *_chip) -{ - rf5c68_state *chip = (rf5c68_state *) _chip; - int i; - pcm_channel* chan; - mem_stream* ms = &chip->memstrm; - - // Clear the PCM memory. - memset(chip->data, 0x00, chip->datasize); - - chip->enable = 0; - chip->cbank = 0; - chip->wbank = 0; - - /* clear channel registers */ - for (i = 0; i < NUM_CHANNELS; i ++) - { - chan = &chip->chan[i]; - chan->enable = 0; - chan->env = 0; - chan->pan = 0; - chan->start = 0; - chan->addr = 0; - chan->step = 0; - chan->loopst = 0; - } - - ms->BaseAddr = 0x0000; - ms->CurAddr = 0x0000; - ms->EndAddr = 0x0000; - ms->MemPnt = NULL; -} - -/************************************************/ -/* RF5C68 write register */ -/************************************************/ - -//WRITE8_DEVICE_HANDLER( rf5c68_w ) -void rf5c68_w(void *_chip, offs_t offset, UINT8 data) -{ - //rf5c68_state *chip = get_safe_token(device); - rf5c68_state *chip = (rf5c68_state *) _chip; - pcm_channel *chan = &chip->chan[chip->cbank]; - int i; - - /* force the stream to update first */ - //stream_update(chip->stream); - - /* switch off the address */ - switch (offset) - { - case 0x00: /* envelope */ - chan->env = data; - break; - - case 0x01: /* pan */ - chan->pan = data; - break; - - case 0x02: /* FDL */ - chan->step = (chan->step & 0xff00) | (data & 0x00ff); - break; - - case 0x03: /* FDH */ - chan->step = (chan->step & 0x00ff) | ((data << 8) & 0xff00); - break; - - case 0x04: /* LSL */ - chan->loopst = (chan->loopst & 0xff00) | (data & 0x00ff); - break; - - case 0x05: /* LSH */ - chan->loopst = (chan->loopst & 0x00ff) | ((data << 8) & 0xff00); - break; - - case 0x06: /* ST */ - chan->start = data; - if (!chan->enable) - chan->addr = chan->start << (8 + 11); - break; - - case 0x07: /* control reg */ - chip->enable = (data >> 7) & 1; - if (data & 0x40) - chip->cbank = data & 7; - else - chip->wbank = data & 15; - break; - - case 0x08: /* channel on/off reg */ - for (i = 0; i < 8; i++) - { - chip->chan[i].enable = (~data >> i) & 1; - if (!chip->chan[i].enable) - chip->chan[i].addr = chip->chan[i].start << (8 + 11); - } - break; - } -} - - -/************************************************/ -/* RF5C68 read memory */ -/************************************************/ - -//READ8_DEVICE_HANDLER( rf5c68_mem_r ) -UINT8 rf5c68_mem_r(void *_chip, offs_t offset) -{ - //rf5c68_state *chip = get_safe_token(device); - rf5c68_state *chip = (rf5c68_state *) _chip; - return chip->data[chip->wbank * 0x1000 + offset]; -} - - -/************************************************/ -/* RF5C68 write memory */ -/************************************************/ - -//WRITE8_DEVICE_HANDLER( rf5c68_mem_w ) -void rf5c68_mem_w(void *_chip, offs_t offset, UINT8 data) -{ - //rf5c68_state *chip = get_safe_token(device); - rf5c68_state *chip = (rf5c68_state *) _chip; - rf5c68_mem_stream_flush(chip); - chip->data[chip->wbank * 0x1000 | offset] = data; -} - -static void rf5c68_mem_stream_flush(rf5c68_state *chip) -{ - mem_stream* ms = &chip->memstrm; - - if (ms->CurAddr >= ms->EndAddr) - return; - - memcpy(chip->data + ms->CurAddr, ms->MemPnt + (ms->CurAddr - ms->BaseAddr), ms->EndAddr - ms->CurAddr); - ms->CurAddr = ms->EndAddr; - - return; -} - -void rf5c68_write_ram(void *_chip, offs_t DataStart, offs_t DataLength, const UINT8* RAMData) -{ - rf5c68_state *chip = (rf5c68_state *) _chip; - mem_stream* ms = &chip->memstrm; - UINT16 BytCnt; - - if (DataStart >= chip->datasize) - return; - if (DataStart + DataLength > chip->datasize) - DataLength = chip->datasize - DataStart; - - //memcpy(chip->data + (chip->wbank * 0x1000 | DataStart), RAMData, DataLength); - - rf5c68_mem_stream_flush(chip); - - ms->BaseAddr = chip->wbank * 0x1000 | DataStart; - ms->CurAddr = ms->BaseAddr; - ms->EndAddr = ms->BaseAddr + DataLength; - ms->MemPnt = RAMData; - - BytCnt = WRITES_PER_SAMPLE; - if (ms->CurAddr + BytCnt > ms->EndAddr) - BytCnt = ms->EndAddr - ms->CurAddr; - - memcpy(chip->data + ms->CurAddr, ms->MemPnt + (ms->CurAddr - ms->BaseAddr), BytCnt); - ms->CurAddr += BytCnt; - - return; -} - - -void rf5c68_set_mute_mask(void *_chip, UINT32 MuteMask) -{ - rf5c68_state *chip = (rf5c68_state *) _chip; - unsigned char CurChn; - - for (CurChn = 0; CurChn < NUM_CHANNELS; CurChn ++) - chip->chan[CurChn].Muted = (MuteMask >> CurChn) & 0x01; - - return; -} - - - -/************************************************************************** - * Generic get_info - **************************************************************************/ - -/*DEVICE_GET_INFO( rf5c68 ) -{ - switch (state) - { - // --- the following bits of info are returned as 64-bit signed integers --- - case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(rf5c68_state); break; - - // --- the following bits of info are returned as pointers to data or functions --- - case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( rf5c68 ); break; - case DEVINFO_FCT_STOP: // Nothing break; - case DEVINFO_FCT_RESET: // Nothing break; - - // --- the following bits of info are returned as NULL-terminated strings --- - case DEVINFO_STR_NAME: strcpy(info->s, "RF5C68"); break; - case DEVINFO_STR_FAMILY: strcpy(info->s, "Ricoh PCM"); break; - case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; - case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; - case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; - } -}*/ - -/**************** end of file ****************/ +/*********************************************************/ +/* ricoh RF5C68(or clone) PCM controller */ +/*********************************************************/ + +#include +#include +//#include "sndintrf.h" +//#include "streams.h" +#include "rf5c68.h" +#include + +#undef NULL +#define NULL ((void *)0) + + +#define NUM_CHANNELS (8) +#define WRITES_PER_SAMPLE 12 + + + +typedef struct _pcm_channel pcm_channel; +struct _pcm_channel +{ + UINT8 enable; + UINT8 env; + UINT8 pan; + UINT8 start; + UINT32 addr; + UINT16 step; + UINT16 loopst; + UINT8 Muted; +}; + +typedef struct _mem_stream mem_stream; +struct _mem_stream +{ + UINT32 BaseAddr; + UINT32 EndAddr; + UINT32 CurAddr; + const UINT8* MemPnt; +}; + + +typedef struct _rf5c68_state rf5c68_state; +struct _rf5c68_state +{ + //sound_stream * stream; + pcm_channel chan[NUM_CHANNELS]; + UINT8 cbank; + UINT8 wbank; + UINT8 enable; + UINT32 datasize; + UINT8* data; + //void (*sample_callback)(running_device* device,int channel); + mem_stream memstrm; +}; + + +static void rf5c68_mem_stream_flush(rf5c68_state *chip); + +/*INLINE rf5c68_state *get_safe_token(const device_config *device) +{ + assert(device != NULL); + assert(device->token != NULL); + assert(device->type == SOUND); + assert(sound_get_type(device) == SOUND_RF5C68); + return (rf5c68_state *)device->token; +}*/ + +/************************************************/ +/* RF5C68 stream update */ +/************************************************/ + +static void memstream_sample_check(rf5c68_state *chip, UINT32 addr) +{ + mem_stream* ms = &chip->memstrm; + + if (addr >= ms->CurAddr) + { + if (addr - ms->CurAddr <= WRITES_PER_SAMPLE * 5) + { + ms->CurAddr -= WRITES_PER_SAMPLE * 2; + if (ms->CurAddr < ms->BaseAddr) + ms->CurAddr = ms->BaseAddr; + } + } + else + { + if (ms->CurAddr - addr <= WRITES_PER_SAMPLE * 4) + { + rf5c68_mem_stream_flush(chip); + } + } + + return; +} + +//static STREAM_UPDATE( rf5c68_update ) +void rf5c68_update(void *_chip, stream_sample_t **outputs, int samples) +{ + //rf5c68_state *chip = (rf5c68_state *)param; + rf5c68_state *chip = (rf5c68_state *) _chip; + mem_stream* ms = &chip->memstrm; + stream_sample_t *left = outputs[0]; + stream_sample_t *right = outputs[1]; + int i, j; + + /* start with clean buffers */ + memset(left, 0, samples * sizeof(*left)); + memset(right, 0, samples * sizeof(*right)); + + /* bail if not enabled */ + if (!chip->enable) + return; + + /* loop over channels */ + for (i = 0; i < NUM_CHANNELS; i++) + { + pcm_channel *chan = &chip->chan[i]; + + /* if this channel is active, accumulate samples */ + if (chan->enable && ! chan->Muted) + { + int lv = (chan->pan & 0x0f) * chan->env; + int rv = ((chan->pan >> 4) & 0x0f) * chan->env; + + /* loop over the sample buffer */ + for (j = 0; j < samples; j++) + { + int sample; + + /* trigger sample callback */ + /*if(chip->sample_callback) + { + if(((chan->addr >> 11) & 0xfff) == 0xfff) + chip->sample_callback(chip->device,((chan->addr >> 11)/0x2000)); + }*/ + + memstream_sample_check(chip, (chan->addr >> 11) & 0xffff); + /* fetch the sample and handle looping */ + sample = chip->data[(chan->addr >> 11) & 0xffff]; + if (sample == 0xff) + { + chan->addr = chan->loopst << 11; + sample = chip->data[(chan->addr >> 11) & 0xffff]; + + /* if we loop to a loop point, we're effectively dead */ + if (sample == 0xff) + break; + } + chan->addr += chan->step; + + /* add to the buffer */ + if (sample & 0x80) + { + sample &= 0x7f; + left[j] += (sample * lv) >> 5; + right[j] += (sample * rv) >> 5; + } + else + { + left[j] -= (sample * lv) >> 5; + right[j] -= (sample * rv) >> 5; + } + } + } + } + + if (samples && ms->CurAddr < ms->EndAddr) + { + i = WRITES_PER_SAMPLE * samples; + if (ms->CurAddr + i > ms->EndAddr) + i = ms->EndAddr - ms->CurAddr; + + memcpy(chip->data + ms->CurAddr, ms->MemPnt + (ms->CurAddr - ms->BaseAddr), i); + ms->CurAddr += i; + } + + // I think, this is completely useless + /* now clamp and shift the result (output is only 10 bits) */ + /*for (j = 0; j < samples; j++) + { + stream_sample_t temp; + + temp = left[j]; + if (temp > 32767) temp = 32767; + else if (temp < -32768) temp = -32768; + left[j] = temp & ~0x3f; + + temp = right[j]; + if (temp > 32767) temp = 32767; + else if (temp < -32768) temp = -32768; + right[j] = temp & ~0x3f; + }*/ +} + + +/************************************************/ +/* RF5C68 start */ +/************************************************/ + +//static DEVICE_START( rf5c68 ) +void * device_start_rf5c68() +{ + //const rf5c68_interface* intf = (const rf5c68_interface*)device->baseconfig().static_config(); + + /* allocate memory for the chip */ + //rf5c68_state *chip = get_safe_token(device); + rf5c68_state *chip; + int chn; + + chip = (rf5c68_state *) malloc(sizeof(rf5c68_state)); + if (!chip) return chip; + + chip->datasize = 0x10000; + chip->data = (UINT8*)malloc(chip->datasize); + + /* allocate the stream */ + //chip->stream = stream_create(device, 0, 2, device->clock / 384, chip, rf5c68_update); + + /* set up callback */ + /*if(intf != NULL) + chip->sample_callback = intf->sample_end_callback; + else + chip->sample_callback = NULL;*/ + for (chn = 0; chn < NUM_CHANNELS; chn ++) + chip->chan[chn].Muted = 0x00; + + return chip; +} + +void device_stop_rf5c68(void *_chip) +{ + rf5c68_state *chip = (rf5c68_state *) _chip; + free(chip->data); chip->data = NULL; + free(chip); +} + +void device_reset_rf5c68(void *_chip) +{ + rf5c68_state *chip = (rf5c68_state *) _chip; + int i; + pcm_channel* chan; + mem_stream* ms = &chip->memstrm; + + // Clear the PCM memory. + memset(chip->data, 0x00, chip->datasize); + + chip->enable = 0; + chip->cbank = 0; + chip->wbank = 0; + + /* clear channel registers */ + for (i = 0; i < NUM_CHANNELS; i ++) + { + chan = &chip->chan[i]; + chan->enable = 0; + chan->env = 0; + chan->pan = 0; + chan->start = 0; + chan->addr = 0; + chan->step = 0; + chan->loopst = 0; + } + + ms->BaseAddr = 0x0000; + ms->CurAddr = 0x0000; + ms->EndAddr = 0x0000; + ms->MemPnt = NULL; +} + +/************************************************/ +/* RF5C68 write register */ +/************************************************/ + +//WRITE8_DEVICE_HANDLER( rf5c68_w ) +void rf5c68_w(void *_chip, offs_t offset, UINT8 data) +{ + //rf5c68_state *chip = get_safe_token(device); + rf5c68_state *chip = (rf5c68_state *) _chip; + pcm_channel *chan = &chip->chan[chip->cbank]; + int i; + + /* force the stream to update first */ + //stream_update(chip->stream); + + /* switch off the address */ + switch (offset) + { + case 0x00: /* envelope */ + chan->env = data; + break; + + case 0x01: /* pan */ + chan->pan = data; + break; + + case 0x02: /* FDL */ + chan->step = (chan->step & 0xff00) | (data & 0x00ff); + break; + + case 0x03: /* FDH */ + chan->step = (chan->step & 0x00ff) | ((data << 8) & 0xff00); + break; + + case 0x04: /* LSL */ + chan->loopst = (chan->loopst & 0xff00) | (data & 0x00ff); + break; + + case 0x05: /* LSH */ + chan->loopst = (chan->loopst & 0x00ff) | ((data << 8) & 0xff00); + break; + + case 0x06: /* ST */ + chan->start = data; + if (!chan->enable) + chan->addr = chan->start << (8 + 11); + break; + + case 0x07: /* control reg */ + chip->enable = (data >> 7) & 1; + if (data & 0x40) + chip->cbank = data & 7; + else + chip->wbank = data & 15; + break; + + case 0x08: /* channel on/off reg */ + for (i = 0; i < 8; i++) + { + chip->chan[i].enable = (~data >> i) & 1; + if (!chip->chan[i].enable) + chip->chan[i].addr = chip->chan[i].start << (8 + 11); + } + break; + } +} + + +/************************************************/ +/* RF5C68 read memory */ +/************************************************/ + +//READ8_DEVICE_HANDLER( rf5c68_mem_r ) +UINT8 rf5c68_mem_r(void *_chip, offs_t offset) +{ + //rf5c68_state *chip = get_safe_token(device); + rf5c68_state *chip = (rf5c68_state *) _chip; + return chip->data[chip->wbank * 0x1000 + offset]; +} + + +/************************************************/ +/* RF5C68 write memory */ +/************************************************/ + +//WRITE8_DEVICE_HANDLER( rf5c68_mem_w ) +void rf5c68_mem_w(void *_chip, offs_t offset, UINT8 data) +{ + //rf5c68_state *chip = get_safe_token(device); + rf5c68_state *chip = (rf5c68_state *) _chip; + rf5c68_mem_stream_flush(chip); + chip->data[chip->wbank * 0x1000 | offset] = data; +} + +static void rf5c68_mem_stream_flush(rf5c68_state *chip) +{ + mem_stream* ms = &chip->memstrm; + + if (ms->CurAddr >= ms->EndAddr) + return; + + memcpy(chip->data + ms->CurAddr, ms->MemPnt + (ms->CurAddr - ms->BaseAddr), ms->EndAddr - ms->CurAddr); + ms->CurAddr = ms->EndAddr; + + return; +} + +void rf5c68_write_ram(void *_chip, offs_t DataStart, offs_t DataLength, const UINT8* RAMData) +{ + rf5c68_state *chip = (rf5c68_state *) _chip; + mem_stream* ms = &chip->memstrm; + UINT16 BytCnt; + + if (DataStart >= chip->datasize) + return; + if (DataStart + DataLength > chip->datasize) + DataLength = chip->datasize - DataStart; + + //memcpy(chip->data + (chip->wbank * 0x1000 | DataStart), RAMData, DataLength); + + rf5c68_mem_stream_flush(chip); + + ms->BaseAddr = chip->wbank * 0x1000 | DataStart; + ms->CurAddr = ms->BaseAddr; + ms->EndAddr = ms->BaseAddr + DataLength; + ms->MemPnt = RAMData; + + BytCnt = WRITES_PER_SAMPLE; + if (ms->CurAddr + BytCnt > ms->EndAddr) + BytCnt = ms->EndAddr - ms->CurAddr; + + memcpy(chip->data + ms->CurAddr, ms->MemPnt + (ms->CurAddr - ms->BaseAddr), BytCnt); + ms->CurAddr += BytCnt; + + return; +} + + +void rf5c68_set_mute_mask(void *_chip, UINT32 MuteMask) +{ + rf5c68_state *chip = (rf5c68_state *) _chip; + unsigned char CurChn; + + for (CurChn = 0; CurChn < NUM_CHANNELS; CurChn ++) + chip->chan[CurChn].Muted = (MuteMask >> CurChn) & 0x01; + + return; +} + + + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +/*DEVICE_GET_INFO( rf5c68 ) +{ + switch (state) + { + // --- the following bits of info are returned as 64-bit signed integers --- + case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(rf5c68_state); break; + + // --- the following bits of info are returned as pointers to data or functions --- + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( rf5c68 ); break; + case DEVINFO_FCT_STOP: // Nothing break; + case DEVINFO_FCT_RESET: // Nothing break; + + // --- the following bits of info are returned as NULL-terminated strings --- + case DEVINFO_STR_NAME: strcpy(info->s, "RF5C68"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Ricoh PCM"); break; + case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; + } +}*/ + +/**************** end of file ****************/ diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rf5C68_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rf5C68_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rf5C68_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rf5C68_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,82 +1,82 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Rf5C68_Emu.h" -#include "rf5c68.h" - -Rf5C68_Emu::Rf5C68_Emu() { chip = 0; } - -Rf5C68_Emu::~Rf5C68_Emu() -{ - if ( chip ) device_stop_rf5c68( chip ); -} - -int Rf5C68_Emu::set_rate() -{ - if ( chip ) - { - device_stop_rf5c68( chip ); - chip = 0; - } - - chip = device_start_rf5c68(); - if ( !chip ) - return 1; - - reset(); - return 0; -} - -void Rf5C68_Emu::reset() -{ - device_reset_rf5c68( chip ); - rf5c68_set_mute_mask( chip, 0 ); -} - -void Rf5C68_Emu::write( int addr, int data ) -{ - rf5c68_w( chip, addr, data ); -} - -void Rf5C68_Emu::write_mem( int addr, int data ) -{ - rf5c68_mem_w( chip, addr, data ); -} - -void Rf5C68_Emu::write_ram( int start, int length, void * data ) -{ - rf5c68_write_ram( chip, start, length, (const UINT8 *) data ); -} - -void Rf5C68_Emu::mute_voices( int mask ) -{ - rf5c68_set_mute_mask( chip, mask ); -} - -void Rf5C68_Emu::run( int pair_count, sample_t* out ) -{ - stream_sample_t bufL[ 1024 ]; - stream_sample_t bufR[ 1024 ]; - stream_sample_t * buffers[2] = { bufL, bufR }; - - while (pair_count > 0) - { - int todo = pair_count; - if (todo > 1024) todo = 1024; - rf5c68_update( chip, buffers, todo ); - - for (int i = 0; i < todo; i++) - { - int output_l = bufL [i]; - int output_r = bufR [i]; - output_l += out [0]; - output_r += out [1]; - if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); - if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); - out [0] = output_l; - out [1] = output_r; - out += 2; - } - - pair_count -= todo; - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Rf5C68_Emu.h" +#include "rf5c68.h" + +Rf5C68_Emu::Rf5C68_Emu() { chip = 0; } + +Rf5C68_Emu::~Rf5C68_Emu() +{ + if ( chip ) device_stop_rf5c68( chip ); +} + +int Rf5C68_Emu::set_rate() +{ + if ( chip ) + { + device_stop_rf5c68( chip ); + chip = 0; + } + + chip = device_start_rf5c68(); + if ( !chip ) + return 1; + + reset(); + return 0; +} + +void Rf5C68_Emu::reset() +{ + device_reset_rf5c68( chip ); + rf5c68_set_mute_mask( chip, 0 ); +} + +void Rf5C68_Emu::write( int addr, int data ) +{ + rf5c68_w( chip, addr, data ); +} + +void Rf5C68_Emu::write_mem( int addr, int data ) +{ + rf5c68_mem_w( chip, addr, data ); +} + +void Rf5C68_Emu::write_ram( int start, int length, void * data ) +{ + rf5c68_write_ram( chip, start, length, (const UINT8 *) data ); +} + +void Rf5C68_Emu::mute_voices( int mask ) +{ + rf5c68_set_mute_mask( chip, mask ); +} + +void Rf5C68_Emu::run( int pair_count, sample_t* out ) +{ + stream_sample_t bufL[ 1024 ]; + stream_sample_t bufR[ 1024 ]; + stream_sample_t * buffers[2] = { bufL, bufR }; + + while (pair_count > 0) + { + int todo = pair_count; + if (todo > 1024) todo = 1024; + rf5c68_update( chip, buffers, todo ); + + for (int i = 0; i < todo; i++) + { + int output_l = bufL [i]; + int output_r = bufR [i]; + output_l += out [0]; + output_r += out [1]; + if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); + if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); + out [0] = output_l; + out [1] = output_r; + out += 2; + } + + pair_count -= todo; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rf5C68_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rf5C68_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rf5C68_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rf5C68_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,39 +1,39 @@ -// RF5C68 sound chip emulator interface - -// Game_Music_Emu $vers -#ifndef RF5C68_EMU_H -#define RF5C68_EMU_H - -class Rf5C68_Emu { - void* chip; -public: - Rf5C68_Emu(); - ~Rf5C68_Emu(); - - // Sets output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - int set_rate(); - - // Resets to power-up state - void reset(); - - // Mutes voice n if bit n (1 << n) of mask is set - enum { channel_count = 8 }; - void mute_voices( int mask ); - - // Writes data to addr - void write( int addr, int data ); - - // Writes to memory - void write_mem( int addr, int data ); - - // Writes length bytes from data at start offset in RAM - void write_ram( int start, int length, void * data ); - - // Runs and writes pair_count*2 samples to output - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif +// RF5C68 sound chip emulator interface + +// Game_Music_Emu $vers +#ifndef RF5C68_EMU_H +#define RF5C68_EMU_H + +class Rf5C68_Emu { + void* chip; +public: + Rf5C68_Emu(); + ~Rf5C68_Emu(); + + // Sets output sample rate and chip clock rates, in Hz. Returns non-zero + // if error. + int set_rate(); + + // Resets to power-up state + void reset(); + + // Mutes voice n if bit n (1 << n) of mask is set + enum { channel_count = 8 }; + void mute_voices( int mask ); + + // Writes data to addr + void write( int addr, int data ); + + // Writes to memory + void write_mem( int addr, int data ); + + // Writes length bytes from data at start offset in RAM + void write_ram( int start, int length, void * data ); + + // Runs and writes pair_count*2 samples to output + typedef short sample_t; + enum { out_chan_count = 2 }; // stereo + void run( int pair_count, sample_t* out ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/rf5c68.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/rf5c68.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/rf5c68.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/rf5c68.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,38 +1,38 @@ -/*********************************************************/ -/* ricoh RF5C68(or clone) PCM controller */ -/*********************************************************/ - -#pragma once - -#include "mamedef.h" - -/******************************************/ -/*WRITE8_DEVICE_HANDLER( rf5c68_w ); - -READ8_DEVICE_HANDLER( rf5c68_mem_r ); -WRITE8_DEVICE_HANDLER( rf5c68_mem_w ); - -DEVICE_GET_INFO( rf5c68 ); -#define SOUND_RF5C68 DEVICE_GET_INFO_NAME( rf5c68 )*/ - -#ifdef __cplusplus -extern "C" { -#endif - -void rf5c68_update(void *chip, stream_sample_t **outputs, int samples); - -void * device_start_rf5c68(); -void device_stop_rf5c68(void *chip); -void device_reset_rf5c68(void *chip); - -void rf5c68_w(void *chip, offs_t offset, UINT8 data); - -UINT8 rf5c68_mem_r(void *chip, offs_t offset); -void rf5c68_mem_w(void *chip, offs_t offset, UINT8 data); -void rf5c68_write_ram(void *chip, offs_t DataStart, offs_t DataLength, const UINT8* RAMData); - -void rf5c68_set_mute_mask(void *chip, UINT32 MuteMask); - -#ifdef __cplusplus -} -#endif +/*********************************************************/ +/* ricoh RF5C68(or clone) PCM controller */ +/*********************************************************/ + +#pragma once + +#include "mamedef.h" + +/******************************************/ +/*WRITE8_DEVICE_HANDLER( rf5c68_w ); + +READ8_DEVICE_HANDLER( rf5c68_mem_r ); +WRITE8_DEVICE_HANDLER( rf5c68_mem_w ); + +DEVICE_GET_INFO( rf5c68 ); +#define SOUND_RF5C68 DEVICE_GET_INFO_NAME( rf5c68 )*/ + +#ifdef __cplusplus +extern "C" { +#endif + +void rf5c68_update(void *chip, stream_sample_t **outputs, int samples); + +void * device_start_rf5c68(); +void device_stop_rf5c68(void *chip); +void device_reset_rf5c68(void *chip); + +void rf5c68_w(void *chip, offs_t offset, UINT8 data); + +UINT8 rf5c68_mem_r(void *chip, offs_t offset); +void rf5c68_mem_w(void *chip, offs_t offset, UINT8 data); +void rf5c68_write_ram(void *chip, offs_t DataStart, offs_t DataLength, const UINT8* RAMData); + +void rf5c68_set_mute_mask(void *chip, UINT32 MuteMask); + +#ifdef __cplusplus +} +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rom_Data.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rom_Data.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rom_Data.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rom_Data.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,99 +1,99 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Rom_Data.h" - -/* Copyright (C) 2003-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -void Rom_Data::clear() -{ - file_size_ = 0; - rom_addr = 0; - mask = 0; - rom.clear(); -} - -Rom_Data::Rom_Data( int page_size ) : - pad_size( page_size + pad_extra ) -{ - // page_size should be power of 2 - check( (page_size & (page_size - 1)) == 0 ); - - clear(); -} - -Rom_Data::~Rom_Data() -{ } - -// Reads file into array, placing file_offset bytes of padding before the beginning, and pad_size after the end -blargg_err_t Rom_Data::load_( Data_Reader& in, int header_size, int file_offset ) -{ - clear(); - file_size_ = in.remain(); - if ( file_size_ <= header_size ) // <= because there must be data after header - return blargg_err_file_type; - - RETURN_ERR( rom.resize( file_offset + file_size_ + pad_size ) ); - - return in.read( rom.begin() + file_offset, file_size_ ); -} - -blargg_err_t Rom_Data::load( Data_Reader& in, int header_size, - void* header_out, int fill ) -{ - int file_offset = pad_size - header_size; - blargg_err_t err = load_( in, header_size, file_offset ); - if ( err ) - { - clear(); - return err; - } - - file_size_ -= header_size; - memcpy( header_out, &rom [file_offset], header_size ); - - memset( rom.begin() , fill, pad_size ); - memset( rom.end() - pad_size, fill, pad_size ); - - return blargg_ok; -} - -void Rom_Data::set_addr( int addr ) -{ - int const page_size = pad_size - pad_extra; - - // Minimum size that contains all bytes and is a multiple of page_size - int const size = (addr + file_size_ + page_size - 1) / page_size * page_size; - - // Find lowest power of 2 that is >= size - int power2 = 1; - while ( power2 < size ) - power2 *= 2; - - mask = power2 - 1; - - // Address of first byte of ROM (possibly negative) - rom_addr = addr - page_size - pad_extra; - - if ( rom.resize( size - rom_addr + pad_extra ) ) { } // OK if shrink fails -} - -byte* Rom_Data::at_addr( int addr ) -{ - int offset = mask_addr( addr ) - rom_addr; - - if ( (unsigned) offset > (unsigned) (rom.size() - pad_size) ) - offset = 0; // unmapped - - return &rom [offset]; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Rom_Data.h" + +/* Copyright (C) 2003-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +void Rom_Data::clear() +{ + file_size_ = 0; + rom_addr = 0; + mask = 0; + rom.clear(); +} + +Rom_Data::Rom_Data( int page_size ) : + pad_size( page_size + pad_extra ) +{ + // page_size should be power of 2 + check( (page_size & (page_size - 1)) == 0 ); + + clear(); +} + +Rom_Data::~Rom_Data() +{ } + +// Reads file into array, placing file_offset bytes of padding before the beginning, and pad_size after the end +blargg_err_t Rom_Data::load_( Data_Reader& in, int header_size, int file_offset ) +{ + clear(); + file_size_ = in.remain(); + if ( file_size_ <= header_size ) // <= because there must be data after header + return blargg_err_file_type; + + RETURN_ERR( rom.resize( file_offset + file_size_ + pad_size ) ); + + return in.read( rom.begin() + file_offset, file_size_ ); +} + +blargg_err_t Rom_Data::load( Data_Reader& in, int header_size, + void* header_out, int fill ) +{ + int file_offset = pad_size - header_size; + blargg_err_t err = load_( in, header_size, file_offset ); + if ( err ) + { + clear(); + return err; + } + + file_size_ -= header_size; + memcpy( header_out, &rom [file_offset], header_size ); + + memset( rom.begin() , fill, pad_size ); + memset( rom.end() - pad_size, fill, pad_size ); + + return blargg_ok; +} + +void Rom_Data::set_addr( int addr ) +{ + int const page_size = pad_size - pad_extra; + + // Minimum size that contains all bytes and is a multiple of page_size + int const size = (addr + file_size_ + page_size - 1) / page_size * page_size; + + // Find lowest power of 2 that is >= size + int power2 = 1; + while ( power2 < size ) + power2 *= 2; + + mask = power2 - 1; + + // Address of first byte of ROM (possibly negative) + rom_addr = addr - page_size - pad_extra; + + if ( rom.resize( size - rom_addr + pad_extra ) ) { } // OK if shrink fails +} + +byte* Rom_Data::at_addr( int addr ) +{ + int offset = mask_addr( addr ) - rom_addr; + + if ( (unsigned) offset > (unsigned) (rom.size() - pad_size) ) + offset = 0; // unmapped + + return &rom [offset]; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rom_Data.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rom_Data.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Rom_Data.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Rom_Data.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,94 +1,94 @@ -// Manages ROM data loaded from file in an efficient manner - -// Game_Music_Emu $vers -#ifndef ROM_DATA_H -#define ROM_DATA_H - -#include "blargg_common.h" -#include "Data_Reader.h" - -/* Loads a ROM file into memory and allows access to it in page-sized chunks. - -* ROM file consists of header followed by ROM data. Instead of storing the entire -ROM contents, the file only stores the occupied portion, with the bytes before and -after that cleared to some value. The size and format of the header is up to the -caller, as is the starting address of the ROM data following it. File loading is -performed with a single read, rather than two or more that might otherwise be -required. - -* Once ROM data is loaded and its address specified, a pointer to any "page" can -be obtained. ROM data is mirrored using smallest power of 2 that contains it. -Addresses not aligned to pages can also be used, but this might cause unexpected -results. - -Example with file data of size 0x0C put at address 0x0F, with page size of 8: - ----------------0123456789AB--------------------0123456789AB---------... -^ ^ ^ ^ ^ ^ ^ ^ ^ -0 0x08 0x10 0x18 0x20 0x28 0x30 0x38 0x40 - -at_addr(0x00) = pointer to 8 bytes of fill. -at_addr(0x08) = pointer to 7 bytes of fill, followed by first byte of file. -at_addr(0x10) = pointer to next 8 bytes of file. -at_addr(0x18) = pointer to last 3 bytes of file, followed by 5 bytes of fill. -at_addr(0x20) = pointer to 8 bytes of fill. -at_addr(0x28) = pointer to 7 bytes of fill, followed by first byte of file. -etc. */ - -class Rom_Data { - enum { pad_extra = 8 }; -public: - typedef unsigned char byte; - - // Page_size should be a power of 2 - Rom_Data( int page_size ); - - // Loads file into memory, then copies header to *header_out and fills - // unmapped bank and file data padding with fill. Returns blargg_err_file_type - // if in.remain() <= header_size. - blargg_err_t load( Data_Reader& in, int header_size, void* header_out, int fill ); - - // Below, "file data" refers to data AFTER the header - - // Size of file data - int file_size() const { return file_size_; } - - // Pointer to beginning of file data - byte * begin() { return rom.begin() + pad_size; } - byte const* begin() const { return rom.begin() + pad_size; } - - // Pointer to unmapped page cleared with fill value - byte* unmapped() { return rom.begin(); } - - // Sets address that file data will start at. Must be set before using following - // functions, and cannot be set more than once. - void set_addr( int addr ); - - // Address of first empty page (file size + addr rounded up to multiple of page_size) - int size() const { return rom.size() - pad_extra + rom_addr; } - - // Masks address to nearest power of two greater than size() - int mask_addr( int addr ) const { return addr & mask; } - - // Pointer to page beginning at addr, or unmapped() if outside data. - // Mirrored using mask_addr(). - byte* at_addr( int addr ); - - // Frees memory - void clear(); - -// Implementation -public: - ~Rom_Data(); - -protected: - blargg_vector rom; - int mask; - int rom_addr; - int const pad_size; - int file_size_; - - blargg_err_t load_( Data_Reader& in, int header_size, int file_offset ); -}; - -#endif +// Manages ROM data loaded from file in an efficient manner + +// Game_Music_Emu $vers +#ifndef ROM_DATA_H +#define ROM_DATA_H + +#include "blargg_common.h" +#include "Data_Reader.h" + +/* Loads a ROM file into memory and allows access to it in page-sized chunks. + +* ROM file consists of header followed by ROM data. Instead of storing the entire +ROM contents, the file only stores the occupied portion, with the bytes before and +after that cleared to some value. The size and format of the header is up to the +caller, as is the starting address of the ROM data following it. File loading is +performed with a single read, rather than two or more that might otherwise be +required. + +* Once ROM data is loaded and its address specified, a pointer to any "page" can +be obtained. ROM data is mirrored using smallest power of 2 that contains it. +Addresses not aligned to pages can also be used, but this might cause unexpected +results. + +Example with file data of size 0x0C put at address 0x0F, with page size of 8: + +---------------0123456789AB--------------------0123456789AB---------... +^ ^ ^ ^ ^ ^ ^ ^ ^ +0 0x08 0x10 0x18 0x20 0x28 0x30 0x38 0x40 + +at_add[5~r(0x00) = pointer to 8 bytes of fill. +at_addr(0x08) = pointer to 7 bytes of fill, followed by first byte of file. +at_addr(0x10) = pointer to next 8 bytes of file. +at_addr(0x18) = pointer to last 3 bytes of file, followed by 5 bytes of fill. +at_addr(0x20) = pointer to 8 bytes of fill. +at_addr(0x28) = pointer to 7 bytes of fill, followed by first byte of file. +etc. */ + +class Rom_Data { + enum { pad_extra = 8 }; +public: + typedef unsigned char byte; + + // Page_size should be a power of 2 + Rom_Data( int page_size ); + + // Loads file into memory, then copies header to *header_out and fills + // unmapped bank and file data padding with fill. Returns blargg_err_file_type + // if in.remain() <= header_size. + blargg_err_t load( Data_Reader& in, int header_size, void* header_out, int fill ); + + // Below, "file data" refers to data AFTER the header + + // Size of file data + int file_size() const { return file_size_; } + + // Pointer to beginning of file data + byte * begin() { return rom.begin() + pad_size; } + byte const* begin() const { return rom.begin() + pad_size; } + + // Pointer to unmapped page cleared with fill value + byte* unmapped() { return rom.begin(); } + + // Sets address that file data will start at. Must be set before using following + // functions, and cannot be set more than once. + void set_addr( int addr ); + + // Address of first empty page (file size + addr rounded up to multiple of page_size) + int size() const { return rom.size() - pad_extra + rom_addr; } + + // Masks address to nearest power of two greater than size() + int mask_addr( int addr ) const { return addr & mask; } + + // Pointer to page beginning at addr, or unmapped() if outside data. + // Mirrored using mask_addr(). + byte* at_addr( int addr ); + + // Frees memory + void clear(); + +// Implementation +public: + ~Rom_Data(); + +protected: + blargg_vector rom; + int mask; + int rom_addr; + int const pad_size; + int file_size_; + + blargg_err_t load_( Data_Reader& in, int header_size, int file_offset ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sap_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sap_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sap_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sap_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,410 +1,410 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Sap_Emu.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Sap_Emu::Sap_Emu() -{ - set_type( gme_sap_type ); - set_silence_lookahead( 6 ); -} - -Sap_Emu::~Sap_Emu() { } - -// Track info - -// Returns 16 or greater if not hex. Handles uppercase and lowercase. -// Thoroughly tested and rejects ALL non-hex characters. -inline int from_hex_char( int h ) -{ - h -= 0x30; - if ( (unsigned) h > 9 ) - h = ((h - 0x11) & 0xDF) + 10; - return h; -} - -static int from_hex( byte const in [] ) -{ - int result = 0; - for ( int n = 4; n--; ) - { - int h = from_hex_char( *in++ ); - if ( h > 15 ) - return -1; - result = result * 0x10 + h; - } - return result; -} - -static int parse_int( byte const* io [], byte const* end ) -{ - byte const* in = *io; - int n = 0; - while ( in < end ) - { - int dig = *in - '0'; - if ( (unsigned) dig > 9 ) - break; - ++in; - n = n * 10 + dig; - } - if ( in == *io ) - n = -1; // no numeric characters - *io = in; - return n; -} - -static int from_dec( byte const in [], byte const* end ) -{ - int n = parse_int( &in, end ); - if ( in < end ) - n = -1; - return n; -} - -static void parse_string( byte const in [], byte const* end, int len, char out [] ) -{ - byte const* start = in; - if ( *in++ == '\"' ) - { - start++; - while ( in < end && *in != '\"' ) - in++; - } - else - { - in = end; - } - len = min( len - 1, int (in - start) ); - out [len] = 0; - memcpy( out, start, len ); -} - -static int parse_time( byte const in [], byte const* end ) -{ - int minutes = parse_int( &in, end ); - if ( minutes < 0 || *in != ':' ) - return 0; - - ++in; - int seconds = parse_int( &in, end ); - if ( seconds < 0 ) - return 0; - - int time = minutes * 60000 + seconds * 1000; - if ( *in == '.' ) - { - byte const* start = ++in; - int msec = parse_int( &in, end ); - if ( msec >= 0 ) - { - // allow 1-3 digits - for ( int n = in - start; n < 3; n++ ) - msec *= 10; - time += msec; - } - } - - while ( in < end && *in <= ' ' ) - ++in; - - if ( end - in >= 4 && !memcmp( in, "LOOP", 4 ) ) - time = -time; - - return time; -} - -static blargg_err_t parse_info( byte const in [], int size, Sap_Emu::info_t* out ) -{ - out->track_count = 1; - out->author [0] = 0; - out->name [0] = 0; - out->copyright [0] = 0; - - for ( int i = 0; i < Sap_Emu::max_tracks; i++ ) - out->track_times [i] = 0; - - if ( size < 16 || memcmp( in, "SAP\x0D\x0A", 5 ) ) - return blargg_err_file_type; - - int time_count = 0; - byte const* file_end = in + size - 5; - in += 5; - while ( in < file_end && (in [0] != 0xFF || in [1] != 0xFF) ) - { - byte const* line_end = in; - while ( line_end < file_end && *line_end != 0x0D ) - line_end++; - - char const* tag = (char const*) in; - while ( in < line_end && *in > ' ' ) - in++; - int tag_len = (char const*) in - tag; - - while ( in < line_end && *in <= ' ' ) in++; - - if ( tag_len <= 0 ) - { - // skip line - } - else if ( !strncmp( "TIME", tag, tag_len ) && time_count < Sap_Emu::max_tracks ) - { - out->track_times [time_count++] = parse_time( in, line_end ); - } - else if ( !strncmp( "INIT", tag, tag_len ) ) - { - out->init_addr = from_hex( in ); - if ( (unsigned) out->init_addr >= 0x10000 ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "init address" ); - } - else if ( !strncmp( "PLAYER", tag, tag_len ) ) - { - out->play_addr = from_hex( in ); - if ( (unsigned) out->play_addr >= 0x10000 ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "play address" ); - } - else if ( !strncmp( "MUSIC", tag, tag_len ) ) - { - out->music_addr = from_hex( in ); - if ( (unsigned) out->music_addr >= 0x10000 ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "music address" ); - } - else if ( !strncmp( "SONGS", tag, tag_len ) ) - { - out->track_count = from_dec( in, line_end ); - if ( out->track_count <= 0 ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "track count" ); - } - else if ( !strncmp( "TYPE", tag, tag_len ) ) - { - switch ( out->type = *in ) - { - case 'S': - out->type = 'C'; - case 'B': - case 'C': - case 'D': - break; - - default: - return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "player type" ); - } - } - else if ( !strncmp( "STEREO", tag, tag_len ) ) - { - out->stereo = true; - } - else if ( !strncmp( "FASTPLAY", tag, tag_len ) ) - { - out->fastplay = from_dec( in, line_end ); - if ( out->fastplay <= 0 ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "fastplay value" ); - } - else if ( !strncmp( "AUTHOR", tag, tag_len ) ) - { - parse_string( in, line_end, sizeof out->author, out->author ); - } - else if ( !strncmp( "NAME", tag, tag_len ) ) - { - parse_string( in, line_end, sizeof out->name, out->name ); - } - else if ( !strncmp( "DATE", tag, tag_len ) ) - { - parse_string( in, line_end, sizeof out->copyright, out->copyright ); - } - - in = line_end + 2; - } - - if ( in [0] != 0xFF || in [1] != 0xFF ) - return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "ROM data missing" ); - out->rom_data = in + 2; - - return blargg_ok; -} - -static void copy_sap_fields( Sap_Emu::info_t const& in, track_info_t* out ) -{ - Gme_File::copy_field_( out->game, in.name ); - Gme_File::copy_field_( out->author, in.author ); - Gme_File::copy_field_( out->copyright, in.copyright ); -} - -static void hash_sap_file( Sap_Emu::info_t const& i, byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - unsigned char temp[4]; - set_le32( &temp[0], i.init_addr ); out.hash_( &temp[0], sizeof(temp) ); - set_le32( &temp[0], i.play_addr ); out.hash_( &temp[0], sizeof(temp) ); - set_le32( &temp[0], i.music_addr ); out.hash_( &temp[0], sizeof(temp) ); - set_le32( &temp[0], i.type ); out.hash_( &temp[0], sizeof(temp) ); - set_le32( &temp[0], i.fastplay ); out.hash_( &temp[0], sizeof(temp) ); - set_le32( &temp[0], i.stereo ); out.hash_( &temp[0], sizeof(temp) ); - set_le32( &temp[0], i.track_count ); out.hash_( &temp[0], sizeof(temp) ); - out.hash_( data, data_size ); -} - -blargg_err_t Sap_Emu::track_info_( track_info_t* out, int track ) const -{ - copy_sap_fields( info_, out ); - - if ( track < max_tracks ) - { - int time = info_.track_times [track]; - if ( time ) - { - if ( time > 0 ) - { - out->loop_length = 0; - } - else - { - time = -time; - out->loop_length = time; - } - out->length = time; - } - } - return blargg_ok; -} - -struct Sap_File : Gme_Info_ -{ - Sap_Emu::info_t info; - - Sap_File() { set_type( gme_sap_type ); } - - blargg_err_t load_mem_( byte const begin [], int size ) - { - RETURN_ERR( parse_info( begin, size, &info ) ); - set_track_count( info.track_count ); - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_sap_fields( info, out ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_sap_file( info, info.rom_data, file_end() - info.rom_data, out ); - return blargg_ok; - } -}; - -static Music_Emu* new_sap_emu () { return BLARGG_NEW Sap_Emu ; } -static Music_Emu* new_sap_file() { return BLARGG_NEW Sap_File; } - -gme_type_t_ const gme_sap_type [1] = {{ "Atari XL", 0, &new_sap_emu, &new_sap_file, "SAP", 1 }}; - -// Setup - -blargg_err_t Sap_Emu::load_mem_( byte const in [], int size ) -{ - file_end = in + size; - - info_.warning = NULL; - info_.type = 'B'; - info_.stereo = false; - info_.init_addr = -1; - info_.play_addr = -1; - info_.music_addr = -1; - info_.fastplay = 312; - RETURN_ERR( parse_info( in, size, &info_ ) ); - - set_warning( info_.warning ); - set_track_count( info_.track_count ); - set_voice_count( Sap_Apu::osc_count << info_.stereo ); - core.apu_impl().volume( gain() ); - - static const char* const names [Sap_Apu::osc_count * 2] = { - "Wave 1", "Wave 2", "Wave 3", "Wave 4", - "Wave 5", "Wave 6", "Wave 7", "Wave 8", - }; - set_voice_names( names ); - - static int const types [Sap_Apu::osc_count * 2] = { - wave_type+1, wave_type+2, wave_type+3, wave_type+0, - wave_type+5, wave_type+6, wave_type+7, wave_type+4, - }; - set_voice_types( types ); - - return setup_buffer( 1773447 ); -} - -void Sap_Emu::update_eq( blip_eq_t const& eq ) -{ - core.apu_impl().synth.treble_eq( eq ); -} - -void Sap_Emu::set_voice( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - int i2 = i - Sap_Apu::osc_count; - if ( i2 >= 0 ) - core.apu2().set_output( i2, right ); - else - core.apu().set_output( i, (info_.stereo ? left : center) ); -} - -// Emulation - -void Sap_Emu::set_tempo_( double t ) -{ - core.set_tempo( t ); -} - -blargg_err_t Sap_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - core.setup_ram(); - - // Copy file data to RAM - byte const* in = info_.rom_data; - while ( file_end - in >= 5 ) - { - int start = get_le16( in ); - int end = get_le16( in + 2 ); - //dprintf( "Block $%04X-$%04X\n", start, end ); - in += 4; - int len = end - start + 1; - if ( (unsigned) len > (unsigned) (file_end - in) ) - { - set_warning( "Invalid file data block" ); - break; - } - - memcpy( core.ram() + start, in, len ); - in += len; - if ( file_end - in >= 2 && in [0] == 0xFF && in [1] == 0xFF ) - in += 2; - } - - return core.start_track( track, info_ ); -} - -blargg_err_t Sap_Emu::run_clocks( blip_time_t& duration, int ) -{ - return core.end_frame( duration ); -} - -blargg_err_t Sap_Emu::hash_( Hash_Function& out ) const -{ - hash_sap_file( info(), info().rom_data, file_end - info().rom_data, out ); - return blargg_ok; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Sap_Emu.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Sap_Emu::Sap_Emu() +{ + set_type( gme_sap_type ); + set_silence_lookahead( 6 ); +} + +Sap_Emu::~Sap_Emu() { } + +// Track info + +// Returns 16 or greater if not hex. Handles uppercase and lowercase. +// Thoroughly tested and rejects ALL non-hex characters. +inline int from_hex_char( int h ) +{ + h -= 0x30; + if ( (unsigned) h > 9 ) + h = ((h - 0x11) & 0xDF) + 10; + return h; +} + +static int from_hex( byte const in [] ) +{ + int result = 0; + for ( int n = 4; n--; ) + { + int h = from_hex_char( *in++ ); + if ( h > 15 ) + return -1; + result = result * 0x10 + h; + } + return result; +} + +static int parse_int( byte const* io [], byte const* end ) +{ + byte const* in = *io; + int n = 0; + while ( in < end ) + { + int dig = *in - '0'; + if ( (unsigned) dig > 9 ) + break; + ++in; + n = n * 10 + dig; + } + if ( in == *io ) + n = -1; // no numeric characters + *io = in; + return n; +} + +static int from_dec( byte const in [], byte const* end ) +{ + int n = parse_int( &in, end ); + if ( in < end ) + n = -1; + return n; +} + +static void parse_string( byte const in [], byte const* end, int len, char out [] ) +{ + byte const* start = in; + if ( *in++ == '\"' ) + { + start++; + while ( in < end && *in != '\"' ) + in++; + } + else + { + in = end; + } + len = min( len - 1, int (in - start) ); + out [len] = 0; + memcpy( out, start, len ); +} + +static int parse_time( byte const in [], byte const* end ) +{ + int minutes = parse_int( &in, end ); + if ( minutes < 0 || *in != ':' ) + return 0; + + ++in; + int seconds = parse_int( &in, end ); + if ( seconds < 0 ) + return 0; + + int time = minutes * 60000 + seconds * 1000; + if ( *in == '.' ) + { + byte const* start = ++in; + int msec = parse_int( &in, end ); + if ( msec >= 0 ) + { + // allow 1-3 digits + for ( int n = in - start; n < 3; n++ ) + msec *= 10; + time += msec; + } + } + + while ( in < end && *in <= ' ' ) + ++in; + + if ( end - in >= 4 && !memcmp( in, "LOOP", 4 ) ) + time = -time; + + return time; +} + +static blargg_err_t parse_info( byte const in [], int size, Sap_Emu::info_t* out ) +{ + out->track_count = 1; + out->author [0] = 0; + out->name [0] = 0; + out->copyright [0] = 0; + + for ( int i = 0; i < Sap_Emu::max_tracks; i++ ) + out->track_times [i] = 0; + + if ( size < 16 || memcmp( in, "SAP\x0D\x0A", 5 ) ) + return blargg_err_file_type; + + int time_count = 0; + byte const* file_end = in + size - 5; + in += 5; + while ( in < file_end && (in [0] != 0xFF || in [1] != 0xFF) ) + { + byte const* line_end = in; + while ( line_end < file_end && *line_end != 0x0D ) + line_end++; + + char const* tag = (char const*) in; + while ( in < line_end && *in > ' ' ) + in++; + int tag_len = (char const*) in - tag; + + while ( in < line_end && *in <= ' ' ) in++; + + if ( tag_len <= 0 ) + { + // skip line + } + else if ( !strncmp( "TIME", tag, tag_len ) && time_count < Sap_Emu::max_tracks ) + { + out->track_times [time_count++] = parse_time( in, line_end ); + } + else if ( !strncmp( "INIT", tag, tag_len ) ) + { + out->init_addr = from_hex( in ); + if ( (unsigned) out->init_addr >= 0x10000 ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "init address" ); + } + else if ( !strncmp( "PLAYER", tag, tag_len ) ) + { + out->play_addr = from_hex( in ); + if ( (unsigned) out->play_addr >= 0x10000 ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "play address" ); + } + else if ( !strncmp( "MUSIC", tag, tag_len ) ) + { + out->music_addr = from_hex( in ); + if ( (unsigned) out->music_addr >= 0x10000 ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "music address" ); + } + else if ( !strncmp( "SONGS", tag, tag_len ) ) + { + out->track_count = from_dec( in, line_end ); + if ( out->track_count <= 0 ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "track count" ); + } + else if ( !strncmp( "TYPE", tag, tag_len ) ) + { + switch ( out->type = *in ) + { + case 'S': + out->type = 'C'; + case 'B': + case 'C': + case 'D': + break; + + default: + return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "player type" ); + } + } + else if ( !strncmp( "STEREO", tag, tag_len ) ) + { + out->stereo = true; + } + else if ( !strncmp( "FASTPLAY", tag, tag_len ) ) + { + out->fastplay = from_dec( in, line_end ); + if ( out->fastplay <= 0 ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "fastplay value" ); + } + else if ( !strncmp( "AUTHOR", tag, tag_len ) ) + { + parse_string( in, line_end, sizeof out->author, out->author ); + } + else if ( !strncmp( "NAME", tag, tag_len ) ) + { + parse_string( in, line_end, sizeof out->name, out->name ); + } + else if ( !strncmp( "DATE", tag, tag_len ) ) + { + parse_string( in, line_end, sizeof out->copyright, out->copyright ); + } + + in = line_end + 2; + } + + if ( in [0] != 0xFF || in [1] != 0xFF ) + return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "ROM data missing" ); + out->rom_data = in + 2; + + return blargg_ok; +} + +static void copy_sap_fields( Sap_Emu::info_t const& in, track_info_t* out ) +{ + Gme_File::copy_field_( out->game, in.name ); + Gme_File::copy_field_( out->author, in.author ); + Gme_File::copy_field_( out->copyright, in.copyright ); +} + +static void hash_sap_file( Sap_Emu::info_t const& i, byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + unsigned char temp[4]; + set_le32( &temp[0], i.init_addr ); out.hash_( &temp[0], sizeof(temp) ); + set_le32( &temp[0], i.play_addr ); out.hash_( &temp[0], sizeof(temp) ); + set_le32( &temp[0], i.music_addr ); out.hash_( &temp[0], sizeof(temp) ); + set_le32( &temp[0], i.type ); out.hash_( &temp[0], sizeof(temp) ); + set_le32( &temp[0], i.fastplay ); out.hash_( &temp[0], sizeof(temp) ); + set_le32( &temp[0], i.stereo ); out.hash_( &temp[0], sizeof(temp) ); + set_le32( &temp[0], i.track_count ); out.hash_( &temp[0], sizeof(temp) ); + out.hash_( data, data_size ); +} + +blargg_err_t Sap_Emu::track_info_( track_info_t* out, int track ) const +{ + copy_sap_fields( info_, out ); + + if ( track < max_tracks ) + { + int time = info_.track_times [track]; + if ( time ) + { + if ( time > 0 ) + { + out->loop_length = 0; + } + else + { + time = -time; + out->loop_length = time; + } + out->length = time; + } + } + return blargg_ok; +} + +struct Sap_File : Gme_Info_ +{ + Sap_Emu::info_t info; + + Sap_File() { set_type( gme_sap_type ); } + + blargg_err_t load_mem_( byte const begin [], int size ) + { + RETURN_ERR( parse_info( begin, size, &info ) ); + set_track_count( info.track_count ); + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + copy_sap_fields( info, out ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_sap_file( info, info.rom_data, file_end() - info.rom_data, out ); + return blargg_ok; + } +}; + +static Music_Emu* new_sap_emu () { return BLARGG_NEW Sap_Emu ; } +static Music_Emu* new_sap_file() { return BLARGG_NEW Sap_File; } + +gme_type_t_ const gme_sap_type [1] = {{ "Atari XL", 0, &new_sap_emu, &new_sap_file, "SAP", 1 }}; + +// Setup + +blargg_err_t Sap_Emu::load_mem_( byte const in [], int size ) +{ + file_end = in + size; + + info_.warning = NULL; + info_.type = 'B'; + info_.stereo = false; + info_.init_addr = -1; + info_.play_addr = -1; + info_.music_addr = -1; + info_.fastplay = 312; + RETURN_ERR( parse_info( in, size, &info_ ) ); + + set_warning( info_.warning ); + set_track_count( info_.track_count ); + set_voice_count( Sap_Apu::osc_count << info_.stereo ); + core.apu_impl().volume( gain() ); + + static const char* const names [Sap_Apu::osc_count * 2] = { + "Wave 1", "Wave 2", "Wave 3", "Wave 4", + "Wave 5", "Wave 6", "Wave 7", "Wave 8", + }; + set_voice_names( names ); + + static int const types [Sap_Apu::osc_count * 2] = { + wave_type+1, wave_type+2, wave_type+3, wave_type+0, + wave_type+5, wave_type+6, wave_type+7, wave_type+4, + }; + set_voice_types( types ); + + return setup_buffer( 1773447 ); +} + +void Sap_Emu::update_eq( blip_eq_t const& eq ) +{ + core.apu_impl().synth.treble_eq( eq ); +} + +void Sap_Emu::set_voice( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) +{ + int i2 = i - Sap_Apu::osc_count; + if ( i2 >= 0 ) + core.apu2().set_output( i2, right ); + else + core.apu().set_output( i, (info_.stereo ? left : center) ); +} + +// Emulation + +void Sap_Emu::set_tempo_( double t ) +{ + core.set_tempo( t ); +} + +blargg_err_t Sap_Emu::start_track_( int track ) +{ + RETURN_ERR( Classic_Emu::start_track_( track ) ); + + core.setup_ram(); + + // Copy file data to RAM + byte const* in = info_.rom_data; + while ( file_end - in >= 5 ) + { + int start = get_le16( in ); + int end = get_le16( in + 2 ); + //dprintf( "Block $%04X-$%04X\n", start, end ); + in += 4; + int len = end - start + 1; + if ( (unsigned) len > (unsigned) (file_end - in) ) + { + set_warning( "Invalid file data block" ); + break; + } + + memcpy( core.ram() + start, in, len ); + in += len; + if ( file_end - in >= 2 && in [0] == 0xFF && in [1] == 0xFF ) + in += 2; + } + + return core.start_track( track, info_ ); +} + +blargg_err_t Sap_Emu::run_clocks( blip_time_t& duration, int ) +{ + return core.end_frame( duration ); +} + +blargg_err_t Sap_Emu::hash_( Hash_Function& out ) const +{ + hash_sap_file( info(), info().rom_data, file_end - info().rom_data, out ); + return blargg_ok; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/scd_pcm.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/scd_pcm.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/scd_pcm.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/scd_pcm.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,498 +1,498 @@ -/***********************************************************/ -/* */ -/* PCM.C : PCM RF5C164 emulator */ -/* */ -/* This source is a part of Gens project */ -/* Written by Stphane Dallongeville (gens@consolemul.com) */ -/* Copyright (c) 2002 by Stphane Dallongeville */ -/* */ -/***********************************************************/ - -#include -#include -#include - -#include "scd_pcm.h" -int PCM_Init(void *chip, int Rate); -void PCM_Set_Rate(void *chip, int Rate); -void PCM_Reset(void *chip); -void PCM_Write_Reg(void *chip, unsigned int Reg, unsigned int Data); -int PCM_Update(void *chip, int **buf, int Length); - -#define PCM_STEP_SHIFT 11 - -static unsigned char VolTabIsInit = 0x00; -static int PCM_Volume_Tab[256 * 256]; - -//unsigned char Ram_PCM[64 * 1024]; -//int PCM_Enable; - - -/** - * PCM_Init(): Initialize the PCM chip. - * @param Rate Sample rate. - * @return 0 if successful. - */ -int PCM_Init(void *_chip, int Rate) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - int i, j, out; - - if (! VolTabIsInit) - { - for (i = 0; i < 0x100; i++) - { - for (j = 0; j < 0x100; j++) - { - if (i & 0x80) - { - out = -(i & 0x7F); - out *= j; - PCM_Volume_Tab[(j << 8) + i] = out; - } - else - { - out = i * j; - PCM_Volume_Tab[(j << 8) + i] = out; - } - } - } - VolTabIsInit = 0x01; - } - - for (i = 0; i < 8; i ++) - chip->Channel[i].Muted = 0x00; - - chip->RAMSize = 64 * 1024; - chip->RAM = (unsigned char*)malloc(chip->RAMSize); - PCM_Reset(chip); - PCM_Set_Rate(chip, Rate); - - return 0; -} - - -/** - * PCM_Reset(): Reset the PCM chip. - */ -void PCM_Reset(void *_chip) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - int i; - struct pcm_chan_* chan; - - // Clear the PCM memory. - memset(chip->RAM, 0x00, chip->RAMSize); - - chip->Enable = 0; - chip->Cur_Chan = 0; - chip->Bank = 0; - - /* clear channel registers */ - for (i = 0; i < 8; i++) - { - chan = &chip->Channel[i]; - chan->Enable = 0; - chan->ENV = 0; - chan->PAN = 0; - chan->St_Addr = 0; - chan->Addr = 0; - chan->Loop_Addr = 0; - chan->Step = 0; - chan->Step_B = 0; - chan->Data = 0; - } -} - - -/** - * PCM_Set_Rate(): Change the PCM sample rate. - * @param Rate New sample rate. - */ -void PCM_Set_Rate(void *_chip, int Rate) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - int i; - - if (Rate == 0) - return; - - //chip->Rate = (float) (32 * 1024) / (float) Rate; - chip->Rate = (float) (31.8 * 1024) / (float) Rate; - - for (i = 0; i < 8; i++) - { - chip->Channel[i].Step = - (int) ((float) chip->Channel[i].Step_B * chip->Rate); - } -} - - -/** - * PCM_Write_Reg(): Write to a PCM register. - * @param Reg Register ID. - * @param Data Data to write. - */ -void PCM_Write_Reg(void *_chip, unsigned int Reg, unsigned int Data) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - int i; - struct pcm_chan_* chan = &chip->Channel[chip->Cur_Chan]; - - Data &= 0xFF; - - switch (Reg) - { - case 0x00: - /* evelope register */ - chan->ENV = Data; - chan->MUL_L = (Data * (chan->PAN & 0x0F)) >> 5; - chan->MUL_R = (Data * (chan->PAN >> 4)) >> 5; - break; - - case 0x01: - /* pan register */ - chan->PAN = Data; - chan->MUL_L = ((Data & 0x0F) * chan->ENV) >> 5; - chan->MUL_R = ((Data >> 4) * chan->ENV) >> 5; - break; - - case 0x02: - /* frequency step (LB) registers */ - chan->Step_B &= 0xFF00; - chan->Step_B += Data; - chan->Step = (int)((float)chan->Step_B * chip->Rate); - - //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, - // "Step low = %.2X Step calculated = %.8X", - // Data, chan->Step); - break; - - case 0x03: - /* frequency step (HB) registers */ - chan->Step_B &= 0x00FF; - chan->Step_B += Data << 8; - chan->Step = (int)((float)chan->Step_B * chip->Rate); - - //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, - // "Step high = %.2X Step calculated = %.8X", - // Data, chan->Step); - break; - - case 0x04: - chan->Loop_Addr &= 0xFF00; - chan->Loop_Addr += Data; - - //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, - // "Loop low = %.2X Loop = %.8X", - // Data, chan->Loop_Addr); - break; - - case 0x05: - /* loop address registers */ - chan->Loop_Addr &= 0x00FF; - chan->Loop_Addr += Data << 8; - - //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, - // "Loop high = %.2X Loop = %.8X", - // Data, chan->Loop_Addr); - break; - - case 0x06: - /* start address registers */ - chan->St_Addr = Data << (PCM_STEP_SHIFT + 8); - //chan->Addr = chan->St_Addr; - - //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, - // "Start addr = %.2X New Addr = %.8X", - // Data, chan->Addr); - break; - - case 0x07: - /* control register */ - /* mod is H */ - if (Data & 0x40) - { - /* select channel */ - chip->Cur_Chan = Data & 0x07; - } - /* mod is L */ - else - { - /* pcm ram bank select */ - chip->Bank = (Data & 0x0F) << 12; - } - - /* sounding bit */ - if (Data & 0x80) - chip->Enable = 0xFF; // Used as mask - else - chip->Enable = 0; - - //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, - // "General Enable = %.2X", Data); - break; - - case 0x08: - /* sound on/off register */ - Data ^= 0xFF; - - //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, - // "Channel Enable = %.2X", Data); - - for (i = 0; i < 8; i++) - { - chan = &chip->Channel[i]; - if (!chan->Enable) - chan->Addr = chan->St_Addr; - } - - for (i = 0; i < 8; i++) - { - chip->Channel[i].Enable = Data & (1 << i); - } - } -} - - -/** - * PCM_Update(): Update the PCM buffer. - * @param buf PCM buffer. - * @param Length Buffer length. - */ -int PCM_Update(void *_chip, int **buf, int Length) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - int i, j; - int *bufL, *bufR; //, *volL, *volR; - unsigned int Addr, k; - struct pcm_chan_ *CH; - - bufL = buf[0]; - bufR = buf[1]; - - // clear buffers - memset(bufL, 0, Length * sizeof(int)); - memset(bufR, 0, Length * sizeof(int)); - - // if PCM disable, no sound - if (!chip->Enable) - return 1; - -#if 0 - // faster for short update - for (j = 0; j < Length; j++) - { - for (i = 0; i < 8; i++) - { - CH = &(chip->Channel[i]); - - // only loop when sounding and on - if (CH->Enable && ! CH->Muted) - { - Addr = CH->Addr >> PCM_STEP_SHIFT; - - if (Addr & 0x10000) - { - for(k = CH->Old_Addr; k < 0x10000; k++) - { - if (chip->RAM[k] == 0xFF) - { - CH->Old_Addr = Addr = CH->Loop_Addr; - CH->Addr = Addr << PCM_STEP_SHIFT; - break; - } - } - - if (Addr & 0x10000) - { - //CH->Addr -= CH->Step; - CH->Enable = 0; - break; - } - } - else - { - for(k = CH->Old_Addr; k <= Addr; k++) - { - if (chip->RAM[k] == 0xFF) - { - CH->Old_Addr = Addr = CH->Loop_Addr; - CH->Addr = Addr << PCM_STEP_SHIFT; - break; - } - } - } - - // test for loop signal - if (chip->RAM[Addr] == 0xFF) - { - Addr = CH->Loop_Addr; - CH->Addr = Addr << PCM_STEP_SHIFT; - } - - if (chip->RAM[Addr] & 0x80) - { - CH->Data = chip->RAM[Addr] & 0x7F; - bufL[j] -= CH->Data * CH->MUL_L; - bufR[j] -= CH->Data * CH->MUL_R; - } - else - { - CH->Data = chip->RAM[Addr]; - bufL[j] += CH->Data * CH->MUL_L; - bufR[j] += CH->Data * CH->MUL_R; - } - - // update address register - //CH->Addr = (CH->Addr + CH->Step) & 0x7FFFFFF; - CH->Addr += CH->Step; - CH->Old_Addr = Addr + 1; - } - } - } -#endif - -#if 1 - // for long update - for (i = 0; i < 8; i++) - { - CH = &(chip->Channel[i]); - - // only loop when sounding and on - if (CH->Enable && ! CH->Muted) - { - Addr = CH->Addr >> PCM_STEP_SHIFT; - //volL = &(PCM_Volume_Tab[CH->MUL_L << 8]); - //volR = &(PCM_Volume_Tab[CH->MUL_R << 8]); - - for (j = 0; j < Length; j++) - { - // test for loop signal - if (chip->RAM[Addr] == 0xFF) - { - CH->Addr = (Addr = CH->Loop_Addr) << PCM_STEP_SHIFT; - if (chip->RAM[Addr] == 0xFF) - break; - else - j--; - } - else - { - if (chip->RAM[Addr] & 0x80) - { - CH->Data = chip->RAM[Addr] & 0x7F; - bufL[j] -= CH->Data * CH->MUL_L; - bufR[j] -= CH->Data * CH->MUL_R; - } - else - { - CH->Data = chip->RAM[Addr]; - bufL[j] += CH->Data * CH->MUL_L; - bufR[j] += CH->Data * CH->MUL_R; - } - - // update address register - k = Addr + 1; - CH->Addr = (CH->Addr + CH->Step) & 0x7FFFFFF; - Addr = CH->Addr >> PCM_STEP_SHIFT; - - for (; k < Addr; k++) - { - if (chip->RAM[k] == 0xFF) - { - CH->Addr = (Addr = CH->Loop_Addr) << PCM_STEP_SHIFT; - break; - } - } - } - } - - if (chip->RAM[Addr] == 0xFF) - { - CH->Addr = CH->Loop_Addr << PCM_STEP_SHIFT; - } - } - } -#endif - - return 0; -} - - -void rf5c164_update(void *_chip, stream_sample_t **outputs, int samples) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - - PCM_Update(chip, outputs, samples); -} - -void * device_start_rf5c164( int clock ) -{ - /* allocate memory for the chip */ - //rf5c164_state *chip = get_safe_token(device); - struct pcm_chip_ *chip; - int rate; - - chip = (struct pcm_chip_ *) malloc(sizeof(struct pcm_chip_)); - if (!chip) return chip; - - rate = clock / 384; - - PCM_Init(chip, rate); - /* allocate the stream */ - //chip->stream = stream_create(device, 0, 2, device->clock / 384, chip, rf5c68_update); - - return chip; -} - -void device_stop_rf5c164(void *_chip) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - free(chip->RAM); chip->RAM = NULL; - free(chip); -} - -void device_reset_rf5c164(void *chip) -{ - //struct pcm_chip_ *chip = &PCM_Chip[ChipID]; - PCM_Reset(chip); -} - -void rf5c164_w(void *chip, offs_t offset, UINT8 data) -{ - //struct pcm_chip_ *chip = &PCM_Chip[ChipID]; - PCM_Write_Reg(chip, offset, data); -} - -void rf5c164_mem_w(void *_chip, offs_t offset, UINT8 data) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - chip->RAM[chip->Bank | offset] = data; -} - -void rf5c164_write_ram(void *_chip, offs_t DataStart, offs_t DataLength, const UINT8* RAMData) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - - if (DataStart >= chip->RAMSize) - return; - if (DataStart + DataLength > chip->RAMSize) - DataLength = chip->RAMSize - DataStart; - - memcpy(chip->RAM + (chip->Bank | DataStart), RAMData, DataLength); - - return; -} - - -void rf5c164_set_mute_mask(void *_chip, UINT32 MuteMask) -{ - struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; - unsigned char CurChn; - - for (CurChn = 0; CurChn < 8; CurChn ++) - chip->Channel[CurChn].Muted = (MuteMask >> CurChn) & 0x01; - - return; -} +/***********************************************************/ +/* */ +/* PCM.C : PCM RF5C164 emulator */ +/* */ +/* This source is a part of Gens project */ +/* Written by Stphane Dallongeville (gens@consolemul.com) */ +/* Copyright (c) 2002 by Stphane Dallongeville */ +/* */ +/***********************************************************/ + +#include +#include +#include + +#include "scd_pcm.h" +int PCM_Init(void *chip, int Rate); +void PCM_Set_Rate(void *chip, int Rate); +void PCM_Reset(void *chip); +void PCM_Write_Reg(void *chip, unsigned int Reg, unsigned int Data); +int PCM_Update(void *chip, int **buf, int Length); + +#define PCM_STEP_SHIFT 11 + +static unsigned char VolTabIsInit = 0x00; +static int PCM_Volume_Tab[256 * 256]; + +//unsigned char Ram_PCM[64 * 1024]; +//int PCM_Enable; + + +/** + * PCM_Init(): Initialize the PCM chip. + * @param Rate Sample rate. + * @return 0 if successful. + */ +int PCM_Init(void *_chip, int Rate) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + int i, j, out; + + if (! VolTabIsInit) + { + for (i = 0; i < 0x100; i++) + { + for (j = 0; j < 0x100; j++) + { + if (i & 0x80) + { + out = -(i & 0x7F); + out *= j; + PCM_Volume_Tab[(j << 8) + i] = out; + } + else + { + out = i * j; + PCM_Volume_Tab[(j << 8) + i] = out; + } + } + } + VolTabIsInit = 0x01; + } + + for (i = 0; i < 8; i ++) + chip->Channel[i].Muted = 0x00; + + chip->RAMSize = 64 * 1024; + chip->RAM = (unsigned char*)malloc(chip->RAMSize); + PCM_Reset(chip); + PCM_Set_Rate(chip, Rate); + + return 0; +} + + +/** + * PCM_Reset(): Reset the PCM chip. + */ +void PCM_Reset(void *_chip) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + int i; + struct pcm_chan_* chan; + + // Clear the PCM memory. + memset(chip->RAM, 0x00, chip->RAMSize); + + chip->Enable = 0; + chip->Cur_Chan = 0; + chip->Bank = 0; + + /* clear channel registers */ + for (i = 0; i < 8; i++) + { + chan = &chip->Channel[i]; + chan->Enable = 0; + chan->ENV = 0; + chan->PAN = 0; + chan->St_Addr = 0; + chan->Addr = 0; + chan->Loop_Addr = 0; + chan->Step = 0; + chan->Step_B = 0; + chan->Data = 0; + } +} + + +/** + * PCM_Set_Rate(): Change the PCM sample rate. + * @param Rate New sample rate. + */ +void PCM_Set_Rate(void *_chip, int Rate) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + int i; + + if (Rate == 0) + return; + + //chip->Rate = (float) (32 * 1024) / (float) Rate; + chip->Rate = (float) (31.8 * 1024) / (float) Rate; + + for (i = 0; i < 8; i++) + { + chip->Channel[i].Step = + (int) ((float) chip->Channel[i].Step_B * chip->Rate); + } +} + + +/** + * PCM_Write_Reg(): Write to a PCM register. + * @param Reg Register ID. + * @param Data Data to write. + */ +void PCM_Write_Reg(void *_chip, unsigned int Reg, unsigned int Data) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + int i; + struct pcm_chan_* chan = &chip->Channel[chip->Cur_Chan]; + + Data &= 0xFF; + + switch (Reg) + { + case 0x00: + /* evelope register */ + chan->ENV = Data; + chan->MUL_L = (Data * (chan->PAN & 0x0F)) >> 5; + chan->MUL_R = (Data * (chan->PAN >> 4)) >> 5; + break; + + case 0x01: + /* pan register */ + chan->PAN = Data; + chan->MUL_L = ((Data & 0x0F) * chan->ENV) >> 5; + chan->MUL_R = ((Data >> 4) * chan->ENV) >> 5; + break; + + case 0x02: + /* frequency step (LB) registers */ + chan->Step_B &= 0xFF00; + chan->Step_B += Data; + chan->Step = (int)((float)chan->Step_B * chip->Rate); + + //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, + // "Step low = %.2X Step calculated = %.8X", + // Data, chan->Step); + break; + + case 0x03: + /* frequency step (HB) registers */ + chan->Step_B &= 0x00FF; + chan->Step_B += Data << 8; + chan->Step = (int)((float)chan->Step_B * chip->Rate); + + //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, + // "Step high = %.2X Step calculated = %.8X", + // Data, chan->Step); + break; + + case 0x04: + chan->Loop_Addr &= 0xFF00; + chan->Loop_Addr += Data; + + //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, + // "Loop low = %.2X Loop = %.8X", + // Data, chan->Loop_Addr); + break; + + case 0x05: + /* loop address registers */ + chan->Loop_Addr &= 0x00FF; + chan->Loop_Addr += Data << 8; + + //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, + // "Loop high = %.2X Loop = %.8X", + // Data, chan->Loop_Addr); + break; + + case 0x06: + /* start address registers */ + chan->St_Addr = Data << (PCM_STEP_SHIFT + 8); + //chan->Addr = chan->St_Addr; + + //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, + // "Start addr = %.2X New Addr = %.8X", + // Data, chan->Addr); + break; + + case 0x07: + /* control register */ + /* mod is H */ + if (Data & 0x40) + { + /* select channel */ + chip->Cur_Chan = Data & 0x07; + } + /* mod is L */ + else + { + /* pcm ram bank select */ + chip->Bank = (Data & 0x0F) << 12; + } + + /* sounding bit */ + if (Data & 0x80) + chip->Enable = 0xFF; // Used as mask + else + chip->Enable = 0; + + //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, + // "General Enable = %.2X", Data); + break; + + case 0x08: + /* sound on/off register */ + Data ^= 0xFF; + + //LOG_MSG(pcm, LOG_MSG_LEVEL_DEBUG1, + // "Channel Enable = %.2X", Data); + + for (i = 0; i < 8; i++) + { + chan = &chip->Channel[i]; + if (!chan->Enable) + chan->Addr = chan->St_Addr; + } + + for (i = 0; i < 8; i++) + { + chip->Channel[i].Enable = Data & (1 << i); + } + } +} + + +/** + * PCM_Update(): Update the PCM buffer. + * @param buf PCM buffer. + * @param Length Buffer length. + */ +int PCM_Update(void *_chip, int **buf, int Length) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + int i, j; + int *bufL, *bufR; //, *volL, *volR; + unsigned int Addr, k; + struct pcm_chan_ *CH; + + bufL = buf[0]; + bufR = buf[1]; + + // clear buffers + memset(bufL, 0, Length * sizeof(int)); + memset(bufR, 0, Length * sizeof(int)); + + // if PCM disable, no sound + if (!chip->Enable) + return 1; + +#if 0 + // faster for short update + for (j = 0; j < Length; j++) + { + for (i = 0; i < 8; i++) + { + CH = &(chip->Channel[i]); + + // only loop when sounding and on + if (CH->Enable && ! CH->Muted) + { + Addr = CH->Addr >> PCM_STEP_SHIFT; + + if (Addr & 0x10000) + { + for(k = CH->Old_Addr; k < 0x10000; k++) + { + if (chip->RAM[k] == 0xFF) + { + CH->Old_Addr = Addr = CH->Loop_Addr; + CH->Addr = Addr << PCM_STEP_SHIFT; + break; + } + } + + if (Addr & 0x10000) + { + //CH->Addr -= CH->Step; + CH->Enable = 0; + break; + } + } + else + { + for(k = CH->Old_Addr; k <= Addr; k++) + { + if (chip->RAM[k] == 0xFF) + { + CH->Old_Addr = Addr = CH->Loop_Addr; + CH->Addr = Addr << PCM_STEP_SHIFT; + break; + } + } + } + + // test for loop signal + if (chip->RAM[Addr] == 0xFF) + { + Addr = CH->Loop_Addr; + CH->Addr = Addr << PCM_STEP_SHIFT; + } + + if (chip->RAM[Addr] & 0x80) + { + CH->Data = chip->RAM[Addr] & 0x7F; + bufL[j] -= CH->Data * CH->MUL_L; + bufR[j] -= CH->Data * CH->MUL_R; + } + else + { + CH->Data = chip->RAM[Addr]; + bufL[j] += CH->Data * CH->MUL_L; + bufR[j] += CH->Data * CH->MUL_R; + } + + // update address register + //CH->Addr = (CH->Addr + CH->Step) & 0x7FFFFFF; + CH->Addr += CH->Step; + CH->Old_Addr = Addr + 1; + } + } + } +#endif + +#if 1 + // for long update + for (i = 0; i < 8; i++) + { + CH = &(chip->Channel[i]); + + // only loop when sounding and on + if (CH->Enable && ! CH->Muted) + { + Addr = CH->Addr >> PCM_STEP_SHIFT; + //volL = &(PCM_Volume_Tab[CH->MUL_L << 8]); + //volR = &(PCM_Volume_Tab[CH->MUL_R << 8]); + + for (j = 0; j < Length; j++) + { + // test for loop signal + if (chip->RAM[Addr] == 0xFF) + { + CH->Addr = (Addr = CH->Loop_Addr) << PCM_STEP_SHIFT; + if (chip->RAM[Addr] == 0xFF) + break; + else + j--; + } + else + { + if (chip->RAM[Addr] & 0x80) + { + CH->Data = chip->RAM[Addr] & 0x7F; + bufL[j] -= CH->Data * CH->MUL_L; + bufR[j] -= CH->Data * CH->MUL_R; + } + else + { + CH->Data = chip->RAM[Addr]; + bufL[j] += CH->Data * CH->MUL_L; + bufR[j] += CH->Data * CH->MUL_R; + } + + // update address register + k = Addr + 1; + CH->Addr = (CH->Addr + CH->Step) & 0x7FFFFFF; + Addr = CH->Addr >> PCM_STEP_SHIFT; + + for (; k < Addr; k++) + { + if (chip->RAM[k] == 0xFF) + { + CH->Addr = (Addr = CH->Loop_Addr) << PCM_STEP_SHIFT; + break; + } + } + } + } + + if (chip->RAM[Addr] == 0xFF) + { + CH->Addr = CH->Loop_Addr << PCM_STEP_SHIFT; + } + } + } +#endif + + return 0; +} + + +void rf5c164_update(void *_chip, stream_sample_t **outputs, int samples) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + + PCM_Update(chip, outputs, samples); +} + +void * device_start_rf5c164( int clock ) +{ + /* allocate memory for the chip */ + //rf5c164_state *chip = get_safe_token(device); + struct pcm_chip_ *chip; + int rate; + + chip = (struct pcm_chip_ *) malloc(sizeof(struct pcm_chip_)); + if (!chip) return chip; + + rate = clock / 384; + + PCM_Init(chip, rate); + /* allocate the stream */ + //chip->stream = stream_create(device, 0, 2, device->clock / 384, chip, rf5c68_update); + + return chip; +} + +void device_stop_rf5c164(void *_chip) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + free(chip->RAM); chip->RAM = NULL; + free(chip); +} + +void device_reset_rf5c164(void *chip) +{ + //struct pcm_chip_ *chip = &PCM_Chip[ChipID]; + PCM_Reset(chip); +} + +void rf5c164_w(void *chip, offs_t offset, UINT8 data) +{ + //struct pcm_chip_ *chip = &PCM_Chip[ChipID]; + PCM_Write_Reg(chip, offset, data); +} + +void rf5c164_mem_w(void *_chip, offs_t offset, UINT8 data) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + chip->RAM[chip->Bank | offset] = data; +} + +void rf5c164_write_ram(void *_chip, offs_t DataStart, offs_t DataLength, const UINT8* RAMData) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + + if (DataStart >= chip->RAMSize) + return; + if (DataStart + DataLength > chip->RAMSize) + DataLength = chip->RAMSize - DataStart; + + memcpy(chip->RAM + (chip->Bank | DataStart), RAMData, DataLength); + + return; +} + + +void rf5c164_set_mute_mask(void *_chip, UINT32 MuteMask) +{ + struct pcm_chip_ *chip = (struct pcm_chip_ *) _chip; + unsigned char CurChn; + + for (CurChn = 0; CurChn < 8; CurChn ++) + chip->Channel[CurChn].Muted = (MuteMask >> CurChn) & 0x01; + + return; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/scd_pcm.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/scd_pcm.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/scd_pcm.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/scd_pcm.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,57 +1,57 @@ -#include "mamedef.h" - -struct pcm_chan_ { - unsigned int ENV; /* envelope register */ - unsigned int PAN; /* pan register */ - unsigned int MUL_L; /* envelope & pan product letf */ - unsigned int MUL_R; /* envelope & pan product right */ - unsigned int St_Addr; /* start address register */ - unsigned int Loop_Addr; /* loop address register */ - unsigned int Addr; /* current address register */ - unsigned int Step; /* frequency register */ - unsigned int Step_B; /* frequency register binaire */ - unsigned int Enable; /* channel on/off register */ - int Data; /* wave data */ - unsigned int Muted; -}; - -struct pcm_chip_ -{ - float Rate; - int Enable; - int Cur_Chan; - int Bank; - - struct pcm_chan_ Channel[8]; - - unsigned long int RAMSize; - unsigned char* RAM; -}; - -//extern struct pcm_chip_ PCM_Chip; -//extern unsigned char Ram_PCM[64 * 1024]; -//extern int PCM_Enable; - -//int PCM_Init(int Rate); -//void PCM_Set_Rate(int Rate); -//void PCM_Reset(void); -//void PCM_Write_Reg(unsigned int Reg, unsigned int Data); -//int PCM_Update(int **buf, int Length); - -#ifdef __cplusplus -extern "C" { -#endif - -void rf5c164_update(void *chip, stream_sample_t **outputs, int samples); -void * device_start_rf5c164(int clock); -void device_stop_rf5c164(void *chip); -void device_reset_rf5c164(void *chip); -void rf5c164_w(void *chip, offs_t offset, UINT8 data); -void rf5c164_mem_w(void *chip, offs_t offset, UINT8 data); -void rf5c164_write_ram(void *chip, offs_t DataStart, offs_t DataLength, const UINT8* RAMData); - -void rf5c164_set_mute_mask(void *chip, UINT32 MuteMask); - -#ifdef __cplusplus -} -#endif +#include "mamedef.h" + +struct pcm_chan_ { + unsigned int ENV; /* envelope register */ + unsigned int PAN; /* pan register */ + unsigned int MUL_L; /* envelope & pan product letf */ + unsigned int MUL_R; /* envelope & pan product right */ + unsigned int St_Addr; /* start address register */ + unsigned int Loop_Addr; /* loop address register */ + unsigned int Addr; /* current address register */ + unsigned int Step; /* frequency register */ + unsigned int Step_B; /* frequency register binaire */ + unsigned int Enable; /* channel on/off register */ + int Data; /* wave data */ + unsigned int Muted; +}; + +struct pcm_chip_ +{ + float Rate; + int Enable; + int Cur_Chan; + int Bank; + + struct pcm_chan_ Channel[8]; + + unsigned long int RAMSize; + unsigned char* RAM; +}; + +//extern struct pcm_chip_ PCM_Chip; +//extern unsigned char Ram_PCM[64 * 1024]; +//extern int PCM_Enable; + +//int PCM_Init(int Rate); +//void PCM_Set_Rate(int Rate); +//void PCM_Reset(void); +//void PCM_Write_Reg(unsigned int Reg, unsigned int Data); +//int PCM_Update(int **buf, int Length); + +#ifdef __cplusplus +extern "C" { +#endif + +void rf5c164_update(void *chip, stream_sample_t **outputs, int samples); +void * device_start_rf5c164(int clock); +void device_stop_rf5c164(void *chip); +void device_reset_rf5c164(void *chip); +void rf5c164_w(void *chip, offs_t offset, UINT8 data); +void rf5c164_mem_w(void *chip, offs_t offset, UINT8 data); +void rf5c164_write_ram(void *chip, offs_t DataStart, offs_t DataLength, const UINT8* RAMData); + +void rf5c164_set_mute_mask(void *chip, UINT32 MuteMask); + +#ifdef __cplusplus +} +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/segapcm.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/segapcm.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/segapcm.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/segapcm.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,384 +1,384 @@ -/*********************************************************/ -/* SEGA 16ch 8bit PCM */ -/*********************************************************/ - -#include -#include -#include -//#include "sndintrf.h" -//#include "streams.h" -#include "segapcm.h" - - -typedef struct _segapcm_state segapcm_state; -struct _segapcm_state -{ - UINT8 *ram; - UINT8 low[16]; - UINT32 ROMSize; - UINT8 *rom; -#ifdef _DEBUG - UINT8 *romusage; -#endif - int bankshift; - int bankmask; - int rgnmask; - sega_pcm_interface intf; - UINT8 Muted[16]; - //sound_stream * stream; -}; - -UINT8 SegaPCM_NewCore = 0x00; - -/*INLINE segapcm_state *get_safe_token(const device_config *device) -{ - assert(device != NULL); - assert(device->token != NULL); - assert(device->type == SOUND); - assert(sound_get_type(device) == SOUND_SEGAPCM); - return (segapcm_state *)device->token; -}*/ - -//static STREAM_UPDATE( SEGAPCM_update ) -void SEGAPCM_update(void *chip, stream_sample_t **outputs, int samples) -{ - //segapcm_state *spcm = (segapcm_state *)param; - segapcm_state *spcm = (segapcm_state *) chip; - int rgnmask = spcm->rgnmask; - int ch; - - /* clear the buffers */ - memset(outputs[0], 0, samples*sizeof(stream_sample_t)); - memset(outputs[1], 0, samples*sizeof(stream_sample_t)); - - // reg function - // ------------------------------------------------ - // 0x00 ? - // 0x01 ? - // 0x02 volume left - // 0x03 volume right - // 0x04 loop address (08-15) - // 0x05 loop address (16-23) - // 0x06 end address - // 0x07 address delta - // 0x80 ? - // 0x81 ? - // 0x82 ? - // 0x83 ? - // 0x84 current address (08-15), 00-07 is internal? - // 0x85 current address (16-23) - // 0x86 bit 0: channel disable? - // bit 1: loop disable - // other bits: bank - // 0x87 ? - - /* loop over channels */ - for (ch = 0; ch < 16; ch++) - { -if (! SegaPCM_NewCore) -{ - /* only process active channels */ - if (!(spcm->ram[0x86+8*ch] & 1) && ! spcm->Muted[ch]) - { - UINT8 *base = spcm->ram+8*ch; - UINT8 flags = base[0x86]; - const UINT8 *rom = spcm->rom + ((flags & spcm->bankmask) << spcm->bankshift); -#ifdef _DEBUG - const UINT8 *romusage = spcm->romusage + ((flags & spcm->bankmask) << spcm->bankshift); -#endif - UINT32 addr = (base[5] << 16) | (base[4] << 8) | spcm->low[ch]; - UINT16 loop = (base[0x85] << 8) | base[0x84]; - UINT8 end = base[6] + 1; - UINT8 delta = base[7]; - UINT8 voll = base[2]; - UINT8 volr = base[3]; - int i; - - /* loop over samples on this channel */ - for (i = 0; i < samples; i++) - { - INT8 v = 0; - - /* handle looping if we've hit the end */ - if ((addr >> 16) == end) - { - if (!(flags & 2)) - addr = loop << 8; - else - { - flags |= 1; - break; - } - } - - /* fetch the sample */ - v = rom[(addr >> 8) & rgnmask] - 0x80; -#ifdef _DEBUG - if (romusage[(addr >> 8) & rgnmask] == 0xFF && (voll || volr)) - printf("Access to empty ROM section! (0x%06lX)\n", - ((flags & spcm->bankmask) << spcm->bankshift) + (addr >> 8) & rgnmask); -#endif - - /* apply panning and advance */ - outputs[0][i] += v * voll; - outputs[1][i] += v * volr; - addr += delta; - } - - /* store back the updated address and info */ - base[0x86] = flags; - base[4] = addr >> 8; - base[5] = addr >> 16; - spcm->low[ch] = flags & 1 ? 0 : addr; - } -} -else -{ - UINT8 *regs = spcm->ram+8*ch; - - /* only process active channels */ - if (!(regs[0x86] & 1) && ! spcm->Muted[ch]) - { - const UINT8 *rom = spcm->rom + ((regs[0x86] & spcm->bankmask) << spcm->bankshift); -#ifdef _DEBUG - const UINT8 *romusage = spcm->romusage + ((regs[0x86] & spcm->bankmask) << spcm->bankshift); -#endif - UINT32 addr = (regs[0x85] << 16) | (regs[0x84] << 8) | spcm->low[ch]; - UINT32 loop = (regs[0x05] << 16) | (regs[0x04] << 8); - UINT8 end = regs[6] + 1; - int i; - - /* loop over samples on this channel */ - for (i = 0; i < samples; i++) - { - INT8 v = 0; - - /* handle looping if we've hit the end */ - if ((addr >> 16) == end) - { - if (regs[0x86] & 2) - { - regs[0x86] |= 1; - break; - } - else addr = loop; - } - - /* fetch the sample */ - v = rom[(addr >> 8) & rgnmask] - 0x80; -#ifdef _DEBUG - if (romusage[(addr >> 8) & rgnmask] == 0xFF && (regs[2] || regs[3])) - printf("Access to empty ROM section! (0x%06lX)\n", - ((regs[0x86] & spcm->bankmask) << spcm->bankshift) + (addr >> 8) & rgnmask); -#endif - - /* apply panning and advance */ - outputs[0][i] += v * regs[2]; - outputs[1][i] += v * regs[3]; - addr = (addr + regs[7]) & 0xffffff; - } - - /* store back the updated address */ - regs[0x84] = addr >> 8; - regs[0x85] = addr >> 16; - spcm->low[ch] = regs[0x86] & 1 ? 0 : addr; - } -} - } -} - -//static DEVICE_START( segapcm ) -void * device_start_segapcm(int intf_bank) -{ - const UINT32 STD_ROM_SIZE = 0x80000; - //const sega_pcm_interface *intf = (const sega_pcm_interface *)device->static_config; - sega_pcm_interface *intf; - int mask, rom_mask, len; - //segapcm_state *spcm = get_safe_token(device); - segapcm_state *spcm; - - spcm = (segapcm_state *) malloc(sizeof(segapcm_state)); - if (!spcm) return spcm; - - intf = &spcm->intf; - intf->bank = intf_bank; - - //spcm->rom = (const UINT8 *)device->region; - //spcm->ram = auto_alloc_array(device->machine, UINT8, 0x800); - spcm->ROMSize = STD_ROM_SIZE; - spcm->rom = (UINT8*) malloc(STD_ROM_SIZE); -#ifdef _DEBUG - spcm->romusage = (UINT8*) malloc(STD_ROM_SIZE); -#endif - spcm->ram = (UINT8*) malloc(0x800); - - memset(spcm->rom, 0xFF, STD_ROM_SIZE); -#ifdef _DEBUG - memset(spcm->romusage, 0xFF, STD_ROM_SIZE); -#endif - //memset(spcm->ram, 0xff, 0x800); // RAM Clear is done at device_reset - - spcm->bankshift = (UINT8)(intf->bank); - mask = intf->bank >> 16; - if(!mask) - mask = BANK_MASK7>>16; - - len = STD_ROM_SIZE; - spcm->rgnmask = len - 1; - for(rom_mask = 1; rom_mask < len; rom_mask *= 2); - rom_mask--; - - spcm->bankmask = mask & (rom_mask >> spcm->bankshift); - - //spcm->stream = stream_create(device, 0, 2, device->clock / 128, spcm, SEGAPCM_update); - - //state_save_register_device_item_array(device, 0, spcm->low); - //state_save_register_device_item_pointer(device, 0, spcm->ram, 0x800); - - for (mask = 0; mask < 16; mask ++) - spcm->Muted[mask] = 0x00; - - return spcm; -} - -//static DEVICE_STOP( segapcm ) -void device_stop_segapcm(void *chip) -{ - //segapcm_state *spcm = get_safe_token(device); - segapcm_state *spcm = (segapcm_state *) chip; - free(spcm->rom); spcm->rom = NULL; -#ifdef _DEBUG - free(spcm->romusage); -#endif - free(spcm->ram); - - free(spcm); -} - -//static DEVICE_RESET( segapcm ) -void device_reset_segapcm(void *chip) -{ - //segapcm_state *spcm = get_safe_token(device); - segapcm_state *spcm = (segapcm_state *) chip; - - memset(spcm->ram, 0xFF, 0x800); - - return; -} - - -//WRITE8_DEVICE_HANDLER( sega_pcm_w ) -void sega_pcm_w(void *chip, offs_t offset, UINT8 data) -{ - //segapcm_state *spcm = get_safe_token(device); - segapcm_state *spcm = (segapcm_state *) chip; - //stream_update(spcm->stream); - - spcm->ram[offset & 0x07ff] = data; -} - -//READ8_DEVICE_HANDLER( sega_pcm_r ) -UINT8 sega_pcm_r(void *chip, offs_t offset) -{ - //segapcm_state *spcm = get_safe_token(device); - segapcm_state *spcm = (segapcm_state *) chip; - //stream_update(spcm->stream); - return spcm->ram[offset & 0x07ff]; -} - -void sega_pcm_write_rom(void *chip, offs_t ROMSize, offs_t DataStart, offs_t DataLength, - const UINT8* ROMData) -{ - segapcm_state *spcm = (segapcm_state *) chip; - - if (spcm->ROMSize != ROMSize) - { - unsigned long int mask, rom_mask; - - spcm->rom = (UINT8*)realloc(spcm->rom, ROMSize); -#ifdef _DEBUG - spcm->romusage = (UINT8*)realloc(spcm->romusage, ROMSize); -#endif - spcm->ROMSize = ROMSize; - memset(spcm->rom, 0xFF, ROMSize); -#ifdef _DEBUG - memset(spcm->romusage, 0xFF, ROMSize); -#endif - - // recalculate bankmask - mask = spcm->intf.bank >> 16; - if (! mask) - mask = BANK_MASK7 >> 16; - - spcm->rgnmask = ROMSize - 1; - for (rom_mask = 1; rom_mask < ROMSize; rom_mask *= 2); - rom_mask --; - - spcm->bankmask = mask & (rom_mask >> spcm->bankshift); - } - if (DataStart > ROMSize) - return; - if (DataStart + DataLength > ROMSize) - DataLength = ROMSize - DataStart; - - memcpy(spcm->rom + DataStart, ROMData, DataLength); -#ifdef _DEBUG - memset(spcm->romusage + DataStart, 0x00, DataLength); -#endif - - return; -} - - -/*void sega_pcm_fwrite_romusage(UINT8 ChipID) -{ - segapcm_state *spcm = &SPCMData[ChipID]; - - FILE* hFile; - - hFile = fopen("SPCM_ROMUsage.bin", "wb"); - if (hFile == NULL) - return; - - fwrite(spcm->romusage, 0x01, spcm->ROMSize, hFile); - - fclose(hFile); - return; -}*/ - -void segapcm_set_mute_mask(void *chip, UINT32 MuteMask) -{ - segapcm_state *spcm = (segapcm_state *) chip; - unsigned char CurChn; - - for (CurChn = 0; CurChn < 16; CurChn ++) - spcm->Muted[CurChn] = (MuteMask >> CurChn) & 0x01; - - return; -} - - -/************************************************************************** - * Generic get_info - **************************************************************************/ - -/*DEVICE_GET_INFO( segapcm ) -{ - switch (state) - { - // --- the following bits of info are returned as 64-bit signed integers --- - case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(segapcm_state); break; - - // --- the following bits of info are returned as pointers to data or functions --- - case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( segapcm ); break; - case DEVINFO_FCT_STOP: // Nothing break; - case DEVINFO_FCT_RESET: // Nothing break; - - // --- the following bits of info are returned as NULL-terminated strings --- - case DEVINFO_STR_NAME: strcpy(info->s, "Sega PCM"); break; - case DEVINFO_STR_FAMILY: strcpy(info->s, "Sega custom"); break; - case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; - case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; - case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; - } -}*/ +/*********************************************************/ +/* SEGA 16ch 8bit PCM */ +/*********************************************************/ + +#include +#include +#include +//#include "sndintrf.h" +//#include "streams.h" +#include "segapcm.h" + + +typedef struct _segapcm_state segapcm_state; +struct _segapcm_state +{ + UINT8 *ram; + UINT8 low[16]; + UINT32 ROMSize; + UINT8 *rom; +#ifdef _DEBUG + UINT8 *romusage; +#endif + int bankshift; + int bankmask; + int rgnmask; + sega_pcm_interface intf; + UINT8 Muted[16]; + //sound_stream * stream; +}; + +UINT8 SegaPCM_NewCore = 0x00; + +/*INLINE segapcm_state *get_safe_token(const device_config *device) +{ + assert(device != NULL); + assert(device->token != NULL); + assert(device->type == SOUND); + assert(sound_get_type(device) == SOUND_SEGAPCM); + return (segapcm_state *)device->token; +}*/ + +//static STREAM_UPDATE( SEGAPCM_update ) +void SEGAPCM_update(void *chip, stream_sample_t **outputs, int samples) +{ + //segapcm_state *spcm = (segapcm_state *)param; + segapcm_state *spcm = (segapcm_state *) chip; + int rgnmask = spcm->rgnmask; + int ch; + + /* clear the buffers */ + memset(outputs[0], 0, samples*sizeof(stream_sample_t)); + memset(outputs[1], 0, samples*sizeof(stream_sample_t)); + + // reg function + // ------------------------------------------------ + // 0x00 ? + // 0x01 ? + // 0x02 volume left + // 0x03 volume right + // 0x04 loop address (08-15) + // 0x05 loop address (16-23) + // 0x06 end address + // 0x07 address delta + // 0x80 ? + // 0x81 ? + // 0x82 ? + // 0x83 ? + // 0x84 current address (08-15), 00-07 is internal? + // 0x85 current address (16-23) + // 0x86 bit 0: channel disable? + // bit 1: loop disable + // other bits: bank + // 0x87 ? + + /* loop over channels */ + for (ch = 0; ch < 16; ch++) + { +if (! SegaPCM_NewCore) +{ + /* only process active channels */ + if (!(spcm->ram[0x86+8*ch] & 1) && ! spcm->Muted[ch]) + { + UINT8 *base = spcm->ram+8*ch; + UINT8 flags = base[0x86]; + const UINT8 *rom = spcm->rom + ((flags & spcm->bankmask) << spcm->bankshift); +#ifdef _DEBUG + const UINT8 *romusage = spcm->romusage + ((flags & spcm->bankmask) << spcm->bankshift); +#endif + UINT32 addr = (base[5] << 16) | (base[4] << 8) | spcm->low[ch]; + UINT16 loop = (base[0x85] << 8) | base[0x84]; + UINT8 end = base[6] + 1; + UINT8 delta = base[7]; + UINT8 voll = base[2]; + UINT8 volr = base[3]; + int i; + + /* loop over samples on this channel */ + for (i = 0; i < samples; i++) + { + INT8 v = 0; + + /* handle looping if we've hit the end */ + if ((addr >> 16) == end) + { + if (!(flags & 2)) + addr = loop << 8; + else + { + flags |= 1; + break; + } + } + + /* fetch the sample */ + v = rom[(addr >> 8) & rgnmask] - 0x80; +#ifdef _DEBUG + if (romusage[(addr >> 8) & rgnmask] == 0xFF && (voll || volr)) + printf("Access to empty ROM section! (0x%06lX)\n", + ((flags & spcm->bankmask) << spcm->bankshift) + (addr >> 8) & rgnmask); +#endif + + /* apply panning and advance */ + outputs[0][i] += v * voll; + outputs[1][i] += v * volr; + addr += delta; + } + + /* store back the updated address and info */ + base[0x86] = flags; + base[4] = addr >> 8; + base[5] = addr >> 16; + spcm->low[ch] = flags & 1 ? 0 : addr; + } +} +else +{ + UINT8 *regs = spcm->ram+8*ch; + + /* only process active channels */ + if (!(regs[0x86] & 1) && ! spcm->Muted[ch]) + { + const UINT8 *rom = spcm->rom + ((regs[0x86] & spcm->bankmask) << spcm->bankshift); +#ifdef _DEBUG + const UINT8 *romusage = spcm->romusage + ((regs[0x86] & spcm->bankmask) << spcm->bankshift); +#endif + UINT32 addr = (regs[0x85] << 16) | (regs[0x84] << 8) | spcm->low[ch]; + UINT32 loop = (regs[0x05] << 16) | (regs[0x04] << 8); + UINT8 end = regs[6] + 1; + int i; + + /* loop over samples on this channel */ + for (i = 0; i < samples; i++) + { + INT8 v = 0; + + /* handle looping if we've hit the end */ + if ((addr >> 16) == end) + { + if (regs[0x86] & 2) + { + regs[0x86] |= 1; + break; + } + else addr = loop; + } + + /* fetch the sample */ + v = rom[(addr >> 8) & rgnmask] - 0x80; +#ifdef _DEBUG + if (romusage[(addr >> 8) & rgnmask] == 0xFF && (regs[2] || regs[3])) + printf("Access to empty ROM section! (0x%06lX)\n", + ((regs[0x86] & spcm->bankmask) << spcm->bankshift) + (addr >> 8) & rgnmask); +#endif + + /* apply panning and advance */ + outputs[0][i] += v * regs[2]; + outputs[1][i] += v * regs[3]; + addr = (addr + regs[7]) & 0xffffff; + } + + /* store back the updated address */ + regs[0x84] = addr >> 8; + regs[0x85] = addr >> 16; + spcm->low[ch] = regs[0x86] & 1 ? 0 : addr; + } +} + } +} + +//static DEVICE_START( segapcm ) +void * device_start_segapcm(int intf_bank) +{ + const UINT32 STD_ROM_SIZE = 0x80000; + //const sega_pcm_interface *intf = (const sega_pcm_interface *)device->static_config; + sega_pcm_interface *intf; + int mask, rom_mask, len; + //segapcm_state *spcm = get_safe_token(device); + segapcm_state *spcm; + + spcm = (segapcm_state *) malloc(sizeof(segapcm_state)); + if (!spcm) return spcm; + + intf = &spcm->intf; + intf->bank = intf_bank; + + //spcm->rom = (const UINT8 *)device->region; + //spcm->ram = auto_alloc_array(device->machine, UINT8, 0x800); + spcm->ROMSize = STD_ROM_SIZE; + spcm->rom = (UINT8*) malloc(STD_ROM_SIZE); +#ifdef _DEBUG + spcm->romusage = (UINT8*) malloc(STD_ROM_SIZE); +#endif + spcm->ram = (UINT8*) malloc(0x800); + + memset(spcm->rom, 0xFF, STD_ROM_SIZE); +#ifdef _DEBUG + memset(spcm->romusage, 0xFF, STD_ROM_SIZE); +#endif + //memset(spcm->ram, 0xff, 0x800); // RAM Clear is done at device_reset + + spcm->bankshift = (UINT8)(intf->bank); + mask = intf->bank >> 16; + if(!mask) + mask = BANK_MASK7>>16; + + len = STD_ROM_SIZE; + spcm->rgnmask = len - 1; + for(rom_mask = 1; rom_mask < len; rom_mask *= 2); + rom_mask--; + + spcm->bankmask = mask & (rom_mask >> spcm->bankshift); + + //spcm->stream = stream_create(device, 0, 2, device->clock / 128, spcm, SEGAPCM_update); + + //state_save_register_device_item_array(device, 0, spcm->low); + //state_save_register_device_item_pointer(device, 0, spcm->ram, 0x800); + + for (mask = 0; mask < 16; mask ++) + spcm->Muted[mask] = 0x00; + + return spcm; +} + +//static DEVICE_STOP( segapcm ) +void device_stop_segapcm(void *chip) +{ + //segapcm_state *spcm = get_safe_token(device); + segapcm_state *spcm = (segapcm_state *) chip; + free(spcm->rom); spcm->rom = NULL; +#ifdef _DEBUG + free(spcm->romusage); +#endif + free(spcm->ram); + + free(spcm); +} + +//static DEVICE_RESET( segapcm ) +void device_reset_segapcm(void *chip) +{ + //segapcm_state *spcm = get_safe_token(device); + segapcm_state *spcm = (segapcm_state *) chip; + + memset(spcm->ram, 0xFF, 0x800); + + return; +} + + +//WRITE8_DEVICE_HANDLER( sega_pcm_w ) +void sega_pcm_w(void *chip, offs_t offset, UINT8 data) +{ + //segapcm_state *spcm = get_safe_token(device); + segapcm_state *spcm = (segapcm_state *) chip; + //stream_update(spcm->stream); + + spcm->ram[offset & 0x07ff] = data; +} + +//READ8_DEVICE_HANDLER( sega_pcm_r ) +UINT8 sega_pcm_r(void *chip, offs_t offset) +{ + //segapcm_state *spcm = get_safe_token(device); + segapcm_state *spcm = (segapcm_state *) chip; + //stream_update(spcm->stream); + return spcm->ram[offset & 0x07ff]; +} + +void sega_pcm_write_rom(void *chip, offs_t ROMSize, offs_t DataStart, offs_t DataLength, + const UINT8* ROMData) +{ + segapcm_state *spcm = (segapcm_state *) chip; + + if (spcm->ROMSize != ROMSize) + { + unsigned long int mask, rom_mask; + + spcm->rom = (UINT8*)realloc(spcm->rom, ROMSize); +#ifdef _DEBUG + spcm->romusage = (UINT8*)realloc(spcm->romusage, ROMSize); +#endif + spcm->ROMSize = ROMSize; + memset(spcm->rom, 0xFF, ROMSize); +#ifdef _DEBUG + memset(spcm->romusage, 0xFF, ROMSize); +#endif + + // recalculate bankmask + mask = spcm->intf.bank >> 16; + if (! mask) + mask = BANK_MASK7 >> 16; + + spcm->rgnmask = ROMSize - 1; + for (rom_mask = 1; rom_mask < ROMSize; rom_mask *= 2); + rom_mask --; + + spcm->bankmask = mask & (rom_mask >> spcm->bankshift); + } + if (DataStart > ROMSize) + return; + if (DataStart + DataLength > ROMSize) + DataLength = ROMSize - DataStart; + + memcpy(spcm->rom + DataStart, ROMData, DataLength); +#ifdef _DEBUG + memset(spcm->romusage + DataStart, 0x00, DataLength); +#endif + + return; +} + + +/*void sega_pcm_fwrite_romusage(UINT8 ChipID) +{ + segapcm_state *spcm = &SPCMData[ChipID]; + + FILE* hFile; + + hFile = fopen("SPCM_ROMUsage.bin", "wb"); + if (hFile == NULL) + return; + + fwrite(spcm->romusage, 0x01, spcm->ROMSize, hFile); + + fclose(hFile); + return; +}*/ + +void segapcm_set_mute_mask(void *chip, UINT32 MuteMask) +{ + segapcm_state *spcm = (segapcm_state *) chip; + unsigned char CurChn; + + for (CurChn = 0; CurChn < 16; CurChn ++) + spcm->Muted[CurChn] = (MuteMask >> CurChn) & 0x01; + + return; +} + + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +/*DEVICE_GET_INFO( segapcm ) +{ + switch (state) + { + // --- the following bits of info are returned as 64-bit signed integers --- + case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(segapcm_state); break; + + // --- the following bits of info are returned as pointers to data or functions --- + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( segapcm ); break; + case DEVINFO_FCT_STOP: // Nothing break; + case DEVINFO_FCT_RESET: // Nothing break; + + // --- the following bits of info are returned as NULL-terminated strings --- + case DEVINFO_STR_NAME: strcpy(info->s, "Sega PCM"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Sega custom"); break; + case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; + } +}*/ diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/SegaPcm_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/SegaPcm_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/SegaPcm_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/SegaPcm_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,77 +1,77 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "SegaPcm_Emu.h" -#include "segapcm.h" - -SegaPcm_Emu::SegaPcm_Emu() { chip = 0; } - -SegaPcm_Emu::~SegaPcm_Emu() -{ - if ( chip ) device_stop_segapcm( chip ); -} - -int SegaPcm_Emu::set_rate( int intf_type ) -{ - if ( chip ) - { - device_stop_segapcm( chip ); - chip = 0; - } - - chip = device_start_segapcm( intf_type ); - if ( !chip ) - return 1; - - reset(); - return 0; -} - -void SegaPcm_Emu::reset() -{ - device_reset_segapcm( chip ); - segapcm_set_mute_mask( chip, 0 ); -} - -void SegaPcm_Emu::write( int addr, int data ) -{ - sega_pcm_w( chip, addr, data ); -} - -void SegaPcm_Emu::write_rom( int size, int start, int length, void * data ) -{ - sega_pcm_write_rom( chip, size, start, length, (const UINT8 *) data ); -} - -void SegaPcm_Emu::mute_voices( int mask ) -{ - segapcm_set_mute_mask( chip, mask ); -} - -void SegaPcm_Emu::run( int pair_count, sample_t* out ) -{ - stream_sample_t bufL[ 1024 ]; - stream_sample_t bufR[ 1024 ]; - stream_sample_t * buffers[2] = { bufL, bufR }; - - while (pair_count > 0) - { - int todo = pair_count; - if (todo > 1024) todo = 1024; - SEGAPCM_update( chip, buffers, todo ); - - for (int i = 0; i < todo; i++) - { - int output_l = bufL [i]; - int output_r = bufR [i]; - output_l += out [0]; - output_r += out [1]; - if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); - if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); - out [0] = output_l; - out [1] = output_r; - out += 2; - } - - pair_count -= todo; - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "SegaPcm_Emu.h" +#include "segapcm.h" + +SegaPcm_Emu::SegaPcm_Emu() { chip = 0; } + +SegaPcm_Emu::~SegaPcm_Emu() +{ + if ( chip ) device_stop_segapcm( chip ); +} + +int SegaPcm_Emu::set_rate( int intf_type ) +{ + if ( chip ) + { + device_stop_segapcm( chip ); + chip = 0; + } + + chip = device_start_segapcm( intf_type ); + if ( !chip ) + return 1; + + reset(); + return 0; +} + +void SegaPcm_Emu::reset() +{ + device_reset_segapcm( chip ); + segapcm_set_mute_mask( chip, 0 ); +} + +void SegaPcm_Emu::write( int addr, int data ) +{ + sega_pcm_w( chip, addr, data ); +} + +void SegaPcm_Emu::write_rom( int size, int start, int length, void * data ) +{ + sega_pcm_write_rom( chip, size, start, length, (const UINT8 *) data ); +} + +void SegaPcm_Emu::mute_voices( int mask ) +{ + segapcm_set_mute_mask( chip, mask ); +} + +void SegaPcm_Emu::run( int pair_count, sample_t* out ) +{ + stream_sample_t bufL[ 1024 ]; + stream_sample_t bufR[ 1024 ]; + stream_sample_t * buffers[2] = { bufL, bufR }; + + while (pair_count > 0) + { + int todo = pair_count; + if (todo > 1024) todo = 1024; + SEGAPCM_update( chip, buffers, todo ); + + for (int i = 0; i < todo; i++) + { + int output_l = bufL [i]; + int output_r = bufR [i]; + output_l += out [0]; + output_r += out [1]; + if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); + if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); + out [0] = output_l; + out [1] = output_r; + out += 2; + } + + pair_count -= todo; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/SegaPcm_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/SegaPcm_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/SegaPcm_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/SegaPcm_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,36 +1,36 @@ -// Sega PCM sound chip emulator interface - -// Game_Music_Emu $vers -#ifndef SEGAPCM_EMU_H -#define SEGAPCM_EMU_H - -class SegaPcm_Emu { - void* chip; -public: - SegaPcm_Emu(); - ~SegaPcm_Emu(); - - // Sets output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - int set_rate( int intf_type ); - - // Resets to power-up state - void reset(); - - // Mutes voice n if bit n (1 << n) of mask is set - enum { channel_count = 16 }; - void mute_voices( int mask ); - - // Writes data to addr - void write( int addr, int data ); - - // Scales ROM size, then writes length bytes from data at start offset - void write_rom( int size, int start, int length, void * data ); - - // Runs and writes pair_count*2 samples to output - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif +// Sega PCM sound chip emulator interface + +// Game_Music_Emu $vers +#ifndef SEGAPCM_EMU_H +#define SEGAPCM_EMU_H + +class SegaPcm_Emu { + void* chip; +public: + SegaPcm_Emu(); + ~SegaPcm_Emu(); + + // Sets output sample rate and chip clock rates, in Hz. Returns non-zero + // if error. + int set_rate( int intf_type ); + + // Resets to power-up state + void reset(); + + // Mutes voice n if bit n (1 << n) of mask is set + enum { channel_count = 16 }; + void mute_voices( int mask ); + + // Writes data to addr + void write( int addr, int data ); + + // Scales ROM size, then writes length bytes from data at start offset + void write_rom( int size, int start, int length, void * data ); + + // Runs and writes pair_count*2 samples to output + typedef short sample_t; + enum { out_chan_count = 2 }; // stereo + void run( int pair_count, sample_t* out ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/segapcm.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/segapcm.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/segapcm.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/segapcm.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,48 +1,48 @@ -/*********************************************************/ -/* SEGA 8bit PCM */ -/*********************************************************/ - -#pragma once - -#include "mamedef.h" - -#define BANK_256 (11) -#define BANK_512 (12) -#define BANK_12M (13) -#define BANK_MASK7 (0x70<<16) -#define BANK_MASKF (0xf0<<16) -#define BANK_MASKF8 (0xf8<<16) - -typedef struct _sega_pcm_interface sega_pcm_interface; -struct _sega_pcm_interface -{ - int bank; -}; - -/*WRITE8_DEVICE_HANDLER( sega_pcm_w ); -READ8_DEVICE_HANDLER( sega_pcm_r ); - -DEVICE_GET_INFO( segapcm ); -#define SOUND_SEGAPCM DEVICE_GET_INFO_NAME( segapcm )*/ - -#ifdef __cplusplus -extern "C" { -#endif - -void SEGAPCM_update(void *chip, stream_sample_t **outputs, int samples); - -void * device_start_segapcm(int intf_bank); -void device_stop_segapcm(void *chip); -void device_reset_segapcm(void *chip); - -void sega_pcm_w(void *chip, offs_t offset, UINT8 data); -UINT8 sega_pcm_r(void *chip, offs_t offset); -void sega_pcm_write_rom(void *chip, offs_t ROMSize, offs_t DataStart, offs_t DataLength, - const UINT8* ROMData); - -//void sega_pcm_fwrite_romusage(UINT8 ChipID); -void segapcm_set_mute_mask(void *chip, UINT32 MuteMask); - -#ifdef __cplusplus -} -#endif +/*********************************************************/ +/* SEGA 8bit PCM */ +/*********************************************************/ + +#pragma once + +#include "mamedef.h" + +#define BANK_256 (11) +#define BANK_512 (12) +#define BANK_12M (13) +#define BANK_MASK7 (0x70<<16) +#define BANK_MASKF (0xf0<<16) +#define BANK_MASKF8 (0xf8<<16) + +typedef struct _sega_pcm_interface sega_pcm_interface; +struct _sega_pcm_interface +{ + int bank; +}; + +/*WRITE8_DEVICE_HANDLER( sega_pcm_w ); +READ8_DEVICE_HANDLER( sega_pcm_r ); + +DEVICE_GET_INFO( segapcm ); +#define SOUND_SEGAPCM DEVICE_GET_INFO_NAME( segapcm )*/ + +#ifdef __cplusplus +extern "C" { +#endif + +void SEGAPCM_update(void *chip, stream_sample_t **outputs, int samples); + +void * device_start_segapcm(int intf_bank); +void device_stop_segapcm(void *chip); +void device_reset_segapcm(void *chip); + +void sega_pcm_w(void *chip, offs_t offset, UINT8 data); +UINT8 sega_pcm_r(void *chip, offs_t offset); +void sega_pcm_write_rom(void *chip, offs_t ROMSize, offs_t DataStart, offs_t DataLength, + const UINT8* ROMData); + +//void sega_pcm_fwrite_romusage(UINT8 ChipID); +void segapcm_set_mute_mask(void *chip, UINT32 MuteMask); + +#ifdef __cplusplus +} +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Core.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Core.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Core.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Core.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,108 +1,108 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Sgc_Core.h" - -/* Copyright (C) 2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -void Sgc_Core::set_tempo( double t ) -{ - set_play_period( clock_rate() / (header().rate ? 50 : 60) / t ); -} - -blargg_err_t Sgc_Core::load_( Data_Reader& dr ) -{ - RETURN_ERR( Sgc_Impl::load_( dr ) ); - - if ( sega_mapping() && fm_apu_.supported() ) - RETURN_ERR( fm_apu_.init( clock_rate(), clock_rate() / 72 ) ); - - set_tempo( 1.0 ); - return blargg_ok; -} - -blargg_err_t Sgc_Core::start_track( int t ) -{ - if ( sega_mapping() ) - { - apu_.reset(); - fm_apu_.reset(); - fm_accessed = false; - } - else - { - apu_.reset( 0x0003, 15 ); - } - - return Sgc_Impl::start_track( t ); -} - -blargg_err_t Sgc_Core::end_frame( time_t t ) -{ - RETURN_ERR( Sgc_Impl::end_frame( t ) ); - apu_.end_frame( t ); - if ( sega_mapping() && fm_accessed ) - { - if ( fm_apu_.supported() ) - fm_apu_.end_frame( t ); - else - set_warning( "FM sound not supported" ); - } - - return blargg_ok; -} - -Sgc_Core::Sgc_Core() -{ } - -Sgc_Core::~Sgc_Core() -{ } - -void Sgc_Core::cpu_out( time_t time, addr_t addr, int data ) -{ - int port = addr & 0xFF; - - if ( sega_mapping() ) - { - switch ( port ) - { - case 0x06: - apu_.write_ggstereo( time, data ); - return; - - case 0x7E: - case 0x7F: - apu_.write_data( time, data ); dprintf( "$7E<-%02X\n", data ); - return; - - case 0xF0: - fm_accessed = true; - if ( fm_apu_.supported() ) - fm_apu_.write_addr( data );//, dprintf( "$F0<-%02X\n", data ); - return; - - case 0xF1: - fm_accessed = true; - if ( fm_apu_.supported() ) - fm_apu_.write_data( time, data );//, dprintf( "$F1<-%02X\n", data ); - return; - } - } - else if ( port >= 0xE0 ) - { - apu_.write_data( time, data ); - return; - } - - Sgc_Impl::cpu_out( time, addr, data ); -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Sgc_Core.h" + +/* Copyright (C) 2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +void Sgc_Core::set_tempo( double t ) +{ + set_play_period( clock_rate() / (header().rate ? 50 : 60) / t ); +} + +blargg_err_t Sgc_Core::load_( Data_Reader& dr ) +{ + RETURN_ERR( Sgc_Impl::load_( dr ) ); + + if ( sega_mapping() && fm_apu_.supported() ) + RETURN_ERR( fm_apu_.init( clock_rate(), clock_rate() / 72 ) ); + + set_tempo( 1.0 ); + return blargg_ok; +} + +blargg_err_t Sgc_Core::start_track( int t ) +{ + if ( sega_mapping() ) + { + apu_.reset(); + fm_apu_.reset(); + fm_accessed = false; + } + else + { + apu_.reset( 0x0003, 15 ); + } + + return Sgc_Impl::start_track( t ); +} + +blargg_err_t Sgc_Core::end_frame( time_t t ) +{ + RETURN_ERR( Sgc_Impl::end_frame( t ) ); + apu_.end_frame( t ); + if ( sega_mapping() && fm_accessed ) + { + if ( fm_apu_.supported() ) + fm_apu_.end_frame( t ); + else + set_warning( "FM sound not supported" ); + } + + return blargg_ok; +} + +Sgc_Core::Sgc_Core() +{ } + +Sgc_Core::~Sgc_Core() +{ } + +void Sgc_Core::cpu_out( time_t time, addr_t addr, int data ) +{ + int port = addr & 0xFF; + + if ( sega_mapping() ) + { + switch ( port ) + { + case 0x06: + apu_.write_ggstereo( time, data ); + return; + + case 0x7E: + case 0x7F: + apu_.write_data( time, data ); dprintf( "$7E<-%02X\n", data ); + return; + + case 0xF0: + fm_accessed = true; + if ( fm_apu_.supported() ) + fm_apu_.write_addr( data );//, dprintf( "$F0<-%02X\n", data ); + return; + + case 0xF1: + fm_accessed = true; + if ( fm_apu_.supported() ) + fm_apu_.write_data( time, data );//, dprintf( "$F1<-%02X\n", data ); + return; + } + } + else if ( port >= 0xE0 ) + { + apu_.write_data( time, data ); + return; + } + + Sgc_Impl::cpu_out( time, addr, data ); +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Core.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Core.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Core.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Core.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,44 +1,44 @@ -// Sega/Game Gear/Coleco SGC music file emulator core - -// Game_Music_Emu $vers -#ifndef SGC_CORE_H -#define SGC_CORE_H - -#include "Sgc_Impl.h" -#include "Sms_Fm_Apu.h" -#include "Sms_Apu.h" - -class Sgc_Core : public Sgc_Impl { -public: - - // Adjusts music tempo, where 1.0 is normal. Can be changed while playing. - // Resets to 1.0 when loading file. - void set_tempo( double ); - - // Starts track, where 0 is the first. - blargg_err_t start_track( int ); - - // Ends time frame at time t - blargg_err_t end_frame( time_t t ); - - // SN76489 sound chip - Sms_Apu& apu() { return apu_; } - Sms_Fm_Apu& fm_apu() { return fm_apu_; } - -protected: - // Overrides - virtual void cpu_out( time_t, addr_t, int data ); - virtual blargg_err_t load_( Data_Reader& ); - -// Implementation -public: - Sgc_Core(); - ~Sgc_Core(); - -private: - bool fm_accessed; - Sms_Apu apu_; - Sms_Fm_Apu fm_apu_; -}; - -#endif +// Sega/Game Gear/Coleco SGC music file emulator core + +// Game_Music_Emu $vers +#ifndef SGC_CORE_H +#define SGC_CORE_H + +#include "Sgc_Impl.h" +#include "Sms_Fm_Apu.h" +#include "Sms_Apu.h" + +class Sgc_Core : public Sgc_Impl { +public: + + // Adjusts music tempo, where 1.0 is normal. Can be changed while playing. + // Resets to 1.0 when loading file. + void set_tempo( double ); + + // Starts track, where 0 is the first. + blargg_err_t start_track( int ); + + // Ends time frame at time t + blargg_err_t end_frame( time_t t ); + + // SN76489 sound chip + Sms_Apu& apu() { return apu_; } + Sms_Fm_Apu& fm_apu() { return fm_apu_; } + +protected: + // Overrides + virtual void cpu_out( time_t, addr_t, int data ); + virtual blargg_err_t load_( Data_Reader& ); + +// Implementation +public: + Sgc_Core(); + ~Sgc_Core(); + +private: + bool fm_accessed; + Sms_Apu apu_; + Sms_Fm_Apu fm_apu_; +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Cpu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Cpu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Cpu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Cpu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,36 +1,36 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Sgc_Impl.h" - -#include "blargg_endian.h" -//#include "z80_cpu_log.h" - -/* Copyright (C) 2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#define OUT_PORT( addr, data ) cpu_out( TIME(), addr, data ) -#define IN_PORT( addr ) cpu_in( addr ) -#define WRITE_MEM( addr, data ) cpu_write( addr, data ) -#define IDLE_ADDR idle_addr -#define CPU cpu -#define RST_BASE vectors_addr - -#define CPU_BEGIN \ -bool Sgc_Impl::run_cpu( time_t end_time )\ -{\ - cpu.set_end_time( end_time ); - - #include "Z80_Cpu_run.h" - - return warning; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Sgc_Impl.h" + +#include "blargg_endian.h" +//#include "z80_cpu_log.h" + +/* Copyright (C) 2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#define OUT_PORT( addr, data ) cpu_out( TIME(), addr, data ) +#define IN_PORT( addr ) cpu_in( addr ) +#define WRITE_MEM( addr, data ) cpu_write( addr, data ) +#define IDLE_ADDR idle_addr +#define CPU cpu +#define RST_BASE vectors_addr + +#define CPU_BEGIN \ +bool Sgc_Impl::run_cpu( time_t end_time )\ +{\ + cpu.set_end_time( end_time ); + + #include "Z80_Cpu_run.h" + + return warning; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,167 +1,167 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Sgc_Emu.h" - -/* Copyright (C) 2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const osc_count = Sms_Apu::osc_count + Sms_Fm_Apu::osc_count; - -Sgc_Emu::Sgc_Emu() -{ - set_type( gme_sgc_type ); - set_silence_lookahead( 6 ); - set_gain( 1.2 ); -} - -Sgc_Emu::~Sgc_Emu() { } - -void Sgc_Emu::unload() -{ - core_.unload(); - Music_Emu::unload(); -} - -// Track info - -static void copy_sgc_fields( Sgc_Emu::header_t const& h, track_info_t* out ) -{ - GME_COPY_FIELD( h, out, game ); - GME_COPY_FIELD( h, out, author ); - GME_COPY_FIELD( h, out, copyright ); -} - -static void hash_sgc_file( Sgc_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( &h.vers, sizeof(h.vers) ); - out.hash_( &h.rate, sizeof(h.rate) ); - out.hash_( &h.reserved1[0], sizeof(h.reserved1) ); - out.hash_( &h.load_addr[0], sizeof(h.load_addr) ); - out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); - out.hash_( &h.play_addr[0], sizeof(h.play_addr) ); - out.hash_( &h.stack_ptr[0], sizeof(h.stack_ptr) ); - out.hash_( &h.reserved2[0], sizeof(h.reserved2) ); - out.hash_( &h.rst_addrs[0], sizeof(h.rst_addrs) ); - out.hash_( &h.mapping[0], sizeof(h.mapping) ); - out.hash_( &h.first_song, sizeof(h.first_song) ); - out.hash_( &h.song_count, sizeof(h.song_count) ); - out.hash_( &h.first_effect, sizeof(h.first_effect) ); - out.hash_( &h.last_effect, sizeof(h.last_effect) ); - out.hash_( &h.system, sizeof(h.system) ); - out.hash_( &h.reserved3[0], sizeof(h.reserved3) ); - out.hash_( data, data_size ); -} - -blargg_err_t Sgc_Emu::track_info_( track_info_t* out, int ) const -{ - copy_sgc_fields( header(), out ); - return blargg_ok; -} - -struct Sgc_File : Gme_Info_ -{ - Sgc_Emu::header_t const* h; - - Sgc_File() { set_type( gme_sgc_type ); } - - blargg_err_t load_mem_( byte const begin [], int size ) - { - h = ( Sgc_Emu::header_t const* ) begin; - - set_track_count( h->song_count ); - if ( !h->valid_tag() ) - return blargg_err_file_type; - - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_sgc_fields( *h, out ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_sgc_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out ); - return blargg_ok; - } -}; - -static Music_Emu* new_sgc_emu () { return BLARGG_NEW Sgc_Emu ; } -static Music_Emu* new_sgc_file() { return BLARGG_NEW Sgc_File; } - -gme_type_t_ const gme_sgc_type [1] = {{ "Z80 PSG", 0, &new_sgc_emu, &new_sgc_file, "SGC", 1 }}; - -// Setup - -blargg_err_t Sgc_Emu::load_( Data_Reader& in ) -{ - RETURN_ERR( core_.load( in ) ); - set_warning( core_.warning() ); - set_track_count( header().song_count ); - set_voice_count( core_.sega_mapping() ? osc_count : core_.apu().osc_count ); - - core_.apu ().volume( gain() ); - core_.fm_apu().volume( gain() ); - - static const char* const names [osc_count + 1] = { - "Square 1", "Square 2", "Square 3", "Noise", "FM" - }; - set_voice_names( names ); - - static int const types [osc_count + 1] = { - wave_type+1, wave_type+2, wave_type+3, mixed_type+1, mixed_type+2 - }; - set_voice_types( types ); - - return setup_buffer( core_.clock_rate() ); -} - -void Sgc_Emu::update_eq( blip_eq_t const& eq ) -{ - core_.apu ().treble_eq( eq ); - core_.fm_apu().treble_eq( eq ); -} - -void Sgc_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) -{ - if ( i < core_.apu().osc_count ) - core_.apu().set_output( i, c, l, r ); - else - core_.fm_apu().set_output( c, l, r ); -} - -void Sgc_Emu::set_tempo_( double t ) -{ - core_.set_tempo( t ); -} - -blargg_err_t Sgc_Emu::start_track_( int track ) -{ - RETURN_ERR( core_.start_track( track ) ); - return Classic_Emu::start_track_( track ); -} - -blargg_err_t Sgc_Emu::run_clocks( blip_time_t& duration, int ) -{ - RETURN_ERR( core_.end_frame( duration ) ); - set_warning( core_.warning() ); - return blargg_ok; -} - -blargg_err_t Sgc_Emu::hash_( Hash_Function& out ) const -{ - hash_sgc_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out ); - return blargg_ok; +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Sgc_Emu.h" + +/* Copyright (C) 2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const osc_count = Sms_Apu::osc_count + Sms_Fm_Apu::osc_count; + +Sgc_Emu::Sgc_Emu() +{ + set_type( gme_sgc_type ); + set_silence_lookahead( 6 ); + set_gain( 1.2 ); +} + +Sgc_Emu::~Sgc_Emu() { } + +void Sgc_Emu::unload() +{ + core_.unload(); + Music_Emu::unload(); +} + +// Track info + +static void copy_sgc_fields( Sgc_Emu::header_t const& h, track_info_t* out ) +{ + GME_COPY_FIELD( h, out, game ); + GME_COPY_FIELD( h, out, author ); + GME_COPY_FIELD( h, out, copyright ); +} + +static void hash_sgc_file( Sgc_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( &h.vers, sizeof(h.vers) ); + out.hash_( &h.rate, sizeof(h.rate) ); + out.hash_( &h.reserved1[0], sizeof(h.reserved1) ); + out.hash_( &h.load_addr[0], sizeof(h.load_addr) ); + out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); + out.hash_( &h.play_addr[0], sizeof(h.play_addr) ); + out.hash_( &h.stack_ptr[0], sizeof(h.stack_ptr) ); + out.hash_( &h.reserved2[0], sizeof(h.reserved2) ); + out.hash_( &h.rst_addrs[0], sizeof(h.rst_addrs) ); + out.hash_( &h.mapping[0], sizeof(h.mapping) ); + out.hash_( &h.first_song, sizeof(h.first_song) ); + out.hash_( &h.song_count, sizeof(h.song_count) ); + out.hash_( &h.first_effect, sizeof(h.first_effect) ); + out.hash_( &h.last_effect, sizeof(h.last_effect) ); + out.hash_( &h.system, sizeof(h.system) ); + out.hash_( &h.reserved3[0], sizeof(h.reserved3) ); + out.hash_( data, data_size ); +} + +blargg_err_t Sgc_Emu::track_info_( track_info_t* out, int ) const +{ + copy_sgc_fields( header(), out ); + return blargg_ok; +} + +struct Sgc_File : Gme_Info_ +{ + Sgc_Emu::header_t const* h; + + Sgc_File() { set_type( gme_sgc_type ); } + + blargg_err_t load_mem_( byte const begin [], int size ) + { + h = ( Sgc_Emu::header_t const* ) begin; + + set_track_count( h->song_count ); + if ( !h->valid_tag() ) + return blargg_err_file_type; + + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + copy_sgc_fields( *h, out ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_sgc_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out ); + return blargg_ok; + } +}; + +static Music_Emu* new_sgc_emu () { return BLARGG_NEW Sgc_Emu ; } +static Music_Emu* new_sgc_file() { return BLARGG_NEW Sgc_File; } + +gme_type_t_ const gme_sgc_type [1] = {{ "Z80 PSG", 0, &new_sgc_emu, &new_sgc_file, "SGC", 1 }}; + +// Setup + +blargg_err_t Sgc_Emu::load_( Data_Reader& in ) +{ + RETURN_ERR( core_.load( in ) ); + set_warning( core_.warning() ); + set_track_count( header().song_count ); + set_voice_count( core_.sega_mapping() ? osc_count : core_.apu().osc_count ); + + core_.apu ().volume( gain() ); + core_.fm_apu().volume( gain() ); + + static const char* const names [osc_count + 1] = { + "Square 1", "Square 2", "Square 3", "Noise", "FM" + }; + set_voice_names( names ); + + static int const types [osc_count + 1] = { + wave_type+1, wave_type+2, wave_type+3, mixed_type+1, mixed_type+2 + }; + set_voice_types( types ); + + return setup_buffer( core_.clock_rate() ); +} + +void Sgc_Emu::update_eq( blip_eq_t const& eq ) +{ + core_.apu ().treble_eq( eq ); + core_.fm_apu().treble_eq( eq ); +} + +void Sgc_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) +{ + if ( i < core_.apu().osc_count ) + core_.apu().set_output( i, c, l, r ); + else + core_.fm_apu().set_output( c, l, r ); +} + +void Sgc_Emu::set_tempo_( double t ) +{ + core_.set_tempo( t ); +} + +blargg_err_t Sgc_Emu::start_track_( int track ) +{ + RETURN_ERR( core_.start_track( track ) ); + return Classic_Emu::start_track_( track ); +} + +blargg_err_t Sgc_Emu::run_clocks( blip_time_t& duration, int ) +{ + RETURN_ERR( core_.end_frame( duration ) ); + set_warning( core_.warning() ); + return blargg_ok; +} + +blargg_err_t Sgc_Emu::hash_( Hash_Function& out ) const +{ + hash_sgc_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out ); + return blargg_ok; } \ No newline at end of file diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,45 +1,45 @@ -// Sega/Game Gear/Coleco SGC music file emulator - -// Game_Music_Emu $vers -#ifndef SGC_EMU_H -#define SGC_EMU_H - -#include "Classic_Emu.h" -#include "Sgc_Core.h" - -class Sgc_Emu : public Classic_Emu { -public: - // SGC file header (see Sgc_Impl.h) - typedef Sgc_Core::header_t header_t; - - // Header for currently loaded file - header_t const& header() const { return core_.header(); } - - blargg_err_t hash_( Hash_Function& ) const; - - // Sets 0x2000-byte Coleco BIOS. Necessary to play Coleco tracks. - static void set_coleco_bios( void const* p ){ Sgc_Core::set_coleco_bios( p ); } - - static gme_type_t static_type() { return gme_sgc_type; } - -// Internal -public: - Sgc_Emu(); - ~Sgc_Emu(); - -protected: - // Classic_Emu overrides - virtual blargg_err_t track_info_( track_info_t*, int track ) const; - virtual blargg_err_t load_( Data_Reader& ); - virtual blargg_err_t start_track_( int ); - virtual blargg_err_t run_clocks( blip_time_t&, int ); - virtual void set_tempo_( double ); - virtual void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); - virtual void update_eq( blip_eq_t const& ); - virtual void unload(); - -private: - Sgc_Core core_; -}; - -#endif +// Sega/Game Gear/Coleco SGC music file emulator + +// Game_Music_Emu $vers +#ifndef SGC_EMU_H +#define SGC_EMU_H + +#include "Classic_Emu.h" +#include "Sgc_Core.h" + +class Sgc_Emu : public Classic_Emu { +public: + // SGC file header (see Sgc_Impl.h) + typedef Sgc_Core::header_t header_t; + + // Header for currently loaded file + header_t const& header() const { return core_.header(); } + + blargg_err_t hash_( Hash_Function& ) const; + + // Sets 0x2000-byte Coleco BIOS. Necessary to play Coleco tracks. + static void set_coleco_bios( void const* p ){ Sgc_Core::set_coleco_bios( p ); } + + static gme_type_t static_type() { return gme_sgc_type; } + +// Internal +public: + Sgc_Emu(); + ~Sgc_Emu(); + +protected: + // Classic_Emu overrides + virtual blargg_err_t track_info_( track_info_t*, int track ) const; + virtual blargg_err_t load_( Data_Reader& ); + virtual blargg_err_t start_track_( int ); + virtual blargg_err_t run_clocks( blip_time_t&, int ); + virtual void set_tempo_( double ); + virtual void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); + virtual void update_eq( blip_eq_t const& ); + virtual void unload(); + +private: + Sgc_Core core_; +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Impl.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Impl.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Impl.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Impl.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,225 +1,225 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Sgc_Impl.h" - -/* Copyright (C) 2006-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -void const* Sgc_Impl::coleco_bios; - -Sgc_Impl::Sgc_Impl() : - rom( bank_size ) -{ - assert( offsetof (header_t,copyright [32]) == header_t::size ); -} - -Sgc_Impl::~Sgc_Impl() -{ } - -bool Sgc_Impl::header_t::valid_tag() const -{ - return 0 == memcmp( tag, "SGC\x1A", 4 ); -} - -blargg_err_t Sgc_Impl::load_( Data_Reader& in ) -{ - RETURN_ERR( rom.load( in, header_.size, &header_, 0 ) ); - - if ( !header_.valid_tag() ) - return blargg_err_file_type; - - if ( header_.vers != 1 ) - set_warning( "Unknown file version" ); - - if ( header_.system > 2 ) - set_warning( "Unknown system" ); - - addr_t load_addr = get_le16( header_.load_addr ); - if ( load_addr < 0x400 ) - set_warning( "Invalid load address" ); - - rom.set_addr( load_addr ); - play_period = clock_rate() / 60; - - if ( sega_mapping() ) - { - RETURN_ERR( ram.resize( 0x2000 + Sgc_Cpu::page_padding ) ); - RETURN_ERR( ram2.resize( bank_size + Sgc_Cpu::page_padding ) ); - } - else - { - RETURN_ERR( ram.resize( 0x400 + Sgc_Cpu::page_padding ) ); - } - - RETURN_ERR( vectors.resize( Sgc_Cpu::page_size + Sgc_Cpu::page_padding ) ); - - // TODO: doesn't need to be larger than page size, if we do mapping calls right - RETURN_ERR( unmapped_write.resize( bank_size ) ); - - return blargg_ok; -} - -void Sgc_Impl::unload() -{ - rom.clear(); - vectors.clear(); - ram.clear(); - ram2.clear(); - unmapped_write.clear(); - Gme_Loader::unload(); -} - -blargg_err_t Sgc_Impl::start_track( int track ) -{ - memset( ram .begin(), 0, ram .size() ); - memset( ram2.begin(), 0, ram2.size() ); - memset( vectors.begin(), 0xFF, vectors.size() ); - cpu.reset( unmapped_write.begin(), rom.unmapped() ); - - if ( sega_mapping() ) - { - vectors_addr = 0x10000 - Sgc_Cpu::page_size; - idle_addr = vectors_addr; - for ( int i = 1; i < 8; ++i ) - { - vectors [i*8 + 0] = 0xC3; // JP addr - vectors [i*8 + 1] = header_.rst_addrs [i*2 + 0]; - vectors [i*8 + 2] = header_.rst_addrs [i*2 + 1]; - } - - cpu.map_mem( 0xC000, 0x2000, ram.begin() ); - cpu.map_mem( vectors_addr, cpu.page_size, unmapped_write.begin(), vectors.begin() ); - - bank2 = NULL; - for ( int i = 0; i < 4; ++i ) - cpu_write( 0xFFFC + i, header_.mapping [i] ); - } - else - { - if ( !coleco_bios ) - return BLARGG_ERR( BLARGG_ERR_CALLER, "Coleco BIOS not set" ); - - vectors_addr = 0; - cpu.map_mem( 0, 0x2000, unmapped_write.begin(), coleco_bios ); - for ( int i = 0; i < 8; ++i ) - cpu.map_mem( 0x6000 + i*0x400, 0x400, ram.begin() ); - - idle_addr = 0x2000; - cpu.map_mem( 0x2000, cpu.page_size, unmapped_write.begin(), vectors.begin() ); - - for ( int i = 0; i < 0x8000 / bank_size; ++i ) - { - int addr = 0x8000 + i*bank_size; - cpu.map_mem( addr, bank_size, unmapped_write.begin(), rom.at_addr( addr ) ); - } - } - - cpu.r.sp = get_le16( header_.stack_ptr ); - cpu.r.b.a = track; - next_play = play_period; - - jsr( header_.init_addr ); - - return blargg_ok; -} - -// Emulation - -void Sgc_Impl::jsr( byte const (&addr) [2] ) -{ - *cpu.write( --cpu.r.sp ) = idle_addr >> 8; - *cpu.write( --cpu.r.sp ) = idle_addr & 0xFF; - cpu.r.pc = get_le16( addr ); -} - -void Sgc_Impl::set_bank( int bank, void const* data ) -{ - //dprintf( "map bank %d to %p\n", bank, (byte*) data - rom.at_addr( 0 ) ); - cpu.map_mem( bank * bank_size, bank_size, unmapped_write.begin(), data ); -} - -void Sgc_Impl::cpu_write( addr_t addr, int data ) -{ - if ( (addr ^ 0xFFFC) > 3 || !sega_mapping() ) - { - *cpu.write( addr ) = data; - return; - } - - switch ( addr ) - { - case 0xFFFC: - cpu.map_mem( 2 * bank_size, bank_size, ram2.begin() ); - if ( data & 0x08 ) - break; - - bank2 = ram2.begin(); - // FALL THROUGH - - case 0xFFFF: { - bool rom_mapped = (cpu.read( 2 * bank_size ) == bank2); - bank2 = rom.at_addr( data * bank_size ); - if ( rom_mapped ) - set_bank( 2, bank2 ); - break; - } - - case 0xFFFD: - set_bank( 0, rom.at_addr( data * bank_size ) ); - break; - - case 0xFFFE: - set_bank( 1, rom.at_addr( data * bank_size ) ); - break; - } -} - -int Sgc_Impl::cpu_in( addr_t addr ) -{ - dprintf( "in %02X\n", addr ); - return 0; -} - -void Sgc_Impl::cpu_out( time_t, addr_t addr, int ) -{ - dprintf( "out %02X\n", addr & 0xFF ); -} - -blargg_err_t Sgc_Impl::end_frame( time_t end ) -{ - while ( cpu.time() < end ) - { - time_t next = min( end, next_play ); - if ( run_cpu( next ) ) - { - set_warning( "Unsupported CPU instruction" ); - cpu.set_time( next ); - } - - if ( cpu.r.pc == idle_addr ) - cpu.set_time( next ); - - if ( cpu.time() >= next_play ) - { - next_play += play_period; - if ( cpu.r.pc == idle_addr ) - jsr( header_.play_addr ); - } - } - - next_play -= end; - check( next_play >= 0 ); - cpu.adjust_time( -end ); - - return blargg_ok; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Sgc_Impl.h" + +/* Copyright (C) 2006-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +void const* Sgc_Impl::coleco_bios; + +Sgc_Impl::Sgc_Impl() : + rom( bank_size ) +{ + assert( offsetof (header_t,copyright [32]) == header_t::size ); +} + +Sgc_Impl::~Sgc_Impl() +{ } + +bool Sgc_Impl::header_t::valid_tag() const +{ + return 0 == memcmp( tag, "SGC\x1A", 4 ); +} + +blargg_err_t Sgc_Impl::load_( Data_Reader& in ) +{ + RETURN_ERR( rom.load( in, header_.size, &header_, 0 ) ); + + if ( !header_.valid_tag() ) + return blargg_err_file_type; + + if ( header_.vers != 1 ) + set_warning( "Unknown file version" ); + + if ( header_.system > 2 ) + set_warning( "Unknown system" ); + + addr_t load_addr = get_le16( header_.load_addr ); + if ( load_addr < 0x400 ) + set_warning( "Invalid load address" ); + + rom.set_addr( load_addr ); + play_period = clock_rate() / 60; + + if ( sega_mapping() ) + { + RETURN_ERR( ram.resize( 0x2000 + Sgc_Cpu::page_padding ) ); + RETURN_ERR( ram2.resize( bank_size + Sgc_Cpu::page_padding ) ); + } + else + { + RETURN_ERR( ram.resize( 0x400 + Sgc_Cpu::page_padding ) ); + } + + RETURN_ERR( vectors.resize( Sgc_Cpu::page_size + Sgc_Cpu::page_padding ) ); + + // TODO: doesn't need to be larger than page size, if we do mapping calls right + RETURN_ERR( unmapped_write.resize( bank_size ) ); + + return blargg_ok; +} + +void Sgc_Impl::unload() +{ + rom.clear(); + vectors.clear(); + ram.clear(); + ram2.clear(); + unmapped_write.clear(); + Gme_Loader::unload(); +} + +blargg_err_t Sgc_Impl::start_track( int track ) +{ + memset( ram .begin(), 0, ram .size() ); + memset( ram2.begin(), 0, ram2.size() ); + memset( vectors.begin(), 0xFF, vectors.size() ); + cpu.reset( unmapped_write.begin(), rom.unmapped() ); + + if ( sega_mapping() ) + { + vectors_addr = 0x10000 - Sgc_Cpu::page_size; + idle_addr = vectors_addr; + for ( int i = 1; i < 8; ++i ) + { + vectors [i*8 + 0] = 0xC3; // JP addr + vectors [i*8 + 1] = header_.rst_addrs [i*2 + 0]; + vectors [i*8 + 2] = header_.rst_addrs [i*2 + 1]; + } + + cpu.map_mem( 0xC000, 0x2000, ram.begin() ); + cpu.map_mem( vectors_addr, cpu.page_size, unmapped_write.begin(), vectors.begin() ); + + bank2 = NULL; + for ( int i = 0; i < 4; ++i ) + cpu_write( 0xFFFC + i, header_.mapping [i] ); + } + else + { + if ( !coleco_bios ) + return BLARGG_ERR( BLARGG_ERR_CALLER, "Coleco BIOS not set" ); + + vectors_addr = 0; + cpu.map_mem( 0, 0x2000, unmapped_write.begin(), coleco_bios ); + for ( int i = 0; i < 8; ++i ) + cpu.map_mem( 0x6000 + i*0x400, 0x400, ram.begin() ); + + idle_addr = 0x2000; + cpu.map_mem( 0x2000, cpu.page_size, unmapped_write.begin(), vectors.begin() ); + + for ( int i = 0; i < 0x8000 / bank_size; ++i ) + { + int addr = 0x8000 + i*bank_size; + cpu.map_mem( addr, bank_size, unmapped_write.begin(), rom.at_addr( addr ) ); + } + } + + cpu.r.sp = get_le16( header_.stack_ptr ); + cpu.r.b.a = track; + next_play = play_period; + + jsr( header_.init_addr ); + + return blargg_ok; +} + +// Emulation + +void Sgc_Impl::jsr( byte const (&addr) [2] ) +{ + *cpu.write( --cpu.r.sp ) = idle_addr >> 8; + *cpu.write( --cpu.r.sp ) = idle_addr & 0xFF; + cpu.r.pc = get_le16( addr ); +} + +void Sgc_Impl::set_bank( int bank, void const* data ) +{ + //dprintf( "map bank %d to %p\n", bank, (byte*) data - rom.at_addr( 0 ) ); + cpu.map_mem( bank * bank_size, bank_size, unmapped_write.begin(), data ); +} + +void Sgc_Impl::cpu_write( addr_t addr, int data ) +{ + if ( (addr ^ 0xFFFC) > 3 || !sega_mapping() ) + { + *cpu.write( addr ) = data; + return; + } + + switch ( addr ) + { + case 0xFFFC: + cpu.map_mem( 2 * bank_size, bank_size, ram2.begin() ); + if ( data & 0x08 ) + break; + + bank2 = ram2.begin(); + // FALL THROUGH + + case 0xFFFF: { + bool rom_mapped = (cpu.read( 2 * bank_size ) == bank2); + bank2 = rom.at_addr( data * bank_size ); + if ( rom_mapped ) + set_bank( 2, bank2 ); + break; + } + + case 0xFFFD: + set_bank( 0, rom.at_addr( data * bank_size ) ); + break; + + case 0xFFFE: + set_bank( 1, rom.at_addr( data * bank_size ) ); + break; + } +} + +int Sgc_Impl::cpu_in( addr_t addr ) +{ + dprintf( "in %02X\n", addr ); + return 0; +} + +void Sgc_Impl::cpu_out( time_t, addr_t addr, int ) +{ + dprintf( "out %02X\n", addr & 0xFF ); +} + +blargg_err_t Sgc_Impl::end_frame( time_t end ) +{ + while ( cpu.time() < end ) + { + time_t next = min( end, next_play ); + if ( run_cpu( next ) ) + { + set_warning( "Unsupported CPU instruction" ); + cpu.set_time( next ); + } + + if ( cpu.r.pc == idle_addr ) + cpu.set_time( next ); + + if ( cpu.time() >= next_play ) + { + next_play += play_period; + if ( cpu.r.pc == idle_addr ) + jsr( header_.play_addr ); + } + } + + next_play -= end; + check( next_play >= 0 ); + cpu.adjust_time( -end ); + + return blargg_ok; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Impl.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Impl.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sgc_Impl.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sgc_Impl.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,116 +1,116 @@ -// Sega/Game Gear/Coleco SGC music file emulator implementation internals - -// Game_Music_Emu $vers -#ifndef SGC_IMPL_H -#define SGC_IMPL_H - -#include "Gme_Loader.h" -#include "Rom_Data.h" -#include "Z80_Cpu.h" - -class Sgc_Impl : public Gme_Loader { -public: - - // SGC file header - struct header_t - { - enum { size = 0xA0 }; - - char tag [4]; // "SGC\x1A" - byte vers; // 0x01 - byte rate; // 0=NTSC 1=PAL - byte reserved1 [2]; - byte load_addr [2]; - byte init_addr [2]; - byte play_addr [2]; - byte stack_ptr [2]; - byte reserved2 [2]; - byte rst_addrs [7*2]; - byte mapping [4]; // Used by Sega only - byte first_song; // Song to start playing first - byte song_count; - byte first_effect; - byte last_effect; - byte system; // 0=Master System 1=Game Gear 2=Colecovision - byte reserved3 [23]; - char game [32]; // strings can be 32 chars, NOT terminated - char author [32]; - char copyright [32]; - - // True if header has valid file signature - bool valid_tag() const; - - int effect_count() const { return last_effect ? last_effect - first_effect + 1 : 0; } - }; - - // Header for currently loaded file - header_t const& header() const { return header_; } - - Rom_Data const& rom_() const { return rom; } - - int clock_rate() const { return header_.rate ? 3546893 : 3579545; } - - // 0x2000 bytes - static void set_coleco_bios( void const* p ) { coleco_bios = p; } - - // Clocks between calls to play routine - typedef int time_t; - void set_play_period( time_t p ) { play_period = p; } - - // 0 = first track - blargg_err_t start_track( int ); - - // Runs for t clocks - blargg_err_t end_frame( time_t t ); - - // True if Master System or Game Gear - bool sega_mapping() const; - -protected: - typedef Z80_Cpu Sgc_Cpu; - Sgc_Cpu cpu; - - typedef int addr_t; - virtual void cpu_out( time_t, addr_t, int data ) BLARGG_PURE( ; ) - -// Implementation -public: - Sgc_Impl(); - ~Sgc_Impl(); - virtual void unload(); - -protected: - virtual blargg_err_t load_( Data_Reader& ); - -private: - enum { bank_size = 0x4000 }; - - Rom_Data rom; - time_t play_period; - time_t next_play; - void const* bank2; // ROM selected for bank 2, in case RAM is currently hiding it - addr_t vectors_addr; // RST vectors start here - addr_t idle_addr; // return address for init/play routines - static void const* coleco_bios; - - // large items - header_t header_; - blargg_vector vectors; - blargg_vector ram; - blargg_vector ram2; - blargg_vector unmapped_write; - - bool run_cpu( time_t end ); - void jsr( byte const (&addr) [2] ); - void cpu_write( addr_t, int data ); - int cpu_in( addr_t ); - - void set_bank( int bank, void const* data ); -}; - -inline bool Sgc_Impl::sega_mapping() const -{ - return header_.system <= 1; -} - -#endif +// Sega/Game Gear/Coleco SGC music file emulator implementation internals + +// Game_Music_Emu $vers +#ifndef SGC_IMPL_H +#define SGC_IMPL_H + +#include "Gme_Loader.h" +#include "Rom_Data.h" +#include "Z80_Cpu.h" + +class Sgc_Impl : public Gme_Loader { +public: + + // SGC file header + struct header_t + { + enum { size = 0xA0 }; + + char tag [4]; // "SGC\x1A" + byte vers; // 0x01 + byte rate; // 0=NTSC 1=PAL + byte reserved1 [2]; + byte load_addr [2]; + byte init_addr [2]; + byte play_addr [2]; + byte stack_ptr [2]; + byte reserved2 [2]; + byte rst_addrs [7*2]; + byte mapping [4]; // Used by Sega only + byte first_song; // Song to start playing first + byte song_count; + byte first_effect; + byte last_effect; + byte system; // 0=Master System 1=Game Gear 2=Colecovision + byte reserved3 [23]; + char game [32]; // strings can be 32 chars, NOT terminated + char author [32]; + char copyright [32]; + + // True if header has valid file signature + bool valid_tag() const; + + int effect_count() const { return last_effect ? last_effect - first_effect + 1 : 0; } + }; + + // Header for currently loaded file + header_t const& header() const { return header_; } + + Rom_Data const& rom_() const { return rom; } + + int clock_rate() const { return header_.rate ? 3546893 : 3579545; } + + // 0x2000 bytes + static void set_coleco_bios( void const* p ) { coleco_bios = p; } + + // Clocks between calls to play routine + typedef int time_t; + void set_play_period( time_t p ) { play_period = p; } + + // 0 = first track + blargg_err_t start_track( int ); + + // Runs for t clocks + blargg_err_t end_frame( time_t t ); + + // True if Master System or Game Gear + bool sega_mapping() const; + +protected: + typedef Z80_Cpu Sgc_Cpu; + Sgc_Cpu cpu; + + typedef int addr_t; + virtual void cpu_out( time_t, addr_t, int data ) BLARGG_PURE( ; ) + +// Implementation +public: + Sgc_Impl(); + ~Sgc_Impl(); + virtual void unload(); + +protected: + virtual blargg_err_t load_( Data_Reader& ); + +private: + enum { bank_size = 0x4000 }; + + Rom_Data rom; + time_t play_period; + time_t next_play; + void const* bank2; // ROM selected for bank 2, in case RAM is currently hiding it + addr_t vectors_addr; // RST vectors start here + addr_t idle_addr; // return address for init/play routines + static void const* coleco_bios; + + // large items + header_t header_; + blargg_vector vectors; + blargg_vector ram; + blargg_vector ram2; + blargg_vector unmapped_write; + + bool run_cpu( time_t end ); + void jsr( byte const (&addr) [2] ); + void cpu_write( addr_t, int data ); + int cpu_in( addr_t ); + + void set_bank( int bank, void const* data ); +}; + +inline bool Sgc_Impl::sega_mapping() const +{ + return header_.system <= 1; +} + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/s_logtbl.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/s_logtbl.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/s_logtbl.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/s_logtbl.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,88 +1,88 @@ -#include "nestypes.h" -#include "s_logtbl.h" - -#if STATIC_TABLES - -static void LogTableRelease(void *ctx) -{ -} - -static KMIF_LOGTABLE log_static_tables = { - &log_static_tables; - LogTableRelease, -#include "s_logt.h" -}; - - -KMIF_LOGTABLE *LogTableAddRef(void) -{ - log_static_tables.release = LogTableRelease; - return &log_static_tables; -} - -#else - -#include - -static volatile Uint32 log_tables_mutex = 0; -static Uint32 log_tables_refcount = 0; -static KMIF_LOGTABLE *log_tables = 0; - -static void LogTableRelease(void *ctx) -{ - ++log_tables_mutex; - while (log_tables_mutex != 1) - { - XSLEEP(0); - } - log_tables_refcount--; - if (!log_tables_refcount) - { - XFREE(ctx); - log_tables = 0; - } - --log_tables_mutex; -} - -static void LogTableCalc(KMIF_LOGTABLE *kmif_lt) -{ - Uint32 i; - double a; - for (i = 0; i < (1 << LOG_BITS); i++) - { - a = (1 << LOG_LIN_BITS) / pow(2, i / (double)(1 << LOG_BITS)); - kmif_lt->logtbl[i] = (Uint32)a; - } - kmif_lt->lineartbl[0] = LOG_LIN_BITS << LOG_BITS; - for (i = 1; i < (1 << LIN_BITS) + 1; i++) - { - Uint32 ua; - a = i << (LOG_LIN_BITS - LIN_BITS); - ua = (Uint32)((LOG_LIN_BITS - (log(a) / log(2))) * (1 << LOG_BITS)); - kmif_lt->lineartbl[i] = ua << 1; - } -} - -KMIF_LOGTABLE *LogTableAddRef(void) -{ - ++log_tables_mutex; - while (log_tables_mutex != 1) - { - XSLEEP(0); - } - if (!log_tables_refcount) - { - log_tables = (KMIF_LOGTABLE*) XMALLOC(sizeof(KMIF_LOGTABLE)); - if (log_tables) - { - log_tables->ctx = log_tables; - log_tables->release = LogTableRelease; - LogTableCalc(log_tables); - } - } - if (log_tables) log_tables_refcount++; - --log_tables_mutex; - return log_tables; -} - -#endif +#include "nestypes.h" +#include "s_logtbl.h" + +#if STATIC_TABLES + +static void LogTableRelease(void *ctx) +{ +} + +static KMIF_LOGTABLE log_static_tables = { + &log_static_tables; + LogTableRelease, +#include "s_logt.h" +}; + + +KMIF_LOGTABLE *LogTableAddRef(void) +{ + log_static_tables.release = LogTableRelease; + return &log_static_tables; +} + +#else + +#include + +static volatile Uint32 log_tables_mutex = 0; +static Uint32 log_tables_refcount = 0; +static KMIF_LOGTABLE *log_tables = 0; + +static void LogTableRelease(void *ctx) +{ + ++log_tables_mutex; + while (log_tables_mutex != 1) + { + XSLEEP(0); + } + log_tables_refcount--; + if (!log_tables_refcount) + { + XFREE(ctx); + log_tables = 0; + } + --log_tables_mutex; +} + +static void LogTableCalc(KMIF_LOGTABLE *kmif_lt) +{ + Uint32 i; + double a; + for (i = 0; i < (1 << LOG_BITS); i++) + { + a = (1 << LOG_LIN_BITS) / pow(2, i / (double)(1 << LOG_BITS)); + kmif_lt->logtbl[i] = (Uint32)a; + } + kmif_lt->lineartbl[0] = LOG_LIN_BITS << LOG_BITS; + for (i = 1; i < (1 << LIN_BITS) + 1; i++) + { + Uint32 ua; + a = i << (LOG_LIN_BITS - LIN_BITS); + ua = (Uint32)((LOG_LIN_BITS - (log(a) / log(2))) * (1 << LOG_BITS)); + kmif_lt->lineartbl[i] = ua << 1; + } +} + +KMIF_LOGTABLE *LogTableAddRef(void) +{ + ++log_tables_mutex; + while (log_tables_mutex != 1) + { + XSLEEP(0); + } + if (!log_tables_refcount) + { + log_tables = (KMIF_LOGTABLE*) XMALLOC(sizeof(KMIF_LOGTABLE)); + if (log_tables) + { + log_tables->ctx = log_tables; + log_tables->release = LogTableRelease; + LogTableCalc(log_tables); + } + } + if (log_tables) log_tables_refcount++; + --log_tables_mutex; + return log_tables; +} + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sms_Fm_Apu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sms_Fm_Apu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sms_Fm_Apu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sms_Fm_Apu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,80 +1,80 @@ -#include "Sms_Fm_Apu.h" - -#include "blargg_source.h" - -Sms_Fm_Apu::Sms_Fm_Apu() -{ } - -Sms_Fm_Apu::~Sms_Fm_Apu() -{ } - -blargg_err_t Sms_Fm_Apu::init( double clock_rate, double sample_rate ) -{ - period_ = clock_rate / sample_rate + 0.5; - CHECK_ALLOC( !apu.set_rate( sample_rate, clock_rate ) ); - - set_output( 0 ); - volume( 1.0 ); - reset(); - return blargg_ok; -} - -void Sms_Fm_Apu::reset() -{ - addr = 0; - next_time = 0; - last_amp = 0; - - apu.reset(); -} - -void Sms_Fm_Apu::write_data( blip_time_t time, int data ) -{ - if ( time > next_time ) - run_until( time ); - - apu.write( addr, data ); -} - -void Sms_Fm_Apu::run_until( blip_time_t end_time ) -{ - assert( end_time > next_time ); - - Blip_Buffer* const output = this->output_; - if ( !output ) - { - next_time = end_time; - return; - } - - blip_time_t time = next_time; - do - { - Ym2413_Emu::sample_t samples [2] = {0}; - apu.run( 1, samples ); - int amp = (samples [0] + samples [1]) >> 1; - - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth.offset_inline( time, delta, output ); - } - time += period_; - } - while ( time < end_time ); - - next_time = time; -} - -void Sms_Fm_Apu::end_frame( blip_time_t time ) -{ - if ( time > next_time ) - run_until( time ); - - next_time -= time; - assert( next_time >= 0 ); - - if ( output_ ) - output_->set_modified(); -} +#include "Sms_Fm_Apu.h" + +#include "blargg_source.h" + +Sms_Fm_Apu::Sms_Fm_Apu() +{ } + +Sms_Fm_Apu::~Sms_Fm_Apu() +{ } + +blargg_err_t Sms_Fm_Apu::init( double clock_rate, double sample_rate ) +{ + period_ = clock_rate / sample_rate + 0.5; + CHECK_ALLOC( !apu.set_rate( sample_rate, clock_rate ) ); + + set_output( 0 ); + volume( 1.0 ); + reset(); + return blargg_ok; +} + +void Sms_Fm_Apu::reset() +{ + addr = 0; + next_time = 0; + last_amp = 0; + + apu.reset(); +} + +void Sms_Fm_Apu::write_data( blip_time_t time, int data ) +{ + if ( time > next_time ) + run_until( time ); + + apu.write( addr, data ); +} + +void Sms_Fm_Apu::run_until( blip_time_t end_time ) +{ + assert( end_time > next_time ); + + Blip_Buffer* const output = this->output_; + if ( !output ) + { + next_time = end_time; + return; + } + + blip_time_t time = next_time; + do + { + Ym2413_Emu::sample_t samples [2] = {0}; + apu.run( 1, samples ); + int amp = (samples [0] + samples [1]) >> 1; + + int delta = amp - last_amp; + if ( delta ) + { + last_amp = amp; + synth.offset_inline( time, delta, output ); + } + time += period_; + } + while ( time < end_time ); + + next_time = time; +} + +void Sms_Fm_Apu::end_frame( blip_time_t time ) +{ + if ( time > next_time ) + run_until( time ); + + next_time -= time; + assert( next_time >= 0 ); + + if ( output_ ) + output_->set_modified(); +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sms_Fm_Apu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sms_Fm_Apu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Sms_Fm_Apu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Sms_Fm_Apu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,47 +1,47 @@ -#ifndef SMS_FM_APU_H -#define SMS_FM_APU_H - -#include "Blip_Buffer.h" -#include "Ym2413_Emu.h" - -class Sms_Fm_Apu { -public: - static bool supported() { return Ym2413_Emu::supported(); } - blargg_err_t init( double clock_rate, double sample_rate ); - - void set_output( Blip_Buffer* b, Blip_Buffer* = NULL, Blip_Buffer* = NULL ) { output_ = b; } - void volume( double v ) { synth.volume( 0.4 / 4096 * v ); } - void treble_eq( blip_eq_t const& eq ) { synth.treble_eq( eq ); } - - void reset(); - - void write_addr( int data ) { addr = data; } - void write_data( blip_time_t, int data ); - - void end_frame( blip_time_t t ); - -// Implementation -public: - Sms_Fm_Apu(); - ~Sms_Fm_Apu(); - BLARGG_DISABLE_NOTHROW - enum { osc_count = 1 }; - void set_output( int i, Blip_Buffer* b, Blip_Buffer* = NULL, Blip_Buffer* = NULL ) { output_ = b; } - -private: - Blip_Buffer* output_; - blip_time_t next_time; - int last_amp; - int addr; - - int clock_; - int rate_; - blip_time_t period_; - - Blip_Synth_Norm synth; - Ym2413_Emu apu; - - void run_until( blip_time_t ); -}; - -#endif +#ifndef SMS_FM_APU_H +#define SMS_FM_APU_H + +#include "Blip_Buffer.h" +#include "Ym2413_Emu.h" + +class Sms_Fm_Apu { +public: + static bool supported() { return Ym2413_Emu::supported(); } + blargg_err_t init( double clock_rate, double sample_rate ); + + void set_output( Blip_Buffer* b, Blip_Buffer* = NULL, Blip_Buffer* = NULL ) { output_ = b; } + void volume( double v ) { synth.volume( 0.4 / 4096 * v ); } + void treble_eq( blip_eq_t const& eq ) { synth.treble_eq( eq ); } + + void reset(); + + void write_addr( int data ) { addr = data; } + void write_data( blip_time_t, int data ); + + void end_frame( blip_time_t t ); + +// Implementation +public: + Sms_Fm_Apu(); + ~Sms_Fm_Apu(); + BLARGG_DISABLE_NOTHROW + enum { osc_count = 1 }; + void set_output( int i, Blip_Buffer* b, Blip_Buffer* = NULL, Blip_Buffer* = NULL ) { output_ = b; } + +private: + Blip_Buffer* output_; + blip_time_t next_time; + int last_amp; + int addr; + + int clock_; + int rate_; + blip_time_t period_; + + Blip_Synth_Norm synth; + Ym2413_Emu apu; + + void run_until( blip_time_t ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Spc_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Spc_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Spc_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Spc_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,462 +1,462 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Spc_Emu.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2004-2009 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// TODO: support Spc_Filter's bass - -Spc_Emu::Spc_Emu() -{ - set_type( gme_spc_type ); - set_gain( 1.4 ); -} - -Spc_Emu::~Spc_Emu() { } - -// Track info - -int const trailer_offset = 0x10200; - -inline byte const* Spc_Emu::trailer_() const { return &file_begin() [min( file_size(), trailer_offset )]; } - -inline int Spc_Emu::trailer_size_() const { return max( 0, file_size() - trailer_offset ); } - -static void get_spc_xid6( byte const begin [], int size, track_info_t* out ) -{ - // header - byte const* end = begin + size; - if ( size < 8 || memcmp( begin, "xid6", 4 ) ) - { - check( false ); - return; - } - int info_size = get_le32( begin + 4 ); - byte const* in = begin + 8; - if ( end - in > info_size ) - { - dprintf( "SPC: Extra data after xid6\n" ); - end = in + info_size; - } - - int year = 0; - char copyright [256 + 5]; - int copyright_len = 0; - int const year_len = 5; - int disc = 0, track = 0; - - while ( end - in >= 4 ) - { - // header - int id = in [0]; - int data = in [3] * 0x100 + in [2]; - int type = in [1]; - int len = type ? data : 0; - in += 4; - if ( len > end - in ) - { - dprintf( "SPC: xid6 goes past end" ); - break; // block goes past end of data - } - - // handle specific block types - char* field = NULL; - switch ( id ) - { - case 0x01: field = out->song; break; - case 0x02: field = out->game; break; - case 0x03: field = out->author; break; - case 0x04: field = out->dumper; break; - case 0x07: field = out->comment; break; - case 0x10: field = out->ost; break; - case 0x11: disc = data; break; - case 0x12: track = data; break; - case 0x14: year = data; break; - - //case 0x30: // intro length - // Many SPCs have intro length set wrong for looped tracks, making it useless - /* - case 0x30: - check( len == 4 ); - if ( len >= 4 ) - { - out->intro_length = get_le32( in ) / 64; - if ( out->length > 0 ) - { - int loop = out->length - out->intro_length; - if ( loop >= 2000 ) - out->loop_length = loop; - } - } - break; - */ - - case 0x33: - check( len == 4 ); - if ( len >= 4 ) - { - out->fade_length = get_le32( in ) / 64; - } - break; - - case 0x13: - copyright_len = min( len, (int) sizeof copyright - year_len ); - memcpy( ©right [year_len], in, copyright_len ); - break; - - default: - if ( id < 0x01 || (id > 0x07 && id < 0x10) || - (id > 0x14 && id < 0x30) || id > 0x36 ) - dprintf( "SPC: Unknown xid6 block: %X\n", (int) id ); - break; - } - if ( field ) - { - check( type == 1 ); - Gme_File::copy_field_( field, (char const*) in, len ); - } - - // skip to next block - in += len; - - // blocks are supposed to be 4-byte aligned with zero-padding... - byte const* unaligned = in; - while ( (in - begin) & 3 && in < end ) - { - if ( *in++ != 0 ) - { - // ...but some files have no padding - in = unaligned; - //dprintf( "SPC: xid6 info tag wasn't properly padded to align\n" ); - break; - } - } - } - - char* p = ©right [year_len]; - if ( year ) - { - *--p = ' '; - // avoid using bloated printf - for ( int n = 4; n--; ) - { - *--p = char (year % 10 + '0'); - year /= 10; - } - copyright_len += year_len; - } - if ( copyright_len ) - Gme_File::copy_field_( out->copyright, p, copyright_len ); - - if ( disc > 0 && disc <= 9 ) - { - out->disc [0] = disc + '0'; - out->disc [1] = 0; - } - - if ( track > 255 && track < ( ( 100 << 8 ) - 1 ) ) - { - char* p = ©right [3]; - *p = 0; - if ( track & 255 ) *--p = char (track & 255); - track >>= 8; - for ( int n = 2; n-- && track; ) - { - *--p = char (track % 10 + '0'); - track /= 10; - } - memcpy( out->track, p, ©right [4] - p ); - } - - check( in == end ); -} - -static void get_spc_info( Spc_Emu::header_t const& h, byte const xid6 [], int xid6_size, - track_info_t* out ) -{ - // decode length (can be in text or binary format, sometimes ambiguous ugh) - int len_secs = 0; - int i; - for ( i = 0; i < 3; i++ ) - { - unsigned n = h.len_secs [i] - '0'; - if ( n > 9 ) - { - // ignore single-digit text lengths - // (except if author field is present and begins at offset 1, ugh) - if ( i == 1 && (h.author [0] || !h.author [1]) ) - len_secs = 0; - break; - } - len_secs *= 10; - len_secs += n; - } - if ( !len_secs || len_secs > 0x1FFF ) - len_secs = get_le16( h.len_secs ); - if ( len_secs < 0x1FFF ) - out->length = len_secs * 1000; - - long fade_msec = 0; - for ( i = 0; i < 4; i++ ) - { - unsigned n = h.fade_msec [i] - '0'; - if ( n > 9 ) - { - if ( i == 1 && (h.author [0] || !h.author [1]) ) - fade_msec = -1; - break; - } - fade_msec *= 10; - fade_msec += n; - } - if ( i == 4 && unsigned( h.author [0] - '0' ) <= 9 ) - fade_msec = fade_msec * 10 + h.author [0] - '0'; - if ( fade_msec < 0 || fade_msec > 0x7FFF ) - fade_msec = get_le32( h.fade_msec ); - if ( fade_msec < 0x7FFF ) - out->fade_length = fade_msec; - - int offset = (h.author [0] < ' ' || unsigned (h.author [0] - '0') <= 9); - Gme_File::copy_field_( out->author, &h.author [offset], sizeof h.author - offset ); - - GME_COPY_FIELD( h, out, song ); - GME_COPY_FIELD( h, out, game ); - GME_COPY_FIELD( h, out, dumper ); - GME_COPY_FIELD( h, out, comment ); - - if ( xid6_size ) - get_spc_xid6( xid6, xid6_size, out ); -} - -static void hash_spc_file( Spc_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( &h.format, sizeof(h.format) ); - out.hash_( &h.version, sizeof(h.version) ); - out.hash_( &h.pc[0], sizeof(h.pc) ); - out.hash_( &h.a, sizeof(h.a) ); - out.hash_( &h.x, sizeof(h.x) ); - out.hash_( &h.y, sizeof(h.y) ); - out.hash_( &h.psw, sizeof(h.psw) ); - out.hash_( &h.sp, sizeof(h.sp) ); - out.hash_( &h.unused[0], sizeof(h.unused) ); - out.hash_( &h.emulator, sizeof(h.emulator) ); - out.hash_( &h.unused2[0], sizeof(h.unused2) ); - out.hash_( data, data_size ); -} - -blargg_err_t Spc_Emu::track_info_( track_info_t* out, int ) const -{ - get_spc_info( header(), trailer_(), trailer_size_(), out ); - return blargg_ok; -} - -static blargg_err_t check_spc_header( void const* header ) -{ - if ( memcmp( header, "SNES-SPC700 Sound File Data", 27 ) ) - return blargg_err_file_type; - return blargg_ok; -} - -struct Spc_File : Gme_Info_ -{ - Spc_Emu::header_t header; - blargg_vector data; - blargg_vector xid6; - - Spc_File() { set_type( gme_spc_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - int file_size = in.remain(); - if ( file_size < 0x10180 ) - return blargg_err_file_type; - RETURN_ERR( in.read( &header, header.size ) ); - RETURN_ERR( check_spc_header( header.tag ) ); - int const xid6_offset = 0x10200; - RETURN_ERR( data.resize( blargg_min( xid6_offset - header.size, file_size - header.size ) ) ); - RETURN_ERR( in.read( data.begin(), data.end() - data.begin() ) ); - int xid6_size = file_size - xid6_offset; - if ( xid6_size > 0 ) - { - RETURN_ERR( xid6.resize( xid6_size ) ); - RETURN_ERR( in.read( xid6.begin(), xid6.size() ) ); - } - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - get_spc_info( header, xid6.begin(), xid6.size(), out ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_spc_file( header, data.begin(), data.end() - data.begin(), out ); - return blargg_ok; - } -}; - -static Music_Emu* new_spc_emu () { return BLARGG_NEW Spc_Emu ; } -static Music_Emu* new_spc_file() { return BLARGG_NEW Spc_File; } - -gme_type_t_ const gme_spc_type [1] = {{ "Super Nintendo", 1, &new_spc_emu, &new_spc_file, "SPC", 0 }}; - -// Setup - -blargg_err_t Spc_Emu::set_sample_rate_( int sample_rate ) -{ - smp.power(); - if ( sample_rate != native_sample_rate ) - { - RETURN_ERR( resampler.resize_buffer( native_sample_rate / 20 * 2 ) ); - RETURN_ERR( resampler.set_rate( (double) native_sample_rate / sample_rate ) ); // 0.9965 rolloff - } - return blargg_ok; -} - -void Spc_Emu::mute_voices_( int m ) -{ - Music_Emu::mute_voices_( m ); - for ( int i = 0, j = 1; i < SuperFamicom::SPC_DSP::voice_count; ++i, j <<= 1 ) - smp.dsp.channel_enable( i, !( m & j ) ); -} - -blargg_err_t Spc_Emu::load_mem_( byte const in [], int size ) -{ - assert( offsetof (header_t,unused2 [46]) == header_t::size ); - set_voice_count( SuperFamicom::SPC_DSP::voice_count ); - if ( size < 0x10180 ) - return blargg_err_file_type; - - static const char* const names [ SuperFamicom::SPC_DSP::voice_count ] = { - "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", "DSP 8" - }; - set_voice_names( names ); - - return check_spc_header( in ); -} - -// Emulation - -void Spc_Emu::set_tempo_( double t ) -{ - smp.set_tempo( t ); -} - -blargg_err_t Spc_Emu::start_track_( int track ) -{ - RETURN_ERR( Music_Emu::start_track_( track ) ); - resampler.clear(); - filter.clear(); - smp.reset(); - const byte * ptr = file_begin(); - - Spc_Emu::header_t & header = *(Spc_Emu::header_t*)ptr; - ptr += sizeof(header); - - smp.regs.pc = header.pc[0] + header.pc[1] * 0x100; - smp.regs.a = header.a; - smp.regs.x = header.x; - smp.regs.y = header.y; - smp.regs.p = header.psw; - smp.regs.s = header.sp; - - memcpy( smp.apuram, ptr, 0x10000 ); - memset( smp.apuram + 0xF4, 0, 4 ); - memcpy( smp.sfm_last, ptr + 0xF4, 4 ); - - static const uint8_t regs_to_copy[][2] = { {0xFC,0xFF}, {0xFB,0xFF}, {0xFA,0xFF}, {0xF9,0xFF}, {0xF8,0xFF}, {0xF2,0xFF}, {0xF1,0x87} }; - for (auto n : regs_to_copy) smp.op_buswrite( n[0], ptr[ n[0] ] & n[1] ); - smp.timer0.stage3_ticks = ptr[ 0xFD ] & 0x0F; - smp.timer1.stage3_ticks = ptr[ 0xFE ] & 0x0F; - smp.timer2.stage3_ticks = ptr[ 0xFF ] & 0x0F; - ptr += 0x10000; - - smp.dsp.spc_dsp.load( ptr ); - - if ( !(smp.dsp.read( SuperFamicom::SPC_DSP::r_flg ) & 0x20) ) - { - int addr = 0x100 * smp.dsp.read( SuperFamicom::SPC_DSP::r_esa ); - int end = addr + 0x800 * (smp.dsp.read( SuperFamicom::SPC_DSP::r_edl ) & 0x0F); - if ( end > 0x10000 ) - end = 0x10000; - memset( &smp.apuram [addr], 0xFF, end - addr ); - } - - filter.set_gain( (int) (gain() * Spc_Filter::gain_unit) ); - return blargg_ok; -} - -blargg_err_t Spc_Emu::play_and_filter( int count, sample_t out [] ) -{ - smp.render( out, count ); - filter.run( out, count ); - return blargg_ok; -} - -blargg_err_t Spc_Emu::skip_( int count ) -{ - if ( sample_rate() != native_sample_rate ) - { - count = (int) (count * resampler.rate()) & ~1; - count -= resampler.skip_input( count ); - } - - // TODO: shouldn't skip be adjusted for the 64 samples read afterwards? - - if ( count > 0 ) - { - smp.skip( count ); - filter.clear(); - } - - // eliminate pop due to resampler - if ( sample_rate() != native_sample_rate ) - { - const int resampler_latency = 64; - sample_t buf [resampler_latency]; - return play_( resampler_latency, buf ); - } - - return blargg_ok; -} - -blargg_err_t Spc_Emu::play_( int count, sample_t out [] ) -{ - if ( sample_rate() == native_sample_rate ) - return play_and_filter( count, out ); - - int remain = count; - while ( remain > 0 ) - { - remain -= resampler.read( &out [count - remain], remain ); - if ( remain > 0 ) - { - int n = resampler.buffer_free(); - RETURN_ERR( play_and_filter( n, resampler.buffer() ) ); - resampler.write( n ); - } - } - check( remain == 0 ); - return blargg_ok; -} - -blargg_err_t Spc_Emu::hash_( Hash_Function& out ) const -{ - hash_spc_file( header(), file_begin() + header_t::size, blargg_min( (size_t) ( 0x10200 - header_t::size ), (size_t) ( file_end() - file_begin() - header_t::size ) ), out ); - return blargg_ok; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Spc_Emu.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2004-2009 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// TODO: support Spc_Filter's bass + +Spc_Emu::Spc_Emu() +{ + set_type( gme_spc_type ); + set_gain( 1.4 ); +} + +Spc_Emu::~Spc_Emu() { } + +// Track info + +int const trailer_offset = 0x10200; + +inline byte const* Spc_Emu::trailer_() const { return &file_begin() [min( file_size(), trailer_offset )]; } + +inline int Spc_Emu::trailer_size_() const { return max( 0, file_size() - trailer_offset ); } + +static void get_spc_xid6( byte const begin [], int size, track_info_t* out ) +{ + // header + byte const* end = begin + size; + if ( size < 8 || memcmp( begin, "xid6", 4 ) ) + { + check( false ); + return; + } + int info_size = get_le32( begin + 4 ); + byte const* in = begin + 8; + if ( end - in > info_size ) + { + dprintf( "SPC: Extra data after xid6\n" ); + end = in + info_size; + } + + int year = 0; + char copyright [256 + 5]; + int copyright_len = 0; + int const year_len = 5; + int disc = 0, track = 0; + + while ( end - in >= 4 ) + { + // header + int id = in [0]; + int data = in [3] * 0x100 + in [2]; + int type = in [1]; + int len = type ? data : 0; + in += 4; + if ( len > end - in ) + { + dprintf( "SPC: xid6 goes past end" ); + break; // block goes past end of data + } + + // handle specific block types + char* field = NULL; + switch ( id ) + { + case 0x01: field = out->song; break; + case 0x02: field = out->game; break; + case 0x03: field = out->author; break; + case 0x04: field = out->dumper; break; + case 0x07: field = out->comment; break; + case 0x10: field = out->ost; break; + case 0x11: disc = data; break; + case 0x12: track = data; break; + case 0x14: year = data; break; + + //case 0x30: // intro length + // Many SPCs have intro length set wrong for looped tracks, making it useless + /* + case 0x30: + check( len == 4 ); + if ( len >= 4 ) + { + out->intro_length = get_le32( in ) / 64; + if ( out->length > 0 ) + { + int loop = out->length - out->intro_length; + if ( loop >= 2000 ) + out->loop_length = loop; + } + } + break; + */ + + case 0x33: + check( len == 4 ); + if ( len >= 4 ) + { + out->fade_length = get_le32( in ) / 64; + } + break; + + case 0x13: + copyright_len = min( len, (int) sizeof copyright - year_len ); + memcpy( ©right [year_len], in, copyright_len ); + break; + + default: + if ( id < 0x01 || (id > 0x07 && id < 0x10) || + (id > 0x14 && id < 0x30) || id > 0x36 ) + dprintf( "SPC: Unknown xid6 block: %X\n", (int) id ); + break; + } + if ( field ) + { + check( type == 1 ); + Gme_File::copy_field_( field, (char const*) in, len ); + } + + // skip to next block + in += len; + + // blocks are supposed to be 4-byte aligned with zero-padding... + byte const* unaligned = in; + while ( (in - begin) & 3 && in < end ) + { + if ( *in++ != 0 ) + { + // ...but some files have no padding + in = unaligned; + //dprintf( "SPC: xid6 info tag wasn't properly padded to align\n" ); + break; + } + } + } + + char* p = ©right [year_len]; + if ( year ) + { + *--p = ' '; + // avoid using bloated printf + for ( int n = 4; n--; ) + { + *--p = char (year % 10 + '0'); + year /= 10; + } + copyright_len += year_len; + } + if ( copyright_len ) + Gme_File::copy_field_( out->copyright, p, copyright_len ); + + if ( disc > 0 && disc <= 9 ) + { + out->disc [0] = disc + '0'; + out->disc [1] = 0; + } + + if ( track > 255 && track < ( ( 100 << 8 ) - 1 ) ) + { + char* p = ©right [3]; + *p = 0; + if ( track & 255 ) *--p = char (track & 255); + track >>= 8; + for ( int n = 2; n-- && track; ) + { + *--p = char (track % 10 + '0'); + track /= 10; + } + memcpy( out->track, p, ©right [4] - p ); + } + + check( in == end ); +} + +static void get_spc_info( Spc_Emu::header_t const& h, byte const xid6 [], int xid6_size, + track_info_t* out ) +{ + // decode length (can be in text or binary format, sometimes ambiguous ugh) + int len_secs = 0; + int i; + for ( i = 0; i < 3; i++ ) + { + unsigned n = h.len_secs [i] - '0'; + if ( n > 9 ) + { + // ignore single-digit text lengths + // (except if author field is present and begins at offset 1, ugh) + if ( i == 1 && (h.author [0] || !h.author [1]) ) + len_secs = 0; + break; + } + len_secs *= 10; + len_secs += n; + } + if ( !len_secs || len_secs > 0x1FFF ) + len_secs = get_le16( h.len_secs ); + if ( len_secs < 0x1FFF ) + out->length = len_secs * 1000; + + long fade_msec = 0; + for ( i = 0; i < 4; i++ ) + { + unsigned n = h.fade_msec [i] - '0'; + if ( n > 9 ) + { + if ( i == 1 && (h.author [0] || !h.author [1]) ) + fade_msec = -1; + break; + } + fade_msec *= 10; + fade_msec += n; + } + if ( i == 4 && unsigned( h.author [0] - '0' ) <= 9 ) + fade_msec = fade_msec * 10 + h.author [0] - '0'; + if ( fade_msec < 0 || fade_msec > 0x7FFF ) + fade_msec = get_le32( h.fade_msec ); + if ( fade_msec < 0x7FFF ) + out->fade_length = fade_msec; + + int offset = (h.author [0] < ' ' || unsigned (h.author [0] - '0') <= 9); + Gme_File::copy_field_( out->author, &h.author [offset], sizeof h.author - offset ); + + GME_COPY_FIELD( h, out, song ); + GME_COPY_FIELD( h, out, game ); + GME_COPY_FIELD( h, out, dumper ); + GME_COPY_FIELD( h, out, comment ); + + if ( xid6_size ) + get_spc_xid6( xid6, xid6_size, out ); +} + +static void hash_spc_file( Spc_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( &h.format, sizeof(h.format) ); + out.hash_( &h.version, sizeof(h.version) ); + out.hash_( &h.pc[0], sizeof(h.pc) ); + out.hash_( &h.a, sizeof(h.a) ); + out.hash_( &h.x, sizeof(h.x) ); + out.hash_( &h.y, sizeof(h.y) ); + out.hash_( &h.psw, sizeof(h.psw) ); + out.hash_( &h.sp, sizeof(h.sp) ); + out.hash_( &h.unused[0], sizeof(h.unused) ); + out.hash_( &h.emulator, sizeof(h.emulator) ); + out.hash_( &h.unused2[0], sizeof(h.unused2) ); + out.hash_( data, data_size ); +} + +blargg_err_t Spc_Emu::track_info_( track_info_t* out, int ) const +{ + get_spc_info( header(), trailer_(), trailer_size_(), out ); + return blargg_ok; +} + +static blargg_err_t check_spc_header( void const* header ) +{ + if ( memcmp( header, "SNES-SPC700 Sound File Data", 27 ) ) + return blargg_err_file_type; + return blargg_ok; +} + +struct Spc_File : Gme_Info_ +{ + Spc_Emu::header_t header; + blargg_vector data; + blargg_vector xid6; + + Spc_File() { set_type( gme_spc_type ); } + + blargg_err_t load_( Data_Reader& in ) + { + int file_size = in.remain(); + if ( file_size < 0x10180 ) + return blargg_err_file_type; + RETURN_ERR( in.read( &header, header.size ) ); + RETURN_ERR( check_spc_header( header.tag ) ); + int const xid6_offset = 0x10200; + RETURN_ERR( data.resize( blargg_min( xid6_offset - header.size, file_size - header.size ) ) ); + RETURN_ERR( in.read( data.begin(), data.end() - data.begin() ) ); + int xid6_size = file_size - xid6_offset; + if ( xid6_size > 0 ) + { + RETURN_ERR( xid6.resize( xid6_size ) ); + RETURN_ERR( in.read( xid6.begin(), xid6.size() ) ); + } + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + get_spc_info( header, xid6.begin(), xid6.size(), out ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_spc_file( header, data.begin(), data.end() - data.begin(), out ); + return blargg_ok; + } +}; + +static Music_Emu* new_spc_emu () { return BLARGG_NEW Spc_Emu ; } +static Music_Emu* new_spc_file() { return BLARGG_NEW Spc_File; } + +gme_type_t_ const gme_spc_type [1] = {{ "Super Nintendo", 1, &new_spc_emu, &new_spc_file, "SPC", 0 }}; + +// Setup + +blargg_err_t Spc_Emu::set_sample_rate_( int sample_rate ) +{ + smp.power(); + if ( sample_rate != native_sample_rate ) + { + RETURN_ERR( resampler.resize_buffer( native_sample_rate / 20 * 2 ) ); + RETURN_ERR( resampler.set_rate( (double) native_sample_rate / sample_rate ) ); // 0.9965 rolloff + } + return blargg_ok; +} + +void Spc_Emu::mute_voices_( int m ) +{ + Music_Emu::mute_voices_( m ); + for ( int i = 0, j = 1; i < SuperFamicom::SPC_DSP::voice_count; ++i, j <<= 1 ) + smp.dsp.channel_enable( i, !( m & j ) ); +} + +blargg_err_t Spc_Emu::load_mem_( byte const in [], int size ) +{ + assert( offsetof (header_t,unused2 [46]) == header_t::size ); + set_voice_count( SuperFamicom::SPC_DSP::voice_count ); + if ( size < 0x10180 ) + return blargg_err_file_type; + + static const char* const names [ SuperFamicom::SPC_DSP::voice_count ] = { + "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", "DSP 8" + }; + set_voice_names( names ); + + return check_spc_header( in ); +} + +// Emulation + +void Spc_Emu::set_tempo_( double t ) +{ + smp.set_tempo( t ); +} + +blargg_err_t Spc_Emu::start_track_( int track ) +{ + RETURN_ERR( Music_Emu::start_track_( track ) ); + resampler.clear(); + filter.clear(); + smp.reset(); + const byte * ptr = file_begin(); + + Spc_Emu::header_t & header = *(Spc_Emu::header_t*)ptr; + ptr += sizeof(header); + + smp.regs.pc = header.pc[0] + header.pc[1] * 0x100; + smp.regs.a = header.a; + smp.regs.x = header.x; + smp.regs.y = header.y; + smp.regs.p = header.psw; + smp.regs.s = header.sp; + + memcpy( smp.apuram, ptr, 0x10000 ); + memset( smp.apuram + 0xF4, 0, 4 ); + memcpy( smp.sfm_last, ptr + 0xF4, 4 ); + + static const uint8_t regs_to_copy[][2] = { {0xFC,0xFF}, {0xFB,0xFF}, {0xFA,0xFF}, {0xF9,0xFF}, {0xF8,0xFF}, {0xF2,0xFF}, {0xF1,0x87} }; + for (auto n : regs_to_copy) smp.op_buswrite( n[0], ptr[ n[0] ] & n[1] ); + smp.timer0.stage3_ticks = ptr[ 0xFD ] & 0x0F; + smp.timer1.stage3_ticks = ptr[ 0xFE ] & 0x0F; + smp.timer2.stage3_ticks = ptr[ 0xFF ] & 0x0F; + ptr += 0x10000; + + smp.dsp.spc_dsp.load( ptr ); + + if ( !(smp.dsp.read( SuperFamicom::SPC_DSP::r_flg ) & 0x20) ) + { + int addr = 0x100 * smp.dsp.read( SuperFamicom::SPC_DSP::r_esa ); + int end = addr + 0x800 * (smp.dsp.read( SuperFamicom::SPC_DSP::r_edl ) & 0x0F); + if ( end > 0x10000 ) + end = 0x10000; + memset( &smp.apuram [addr], 0xFF, end - addr ); + } + + filter.set_gain( (int) (gain() * Spc_Filter::gain_unit) ); + return blargg_ok; +} + +blargg_err_t Spc_Emu::play_and_filter( int count, sample_t out [] ) +{ + smp.render( out, count ); + filter.run( out, count ); + return blargg_ok; +} + +blargg_err_t Spc_Emu::skip_( int count ) +{ + if ( sample_rate() != native_sample_rate ) + { + count = (int) (count * resampler.rate()) & ~1; + count -= resampler.skip_input( count ); + } + + // TODO: shouldn't skip be adjusted for the 64 samples read afterwards? + + if ( count > 0 ) + { + smp.skip( count ); + filter.clear(); + } + + // eliminate pop due to resampler + if ( sample_rate() != native_sample_rate ) + { + const int resampler_latency = 64; + sample_t buf [resampler_latency]; + return play_( resampler_latency, buf ); + } + + return blargg_ok; +} + +blargg_err_t Spc_Emu::play_( int count, sample_t out [] ) +{ + if ( sample_rate() == native_sample_rate ) + return play_and_filter( count, out ); + + int remain = count; + while ( remain > 0 ) + { + remain -= resampler.read( &out [count - remain], remain ); + if ( remain > 0 ) + { + int n = resampler.buffer_free(); + RETURN_ERR( play_and_filter( n, resampler.buffer() ) ); + resampler.write( n ); + } + } + check( remain == 0 ); + return blargg_ok; +} + +blargg_err_t Spc_Emu::hash_( Hash_Function& out ) const +{ + hash_spc_file( header(), file_begin() + header_t::size, blargg_min( (size_t) ( 0x10200 - header_t::size ), (size_t) ( file_end() - file_begin() - header_t::size ) ), out ); + return blargg_ok; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Spc_Sfm.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Spc_Sfm.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Spc_Sfm.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Spc_Sfm.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,680 +1,680 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Spc_Sfm.h" - -#include "blargg_endian.h" - -#include - -/* Copyright (C) 2004-2013 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// TODO: support Spc_Filter's bass - -Sfm_Emu::Sfm_Emu() -{ - set_type( gme_sfm_type ); - set_gain( 1.4 ); - set_max_initial_silence( 30 ); - set_silence_lookahead( 30 ); // Some SFMs may have a lot of initialization code -} - -Sfm_Emu::~Sfm_Emu() { } - -// Track info - -static void hash_sfm_file( byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( data, data_size ); -} - -static void copy_field( char* out, size_t size, const Bml_Parser& in, char const* in_path ) -{ - const char * value = in.enumValue( in_path ); - if ( value ) strncpy( out, value, size - 1 ), out[ size - 1 ] = 0; - else out[ 0 ] = 0; -} - -static void copy_info( track_info_t* out, const Bml_Parser& in ) -{ - copy_field( out->song, sizeof(out->song), in, "information:title" ); - copy_field( out->game, sizeof(out->game), in, "information:game" ); - copy_field( out->author, sizeof(out->author), in, "information:author" ); - copy_field( out->composer, sizeof(out->composer), in, "information:composer" ); - copy_field( out->copyright, sizeof(out->copyright), in, "information:copyright" ); - copy_field( out->date, sizeof(out->date), in, "information:date" ); - copy_field( out->track, sizeof(out->track), in, "information:track" ); - copy_field( out->disc, sizeof(out->disc), in, "information:disc" ); - copy_field( out->dumper, sizeof(out->dumper), in, "information:dumper" ); - - char * end; - const char * value = in.enumValue( "timing:length" ); - if ( value ) - out->length = strtoul( value, &end, 10 ); - else - out->length = 0; - - value = in.enumValue( "timing:fade" ); - if ( value ) - out->fade_length = strtoul( value, &end, 10 ); - else - out->fade_length = 0; -} - -blargg_err_t Sfm_Emu::track_info_( track_info_t* out, int ) const -{ - copy_info( out, metadata ); - return blargg_ok; -} - -static void set_track_info( const track_info_t* in, Bml_Parser& out ) -{ - out.setValue( "information:title", in->song ); - out.setValue( "information:game", in->game ); - out.setValue( "information:author", in->author ); - out.setValue( "information:composer", in->composer ); - out.setValue( "information:copyright", in->copyright ); - out.setValue( "information:date", in->date ); - out.setValue( "information:track", in->track ); - out.setValue( "information:disc", in->disc ); - out.setValue( "information:dumper", in->dumper ); - - out.setValue( "timing:length", in->length ); - out.setValue( "timing:fade", in->fade_length ); -} - -blargg_err_t Sfm_Emu::set_track_info_( const track_info_t* in, int ) -{ - ::set_track_info(in, metadata); - - return blargg_ok; -} - -static blargg_err_t check_sfm_header( void const* header ) -{ - if ( memcmp( header, "SFM1", 4 ) ) - return blargg_err_file_type; - return blargg_ok; -} - -struct Sfm_File : Gme_Info_ -{ - blargg_vector data; - Bml_Parser metadata; - unsigned long original_metadata_size; - - Sfm_File() { set_type( gme_sfm_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - int file_size = in.remain(); - if ( file_size < Sfm_Emu::sfm_min_file_size ) - return blargg_err_file_type; - RETURN_ERR( data.resize( file_size ) ); - RETURN_ERR( in.read( data.begin(), data.end() - data.begin() ) ); - RETURN_ERR( check_sfm_header( data.begin() ) ); - if ( file_size < 8 ) - return "SFM file too small"; - int metadata_size = get_le32( data.begin() + 4 ); - metadata.parseDocument( (const char *)data.begin() + 8, metadata_size ); - original_metadata_size = metadata_size; - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_info( out, metadata ); - return blargg_ok; - } - - blargg_err_t set_track_info_( const track_info_t* in, int ) - { - ::set_track_info( in, metadata ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_sfm_file( data.begin(), data.end() - data.begin(), out ); - return blargg_ok; - } - - blargg_err_t save_( gme_writer_t writer, void* your_data ) const - { - std::string metadata_serialized; - metadata.serialize( metadata_serialized ); - uint8_t meta_length[4]; - set_le32( meta_length, (unsigned int) metadata_serialized.length() ); - writer( your_data, "SFM1", 4 ); - writer( your_data, meta_length, 4 ); - writer( your_data, metadata_serialized.c_str(), metadata_serialized.length() ); - writer( your_data, data.begin() + 4 + 4 + original_metadata_size, data.size() - (4 + 4 + original_metadata_size) ); - return blargg_ok; - } -}; - -static Music_Emu* new_sfm_emu () { return BLARGG_NEW Sfm_Emu ; } -static Music_Emu* new_sfm_file() { return BLARGG_NEW Sfm_File; } - -gme_type_t_ const gme_sfm_type [1] = {{ "Super Nintendo with log", 1, &new_sfm_emu, &new_sfm_file, "SFM", 0 }}; - -// Setup - -blargg_err_t Sfm_Emu::set_sample_rate_( int sample_rate ) -{ - smp.power(); - if ( sample_rate != native_sample_rate ) - { - RETURN_ERR( resampler.resize_buffer( native_sample_rate / 20 * 2 ) ); - RETURN_ERR( resampler.set_rate( (double) native_sample_rate / sample_rate ) ); // 0.9965 rolloff - } - return blargg_ok; -} - -void Sfm_Emu::mute_voices_( int m ) -{ - Music_Emu::mute_voices_( m ); - for ( int i = 0, j = 1; i < 8; ++i, j <<= 1 ) - smp.dsp.channel_enable( i, !( m & j ) ); -} - -blargg_err_t Sfm_Emu::load_mem_( byte const in [], int size ) -{ - set_voice_count( 8 ); - if ( size < Sfm_Emu::sfm_min_file_size ) - return blargg_err_file_type; - - static const char* const names [ 8 ] = { - "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", "DSP 8" - }; - set_voice_names( names ); - - RETURN_ERR( check_sfm_header( in ) ); - - const byte * ptr = file_begin(); - int metadata_size = get_le32(ptr + 4); - if ( file_size() < metadata_size + Sfm_Emu::sfm_min_file_size ) - return "SFM file too small"; - metadata.parseDocument((const char *) ptr + 8, metadata_size); - - return blargg_ok; -} - -// Emulation - -void Sfm_Emu::set_tempo_( double t ) -{ - smp.set_tempo( t ); -} - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - -#define META_ENUM_INT(n,d) (value = metadata.enumValue(n), value ? strtol(value, &end, 10) : (d)) - -static const byte ipl_rom[0x40] = -{ - 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, - 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78, - 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4, - 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5, - 0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB, - 0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA, - 0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD, - 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF -}; - -blargg_err_t Sfm_Emu::start_track_( int track ) -{ - RETURN_ERR( Music_Emu::start_track_( track ) ); - resampler.clear(); - filter.clear(); - const byte * ptr = file_begin(); - int metadata_size = get_le32(ptr + 4); - - memcpy( smp.iplrom, ipl_rom, 64 ); - - smp.reset(); - - memcpy( smp.apuram, ptr + 8 + metadata_size, 65536 ); - - memcpy( smp.dsp.spc_dsp.m.regs, ptr + 8 + metadata_size + 65536, 128 ); - - const uint8_t* log_begin = ptr + 8 + metadata_size + 65536 + 128; - const uint8_t* log_end = ptr + file_size(); - size_t loop_begin = log_end - log_begin; - - char * end; - const char * value; - - loop_begin = META_ENUM_INT("timing:loopstart", loop_begin); - - smp.set_sfm_queue( log_begin, log_end, log_begin + loop_begin ); - - uint32_t test = META_ENUM_INT("smp:test", 0); - smp.status.clock_speed = (test >> 6) & 3; - smp.status.timer_speed = (test >> 4) & 3; - smp.status.timers_enable = test & 0x08; - smp.status.ram_disable = test & 0x04; - smp.status.ram_writable = test & 0x02; - smp.status.timers_disable = test & 0x01; - - smp.status.iplrom_enable = META_ENUM_INT("smp:iplrom",1); - smp.status.dsp_addr = META_ENUM_INT("smp:dspaddr",0); - - value = metadata.enumValue("smp:ram"); - if (value) - { - smp.status.ram00f8 = strtol(value, &end, 10); - if (*end) - { - value = end + 1; - smp.status.ram00f9 = strtol(value, &end, 10); - } - } - - std::string name; - std::ostringstream oss; - - name = "smp:regs:"; - smp.regs.pc = META_ENUM_INT(name + "pc", 0xffc0); - smp.regs.a = META_ENUM_INT(name + "a", 0x00); - smp.regs.x = META_ENUM_INT(name + "x", 0x00); - smp.regs.y = META_ENUM_INT(name + "y", 0x00); - smp.regs.s = META_ENUM_INT(name + "s", 0xef); - smp.regs.p = META_ENUM_INT(name + "psw", 0x02); - - value = metadata.enumValue("smp:ports"); - if (value) - { - for (auto &n : smp.sfm_last) - { - n = strtol(value, &end, 10); - if (*end == ',') - value = end + 1; - else - break; - } - } - - for (int i = 0; i < 3; ++i) - { - SuperFamicom::SMP::Timer<192> &t = (i == 0 ? smp.timer0 : (i == 1 ? smp.timer1 : *(SuperFamicom::SMP::Timer<192>*)&smp.timer2)); - oss.str(""); - oss.clear(); - oss << "smp:timer[" << i << "]:"; - name = oss.str(); - value = metadata.enumValue(name + "enable"); - if (value) - { - t.enable = !!strtol(value, &end, 10); - } - value = metadata.enumValue(name + "target"); - if (value) - { - t.target = strtol(value, &end, 10); - } - value = metadata.enumValue(name + "stage"); - if (value) - { - t.stage0_ticks = strtol(value, &end, 10); - if (*end != ',') break; - value = end + 1; - t.stage1_ticks = strtol(value, &end, 10); - if (*end != ',') break; - value = end + 1; - t.stage2_ticks = strtol(value, &end, 10); - if (*end != ',') break; - value = end + 1; - t.stage3_ticks = strtol(value, &end, 10); - } - value = metadata.enumValue(name + "line"); - if (value) - { - t.current_line = !!strtol(value, &end, 10); - } - } - - smp.dsp.clock = META_ENUM_INT("dsp:clock", 0) * 4096; - - smp.dsp.spc_dsp.m.echo_hist_pos = &smp.dsp.spc_dsp.m.echo_hist[META_ENUM_INT("dsp:echohistaddr", 0)]; - - value = metadata.enumValue("dsp:echohistdata"); - if (value) - { - for (int i = 0; i < 8; ++i) - { - smp.dsp.spc_dsp.m.echo_hist[i][0] = strtol(value, &end, 10); - value = strchr(value, ','); - if (!value) break; - ++value; - smp.dsp.spc_dsp.m.echo_hist[i][1] = strtol(value, &end, 10); - value = strchr(value, ','); - if (!value) break; - ++value; - } - } - - smp.dsp.spc_dsp.m.phase = META_ENUM_INT("dsp:sample", 0); - smp.dsp.spc_dsp.m.kon = META_ENUM_INT("dsp:kon", 0); - smp.dsp.spc_dsp.m.noise = META_ENUM_INT("dsp:noise", 0); - smp.dsp.spc_dsp.m.counter = META_ENUM_INT("dsp:counter", 0); - smp.dsp.spc_dsp.m.echo_offset = META_ENUM_INT("dsp:echooffset", 0); - smp.dsp.spc_dsp.m.echo_length = META_ENUM_INT("dsp:echolength", 0); - smp.dsp.spc_dsp.m.new_kon = META_ENUM_INT("dsp:koncache", 0); - smp.dsp.spc_dsp.m.endx_buf = META_ENUM_INT("dsp:endx", 0); - smp.dsp.spc_dsp.m.envx_buf = META_ENUM_INT("dsp:envx", 0); - smp.dsp.spc_dsp.m.outx_buf = META_ENUM_INT("dsp:outx", 0); - smp.dsp.spc_dsp.m.t_pmon = META_ENUM_INT("dsp:pmon", 0); - smp.dsp.spc_dsp.m.t_non = META_ENUM_INT("dsp:non", 0); - smp.dsp.spc_dsp.m.t_eon = META_ENUM_INT("dsp:eon", 0); - smp.dsp.spc_dsp.m.t_dir = META_ENUM_INT("dsp:dir", 0); - smp.dsp.spc_dsp.m.t_koff = META_ENUM_INT("dsp:koff", 0); - smp.dsp.spc_dsp.m.t_brr_next_addr = META_ENUM_INT("dsp:brrnext", 0); - smp.dsp.spc_dsp.m.t_adsr0 = META_ENUM_INT("dsp:adsr0", 0); - smp.dsp.spc_dsp.m.t_brr_header = META_ENUM_INT("dsp:brrheader", 0); - smp.dsp.spc_dsp.m.t_brr_byte = META_ENUM_INT("dsp:brrdata", 0); - smp.dsp.spc_dsp.m.t_srcn = META_ENUM_INT("dsp:srcn", 0); - smp.dsp.spc_dsp.m.t_esa = META_ENUM_INT("dsp:esa", 0); - smp.dsp.spc_dsp.m.t_echo_enabled = !META_ENUM_INT("dsp:echodisable", 0); - smp.dsp.spc_dsp.m.t_dir_addr = META_ENUM_INT("dsp:diraddr", 0); - smp.dsp.spc_dsp.m.t_pitch = META_ENUM_INT("dsp:pitch", 0); - smp.dsp.spc_dsp.m.t_output = META_ENUM_INT("dsp:output", 0); - smp.dsp.spc_dsp.m.t_looped = META_ENUM_INT("dsp:looped", 0); - smp.dsp.spc_dsp.m.t_echo_ptr = META_ENUM_INT("dsp:echoaddr", 0); - - -#define META_ENUM_LEVELS(n, o) \ - value = metadata.enumValue(n); \ - if (value) \ - { \ - (o)[0] = strtol(value, &end, 10); \ - if (*end) \ - { \ - value = end + 1; \ - (o)[1] = strtol(value, &end, 10); \ - } \ - } - - META_ENUM_LEVELS("dsp:mainout", smp.dsp.spc_dsp.m.t_main_out); - META_ENUM_LEVELS("dsp:echoout", smp.dsp.spc_dsp.m.t_echo_out); - META_ENUM_LEVELS("dsp:echoin", smp.dsp.spc_dsp.m.t_echo_in); - -#undef META_ENUM_LEVELS - - for (int i = 0; i < 8; ++i) - { - oss.str(""); - oss.clear(); - oss << "dsp:voice[" << i << "]:"; - name = oss.str(); - SuperFamicom::SPC_DSP::voice_t & voice = smp.dsp.spc_dsp.m.voices[i]; - value = metadata.enumValue(name + "brrhistaddr"); - if (value) - { - voice.buf_pos = strtol(value, &end, 10); - } - value = metadata.enumValue(name + "brrhistdata"); - if (value) - { - for (int j = 0; j < SuperFamicom::SPC_DSP::brr_buf_size; ++j) - { - voice.buf[j] = voice.buf[j + SuperFamicom::SPC_DSP::brr_buf_size] = strtol(value, &end, 10); - if (!*end) break; - value = end + 1; - } - } - voice.interp_pos = META_ENUM_INT(name + "interpaddr",0); - voice.brr_addr = META_ENUM_INT(name + "brraddr",0); - voice.brr_offset = META_ENUM_INT(name + "brroffset",0); - voice.vbit = META_ENUM_INT(name + "vbit",0); - voice.regs = &smp.dsp.spc_dsp.m.regs[META_ENUM_INT(name + "vidx",0)]; - voice.kon_delay = META_ENUM_INT(name + "kondelay", 0); - voice.env_mode = (SuperFamicom::SPC_DSP::env_mode_t) META_ENUM_INT(name + "envmode", 0); - voice.env = META_ENUM_INT(name + "env", 0); - voice.t_envx_out = META_ENUM_INT(name + "envxout", 0); - voice.hidden_env = META_ENUM_INT(name + "envcache", 0); - } - - filter.set_gain( (int) (gain() * Spc_Filter::gain_unit) ); - return blargg_ok; -} - -#undef META_ENUM_INT - -void Sfm_Emu::create_updated_metadata( Bml_Parser &out ) const -{ - bool first; - std::string name; - std::ostringstream oss; - - metadata.serialize(name); - - out.parseDocument(name.c_str()); - - out.setValue( "smp:test", (smp.status.clock_speed << 6) | (smp.status.timer_speed << 4) | (smp.status.timers_enable << 3) | (smp.status.ram_disable << 2) | (smp.status.ram_writable << 1) | (smp.status.timers_disable << 0) ); - out.setValue( "smp:iplrom", smp.status.iplrom_enable ); - out.setValue( "smp:dspaddr", smp.status.dsp_addr ); - - oss.str(""); - oss.clear(); - oss << (unsigned long)smp.status.ram00f8 << "," << (unsigned long)smp.status.ram00f9; - out.setValue( "smp:ram", oss.str().c_str() ); - - name = "smp:regs:"; - out.setValue( name + "pc", smp.regs.pc ); - out.setValue( name + "a", smp.regs.a ); - out.setValue( name + "x", smp.regs.x ); - out.setValue( name + "y", smp.regs.y ); - out.setValue( name + "s", smp.regs.s ); - out.setValue( name + "psw", smp.regs.p ); - - oss.str(""); - oss.clear(); - first = true; - for (auto n : smp.sfm_last) - { - if (!first) oss << ","; - oss << (unsigned long)n; - first = false; - } - out.setValue("smp:ports", oss.str().c_str()); - - for (int i = 0; i < 3; ++i) - { - SuperFamicom::SMP::Timer<192> const& t = (i == 0 ? smp.timer0 : (i == 1 ? smp.timer1 : *(SuperFamicom::SMP::Timer<192>*)&smp.timer2)); - oss.str(""); - oss.clear(); - oss << "smp:timer[" << i << "]:"; - name = oss.str(); - out.setValue( name + "enable", t.enable ); - out.setValue( name + "target", t.target ); - oss.str(""); - oss.clear(); - oss << (unsigned long)t.stage0_ticks << "," << (unsigned long)t.stage1_ticks << "," - << (unsigned long)t.stage2_ticks << "," << (unsigned long)t.stage3_ticks; - out.setValue( name + "stage", oss.str().c_str() ); - out.setValue( name + "line", t.current_line ); - } - - out.setValue( "dsp:clock", smp.dsp.clock / 4096 ); - - out.setValue( "dsp:echohistaddr", smp.dsp.spc_dsp.m.echo_hist_pos - smp.dsp.spc_dsp.m.echo_hist ); - - oss.str(""); - oss.clear(); - for (int i = 0; i < 8; ++i) - { - oss << smp.dsp.spc_dsp.m.echo_hist[i][0] << "," - << smp.dsp.spc_dsp.m.echo_hist[i][1]; - if ( i != 7 ) oss << ","; - } - out.setValue( "dsp:echohistdata", oss.str().c_str() ); - - out.setValue( "dsp:sample", smp.dsp.spc_dsp.m.phase ); - out.setValue( "dsp:kon", smp.dsp.spc_dsp.m.kon ); - out.setValue( "dsp:noise", smp.dsp.spc_dsp.m.noise ); - out.setValue( "dsp:counter", smp.dsp.spc_dsp.m.counter ); - out.setValue( "dsp:echooffset", smp.dsp.spc_dsp.m.echo_offset ); - out.setValue( "dsp:echolength", smp.dsp.spc_dsp.m.echo_length ); - out.setValue( "dsp:koncache", smp.dsp.spc_dsp.m.new_kon ); - out.setValue( "dsp:endx", smp.dsp.spc_dsp.m.endx_buf ); - out.setValue( "dsp:envx", smp.dsp.spc_dsp.m.envx_buf ); - out.setValue( "dsp:outx", smp.dsp.spc_dsp.m.outx_buf ); - out.setValue( "dsp:pmon", smp.dsp.spc_dsp.m.t_pmon ); - out.setValue( "dsp:non", smp.dsp.spc_dsp.m.t_non ); - out.setValue( "dsp:eon", smp.dsp.spc_dsp.m.t_eon ); - out.setValue( "dsp:dir", smp.dsp.spc_dsp.m.t_dir ); - out.setValue( "dsp:koff", smp.dsp.spc_dsp.m.t_koff ); - out.setValue( "dsp:brrnext", smp.dsp.spc_dsp.m.t_brr_next_addr ); - out.setValue( "dsp:adsr0", smp.dsp.spc_dsp.m.t_adsr0 ); - out.setValue( "dsp:brrheader", smp.dsp.spc_dsp.m.t_brr_header ); - out.setValue( "dsp:brrdata", smp.dsp.spc_dsp.m.t_brr_byte ); - out.setValue( "dsp:srcn", smp.dsp.spc_dsp.m.t_srcn ); - out.setValue( "dsp:esa", smp.dsp.spc_dsp.m.t_esa ); - out.setValue( "dsp:echodisable", !smp.dsp.spc_dsp.m.t_echo_enabled ); - out.setValue( "dsp:diraddr", smp.dsp.spc_dsp.m.t_dir_addr ); - out.setValue( "dsp:pitch", smp.dsp.spc_dsp.m.t_pitch ); - out.setValue( "dsp:output", smp.dsp.spc_dsp.m.t_output ); - out.setValue( "dsp:looped", smp.dsp.spc_dsp.m.t_looped ); - out.setValue( "dsp:echoaddr", smp.dsp.spc_dsp.m.t_echo_ptr ); - -#define META_WRITE_LEVELS(n, o) \ - oss.str(""); \ - oss.clear(); \ - oss << (o)[0] << "," << (o)[1]; \ - out.setValue((n), oss.str().c_str()); - - META_WRITE_LEVELS("dsp:mainout", smp.dsp.spc_dsp.m.t_main_out); - META_WRITE_LEVELS("dsp:echoout", smp.dsp.spc_dsp.m.t_echo_out); - META_WRITE_LEVELS("dsp:echoin", smp.dsp.spc_dsp.m.t_echo_in); - -#undef META_WRITE_LEVELS - - for (int i = 0; i < 8; ++i) - { - oss.str(""); - oss.clear(); - oss << "dsp:voice[" << i << "]:"; - name = oss.str(); - SuperFamicom::SPC_DSP::voice_t const& voice = smp.dsp.spc_dsp.m.voices[i]; - out.setValue( name + "brrhistaddr", voice.buf_pos ); - oss.str(""); - oss.clear(); - for (int j = 0; j < SuperFamicom::SPC_DSP::brr_buf_size; ++j) - { - oss << voice.buf[j]; - if ( j != SuperFamicom::SPC_DSP::brr_buf_size - 1 ) - oss << ","; - } - out.setValue( name + "brrhistdata", oss.str().c_str() ); - out.setValue( name + "interpaddr", voice.interp_pos ); - out.setValue( name + "brraddr", voice.brr_addr ); - out.setValue( name + "brroffset", voice.brr_offset ); - out.setValue( name + "vbit", voice.vbit ); - out.setValue( name + "vidx", voice.regs - smp.dsp.spc_dsp.m.regs); - out.setValue( name + "kondelay", voice.kon_delay ); - out.setValue( name + "envmode", voice.env_mode ); - out.setValue( name + "env", voice.env ); - out.setValue( name + "envxout", voice.t_envx_out ); - out.setValue( name + "envcache", voice.hidden_env ); - } -} - -blargg_err_t Sfm_Emu::save_( gme_writer_t writer, void* your_data ) const -{ - std::string meta_serialized; - - Bml_Parser metadata; - create_updated_metadata( metadata ); - metadata.serialize( meta_serialized ); - - RETURN_ERR( writer( your_data, "SFM1", 4 ) ); - - uint8_t temp[4]; - uint32_t meta_length = (uint32_t) meta_serialized.length(); - set_le32( temp, meta_length ); - RETURN_ERR( writer( your_data, temp, 4 ) ); - - RETURN_ERR( writer( your_data, meta_serialized.c_str(), meta_length ) ); - - RETURN_ERR( writer( your_data, smp.apuram, 65536 ) ); - - RETURN_ERR( writer( your_data, smp.dsp.spc_dsp.m.regs, 128 ) ); - - if ( smp.get_sfm_queue_remain() ) - RETURN_ERR( writer( your_data, smp.get_sfm_queue(), smp.get_sfm_queue_remain() ) ); - - return blargg_ok; -} - -blargg_err_t Sfm_Emu::play_and_filter( int count, sample_t out [] ) -{ - smp.render( out, count ); - filter.run( out, count ); - return blargg_ok; -} - -blargg_err_t Sfm_Emu::skip_( int count ) -{ - if ( sample_rate() != native_sample_rate ) - { - count = (int) (count * resampler.rate()) & ~1; - count -= resampler.skip_input( count ); - } - - // TODO: shouldn't skip be adjusted for the 64 samples read afterwards? - - if ( count > 0 ) - { - smp.skip( count ); - filter.clear(); - } - - if ( sample_rate() != native_sample_rate ) - { - // eliminate pop due to resampler - const int resampler_latency = 64; - sample_t buf [resampler_latency]; - return play_( resampler_latency, buf ); - } - - return blargg_ok; -} - -blargg_err_t Sfm_Emu::play_( int count, sample_t out [] ) -{ - if ( sample_rate() == native_sample_rate ) - return play_and_filter( count, out ); - - int remain = count; - while ( remain > 0 ) - { - remain -= resampler.read( &out [count - remain], remain ); - if ( remain > 0 ) - { - int n = resampler.buffer_free(); - RETURN_ERR( play_and_filter( n, resampler.buffer() ) ); - resampler.write( n ); - } - } - check( remain == 0 ); - return blargg_ok; -} - -blargg_err_t Sfm_Emu::hash_( Hash_Function& out ) const -{ - hash_sfm_file( file_begin(), file_size(), out ); - return blargg_ok; -} - +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Spc_Sfm.h" + +#include "blargg_endian.h" + +#include + +/* Copyright (C) 2004-2013 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// TODO: support Spc_Filter's bass + +Sfm_Emu::Sfm_Emu() +{ + set_type( gme_sfm_type ); + set_gain( 1.4 ); + set_max_initial_silence( 30 ); + set_silence_lookahead( 30 ); // Some SFMs may have a lot of initialization code +} + +Sfm_Emu::~Sfm_Emu() { } + +// Track info + +static void hash_sfm_file( byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( data, data_size ); +} + +static void copy_field( char* out, size_t size, const Bml_Parser& in, char const* in_path ) +{ + const char * value = in.enumValue( in_path ); + if ( value ) strncpy( out, value, size - 1 ), out[ size - 1 ] = 0; + else out[ 0 ] = 0; +} + +static void copy_info( track_info_t* out, const Bml_Parser& in ) +{ + copy_field( out->song, sizeof(out->song), in, "information:title" ); + copy_field( out->game, sizeof(out->game), in, "information:game" ); + copy_field( out->author, sizeof(out->author), in, "information:author" ); + copy_field( out->composer, sizeof(out->composer), in, "information:composer" ); + copy_field( out->copyright, sizeof(out->copyright), in, "information:copyright" ); + copy_field( out->date, sizeof(out->date), in, "information:date" ); + copy_field( out->track, sizeof(out->track), in, "information:track" ); + copy_field( out->disc, sizeof(out->disc), in, "information:disc" ); + copy_field( out->dumper, sizeof(out->dumper), in, "information:dumper" ); + + char * end; + const char * value = in.enumValue( "timing:length" ); + if ( value ) + out->length = strtoul( value, &end, 10 ); + else + out->length = 0; + + value = in.enumValue( "timing:fade" ); + if ( value ) + out->fade_length = strtoul( value, &end, 10 ); + else + out->fade_length = 0; +} + +blargg_err_t Sfm_Emu::track_info_( track_info_t* out, int ) const +{ + copy_info( out, metadata ); + return blargg_ok; +} + +static void set_track_info( const track_info_t* in, Bml_Parser& out ) +{ + out.setValue( "information:title", in->song ); + out.setValue( "information:game", in->game ); + out.setValue( "information:author", in->author ); + out.setValue( "information:composer", in->composer ); + out.setValue( "information:copyright", in->copyright ); + out.setValue( "information:date", in->date ); + out.setValue( "information:track", in->track ); + out.setValue( "information:disc", in->disc ); + out.setValue( "information:dumper", in->dumper ); + + out.setValue( "timing:length", in->length ); + out.setValue( "timing:fade", in->fade_length ); +} + +blargg_err_t Sfm_Emu::set_track_info_( const track_info_t* in, int ) +{ + ::set_track_info(in, metadata); + + return blargg_ok; +} + +static blargg_err_t check_sfm_header( void const* header ) +{ + if ( memcmp( header, "SFM1", 4 ) ) + return blargg_err_file_type; + return blargg_ok; +} + +struct Sfm_File : Gme_Info_ +{ + blargg_vector data; + Bml_Parser metadata; + unsigned long original_metadata_size; + + Sfm_File() { set_type( gme_sfm_type ); } + + blargg_err_t load_( Data_Reader& in ) + { + int file_size = in.remain(); + if ( file_size < Sfm_Emu::sfm_min_file_size ) + return blargg_err_file_type; + RETURN_ERR( data.resize( file_size ) ); + RETURN_ERR( in.read( data.begin(), data.end() - data.begin() ) ); + RETURN_ERR( check_sfm_header( data.begin() ) ); + if ( file_size < 8 ) + return "SFM file too small"; + int metadata_size = get_le32( data.begin() + 4 ); + metadata.parseDocument( (const char *)data.begin() + 8, metadata_size ); + original_metadata_size = metadata_size; + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + copy_info( out, metadata ); + return blargg_ok; + } + + blargg_err_t set_track_info_( const track_info_t* in, int ) + { + ::set_track_info( in, metadata ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_sfm_file( data.begin(), data.end() - data.begin(), out ); + return blargg_ok; + } + + blargg_err_t save_( gme_writer_t writer, void* your_data ) const + { + std::string metadata_serialized; + metadata.serialize( metadata_serialized ); + uint8_t meta_length[4]; + set_le32( meta_length, (unsigned int) metadata_serialized.length() ); + writer( your_data, "SFM1", 4 ); + writer( your_data, meta_length, 4 ); + writer( your_data, metadata_serialized.c_str(), metadata_serialized.length() ); + writer( your_data, data.begin() + 4 + 4 + original_metadata_size, data.size() - (4 + 4 + original_metadata_size) ); + return blargg_ok; + } +}; + +static Music_Emu* new_sfm_emu () { return BLARGG_NEW Sfm_Emu ; } +static Music_Emu* new_sfm_file() { return BLARGG_NEW Sfm_File; } + +gme_type_t_ const gme_sfm_type [1] = {{ "Super Nintendo with log", 1, &new_sfm_emu, &new_sfm_file, "SFM", 0 }}; + +// Setup + +blargg_err_t Sfm_Emu::set_sample_rate_( int sample_rate ) +{ + smp.power(); + if ( sample_rate != native_sample_rate ) + { + RETURN_ERR( resampler.resize_buffer( native_sample_rate / 20 * 2 ) ); + RETURN_ERR( resampler.set_rate( (double) native_sample_rate / sample_rate ) ); // 0.9965 rolloff + } + return blargg_ok; +} + +void Sfm_Emu::mute_voices_( int m ) +{ + Music_Emu::mute_voices_( m ); + for ( int i = 0, j = 1; i < 8; ++i, j <<= 1 ) + smp.dsp.channel_enable( i, !( m & j ) ); +} + +blargg_err_t Sfm_Emu::load_mem_( byte const in [], int size ) +{ + set_voice_count( 8 ); + if ( size < Sfm_Emu::sfm_min_file_size ) + return blargg_err_file_type; + + static const char* const names [ 8 ] = { + "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", "DSP 8" + }; + set_voice_names( names ); + + RETURN_ERR( check_sfm_header( in ) ); + + const byte * ptr = file_begin(); + int metadata_size = get_le32(ptr + 4); + if ( file_size() < metadata_size + Sfm_Emu::sfm_min_file_size ) + return "SFM file too small"; + metadata.parseDocument((const char *) ptr + 8, metadata_size); + + return blargg_ok; +} + +// Emulation + +void Sfm_Emu::set_tempo_( double t ) +{ + smp.set_tempo( t ); +} + +// (n ? n : 256) +#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) + +#define META_ENUM_INT(n,d) (value = metadata.enumValue(n), value ? strtol(value, &end, 10) : (d)) + +static const byte ipl_rom[0x40] = +{ + 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, + 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78, + 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4, + 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5, + 0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB, + 0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA, + 0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD, + 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF +}; + +blargg_err_t Sfm_Emu::start_track_( int track ) +{ + RETURN_ERR( Music_Emu::start_track_( track ) ); + resampler.clear(); + filter.clear(); + const byte * ptr = file_begin(); + int metadata_size = get_le32(ptr + 4); + + memcpy( smp.iplrom, ipl_rom, 64 ); + + smp.reset(); + + memcpy( smp.apuram, ptr + 8 + metadata_size, 65536 ); + + memcpy( smp.dsp.spc_dsp.m.regs, ptr + 8 + metadata_size + 65536, 128 ); + + const uint8_t* log_begin = ptr + 8 + metadata_size + 65536 + 128; + const uint8_t* log_end = ptr + file_size(); + size_t loop_begin = log_end - log_begin; + + char * end; + const char * value; + + loop_begin = META_ENUM_INT("timing:loopstart", loop_begin); + + smp.set_sfm_queue( log_begin, log_end, log_begin + loop_begin ); + + uint32_t test = META_ENUM_INT("smp:test", 0); + smp.status.clock_speed = (test >> 6) & 3; + smp.status.timer_speed = (test >> 4) & 3; + smp.status.timers_enable = test & 0x08; + smp.status.ram_disable = test & 0x04; + smp.status.ram_writable = test & 0x02; + smp.status.timers_disable = test & 0x01; + + smp.status.iplrom_enable = META_ENUM_INT("smp:iplrom",1); + smp.status.dsp_addr = META_ENUM_INT("smp:dspaddr",0); + + value = metadata.enumValue("smp:ram"); + if (value) + { + smp.status.ram00f8 = strtol(value, &end, 10); + if (*end) + { + value = end + 1; + smp.status.ram00f9 = strtol(value, &end, 10); + } + } + + std::string name; + std::ostringstream oss; + + name = "smp:regs:"; + smp.regs.pc = META_ENUM_INT(name + "pc", 0xffc0); + smp.regs.a = META_ENUM_INT(name + "a", 0x00); + smp.regs.x = META_ENUM_INT(name + "x", 0x00); + smp.regs.y = META_ENUM_INT(name + "y", 0x00); + smp.regs.s = META_ENUM_INT(name + "s", 0xef); + smp.regs.p = META_ENUM_INT(name + "psw", 0x02); + + value = metadata.enumValue("smp:ports"); + if (value) + { + for (auto &n : smp.sfm_last) + { + n = strtol(value, &end, 10); + if (*end == ',') + value = end + 1; + else + break; + } + } + + for (int i = 0; i < 3; ++i) + { + SuperFamicom::SMP::Timer<192> &t = (i == 0 ? smp.timer0 : (i == 1 ? smp.timer1 : *(SuperFamicom::SMP::Timer<192>*)&smp.timer2)); + oss.str(""); + oss.clear(); + oss << "smp:timer[" << i << "]:"; + name = oss.str(); + value = metadata.enumValue(name + "enable"); + if (value) + { + t.enable = !!strtol(value, &end, 10); + } + value = metadata.enumValue(name + "target"); + if (value) + { + t.target = strtol(value, &end, 10); + } + value = metadata.enumValue(name + "stage"); + if (value) + { + t.stage0_ticks = strtol(value, &end, 10); + if (*end != ',') break; + value = end + 1; + t.stage1_ticks = strtol(value, &end, 10); + if (*end != ',') break; + value = end + 1; + t.stage2_ticks = strtol(value, &end, 10); + if (*end != ',') break; + value = end + 1; + t.stage3_ticks = strtol(value, &end, 10); + } + value = metadata.enumValue(name + "line"); + if (value) + { + t.current_line = !!strtol(value, &end, 10); + } + } + + smp.dsp.clock = META_ENUM_INT("dsp:clock", 0) * 4096; + + smp.dsp.spc_dsp.m.echo_hist_pos = &smp.dsp.spc_dsp.m.echo_hist[META_ENUM_INT("dsp:echohistaddr", 0)]; + + value = metadata.enumValue("dsp:echohistdata"); + if (value) + { + for (int i = 0; i < 8; ++i) + { + smp.dsp.spc_dsp.m.echo_hist[i][0] = strtol(value, &end, 10); + value = strchr(value, ','); + if (!value) break; + ++value; + smp.dsp.spc_dsp.m.echo_hist[i][1] = strtol(value, &end, 10); + value = strchr(value, ','); + if (!value) break; + ++value; + } + } + + smp.dsp.spc_dsp.m.phase = META_ENUM_INT("dsp:sample", 0); + smp.dsp.spc_dsp.m.kon = META_ENUM_INT("dsp:kon", 0); + smp.dsp.spc_dsp.m.noise = META_ENUM_INT("dsp:noise", 0); + smp.dsp.spc_dsp.m.counter = META_ENUM_INT("dsp:counter", 0); + smp.dsp.spc_dsp.m.echo_offset = META_ENUM_INT("dsp:echooffset", 0); + smp.dsp.spc_dsp.m.echo_length = META_ENUM_INT("dsp:echolength", 0); + smp.dsp.spc_dsp.m.new_kon = META_ENUM_INT("dsp:koncache", 0); + smp.dsp.spc_dsp.m.endx_buf = META_ENUM_INT("dsp:endx", 0); + smp.dsp.spc_dsp.m.envx_buf = META_ENUM_INT("dsp:envx", 0); + smp.dsp.spc_dsp.m.outx_buf = META_ENUM_INT("dsp:outx", 0); + smp.dsp.spc_dsp.m.t_pmon = META_ENUM_INT("dsp:pmon", 0); + smp.dsp.spc_dsp.m.t_non = META_ENUM_INT("dsp:non", 0); + smp.dsp.spc_dsp.m.t_eon = META_ENUM_INT("dsp:eon", 0); + smp.dsp.spc_dsp.m.t_dir = META_ENUM_INT("dsp:dir", 0); + smp.dsp.spc_dsp.m.t_koff = META_ENUM_INT("dsp:koff", 0); + smp.dsp.spc_dsp.m.t_brr_next_addr = META_ENUM_INT("dsp:brrnext", 0); + smp.dsp.spc_dsp.m.t_adsr0 = META_ENUM_INT("dsp:adsr0", 0); + smp.dsp.spc_dsp.m.t_brr_header = META_ENUM_INT("dsp:brrheader", 0); + smp.dsp.spc_dsp.m.t_brr_byte = META_ENUM_INT("dsp:brrdata", 0); + smp.dsp.spc_dsp.m.t_srcn = META_ENUM_INT("dsp:srcn", 0); + smp.dsp.spc_dsp.m.t_esa = META_ENUM_INT("dsp:esa", 0); + smp.dsp.spc_dsp.m.t_echo_enabled = !META_ENUM_INT("dsp:echodisable", 0); + smp.dsp.spc_dsp.m.t_dir_addr = META_ENUM_INT("dsp:diraddr", 0); + smp.dsp.spc_dsp.m.t_pitch = META_ENUM_INT("dsp:pitch", 0); + smp.dsp.spc_dsp.m.t_output = META_ENUM_INT("dsp:output", 0); + smp.dsp.spc_dsp.m.t_looped = META_ENUM_INT("dsp:looped", 0); + smp.dsp.spc_dsp.m.t_echo_ptr = META_ENUM_INT("dsp:echoaddr", 0); + + +#define META_ENUM_LEVELS(n, o) \ + value = metadata.enumValue(n); \ + if (value) \ + { \ + (o)[0] = strtol(value, &end, 10); \ + if (*end) \ + { \ + value = end + 1; \ + (o)[1] = strtol(value, &end, 10); \ + } \ + } + + META_ENUM_LEVELS("dsp:mainout", smp.dsp.spc_dsp.m.t_main_out); + META_ENUM_LEVELS("dsp:echoout", smp.dsp.spc_dsp.m.t_echo_out); + META_ENUM_LEVELS("dsp:echoin", smp.dsp.spc_dsp.m.t_echo_in); + +#undef META_ENUM_LEVELS + + for (int i = 0; i < 8; ++i) + { + oss.str(""); + oss.clear(); + oss << "dsp:voice[" << i << "]:"; + name = oss.str(); + SuperFamicom::SPC_DSP::voice_t & voice = smp.dsp.spc_dsp.m.voices[i]; + value = metadata.enumValue(name + "brrhistaddr"); + if (value) + { + voice.buf_pos = strtol(value, &end, 10); + } + value = metadata.enumValue(name + "brrhistdata"); + if (value) + { + for (int j = 0; j < SuperFamicom::SPC_DSP::brr_buf_size; ++j) + { + voice.buf[j] = voice.buf[j + SuperFamicom::SPC_DSP::brr_buf_size] = strtol(value, &end, 10); + if (!*end) break; + value = end + 1; + } + } + voice.interp_pos = META_ENUM_INT(name + "interpaddr",0); + voice.brr_addr = META_ENUM_INT(name + "brraddr",0); + voice.brr_offset = META_ENUM_INT(name + "brroffset",0); + voice.vbit = META_ENUM_INT(name + "vbit",0); + voice.regs = &smp.dsp.spc_dsp.m.regs[META_ENUM_INT(name + "vidx",0)]; + voice.kon_delay = META_ENUM_INT(name + "kondelay", 0); + voice.env_mode = (SuperFamicom::SPC_DSP::env_mode_t) META_ENUM_INT(name + "envmode", 0); + voice.env = META_ENUM_INT(name + "env", 0); + voice.t_envx_out = META_ENUM_INT(name + "envxout", 0); + voice.hidden_env = META_ENUM_INT(name + "envcache", 0); + } + + filter.set_gain( (int) (gain() * Spc_Filter::gain_unit) ); + return blargg_ok; +} + +#undef META_ENUM_INT + +void Sfm_Emu::create_updated_metadata( Bml_Parser &out ) const +{ + bool first; + std::string name; + std::ostringstream oss; + + metadata.serialize(name); + + out.parseDocument(name.c_str()); + + out.setValue( "smp:test", (smp.status.clock_speed << 6) | (smp.status.timer_speed << 4) | (smp.status.timers_enable << 3) | (smp.status.ram_disable << 2) | (smp.status.ram_writable << 1) | (smp.status.timers_disable << 0) ); + out.setValue( "smp:iplrom", smp.status.iplrom_enable ); + out.setValue( "smp:dspaddr", smp.status.dsp_addr ); + + oss.str(""); + oss.clear(); + oss << (unsigned long)smp.status.ram00f8 << "," << (unsigned long)smp.status.ram00f9; + out.setValue( "smp:ram", oss.str().c_str() ); + + name = "smp:regs:"; + out.setValue( name + "pc", smp.regs.pc ); + out.setValue( name + "a", smp.regs.a ); + out.setValue( name + "x", smp.regs.x ); + out.setValue( name + "y", smp.regs.y ); + out.setValue( name + "s", smp.regs.s ); + out.setValue( name + "psw", smp.regs.p ); + + oss.str(""); + oss.clear(); + first = true; + for (auto n : smp.sfm_last) + { + if (!first) oss << ","; + oss << (unsigned long)n; + first = false; + } + out.setValue("smp:ports", oss.str().c_str()); + + for (int i = 0; i < 3; ++i) + { + SuperFamicom::SMP::Timer<192> const& t = (i == 0 ? smp.timer0 : (i == 1 ? smp.timer1 : *(SuperFamicom::SMP::Timer<192>*)&smp.timer2)); + oss.str(""); + oss.clear(); + oss << "smp:timer[" << i << "]:"; + name = oss.str(); + out.setValue( name + "enable", t.enable ); + out.setValue( name + "target", t.target ); + oss.str(""); + oss.clear(); + oss << (unsigned long)t.stage0_ticks << "," << (unsigned long)t.stage1_ticks << "," + << (unsigned long)t.stage2_ticks << "," << (unsigned long)t.stage3_ticks; + out.setValue( name + "stage", oss.str().c_str() ); + out.setValue( name + "line", t.current_line ); + } + + out.setValue( "dsp:clock", smp.dsp.clock / 4096 ); + + out.setValue( "dsp:echohistaddr", smp.dsp.spc_dsp.m.echo_hist_pos - smp.dsp.spc_dsp.m.echo_hist ); + + oss.str(""); + oss.clear(); + for (int i = 0; i < 8; ++i) + { + oss << smp.dsp.spc_dsp.m.echo_hist[i][0] << "," + << smp.dsp.spc_dsp.m.echo_hist[i][1]; + if ( i != 7 ) oss << ","; + } + out.setValue( "dsp:echohistdata", oss.str().c_str() ); + + out.setValue( "dsp:sample", smp.dsp.spc_dsp.m.phase ); + out.setValue( "dsp:kon", smp.dsp.spc_dsp.m.kon ); + out.setValue( "dsp:noise", smp.dsp.spc_dsp.m.noise ); + out.setValue( "dsp:counter", smp.dsp.spc_dsp.m.counter ); + out.setValue( "dsp:echooffset", smp.dsp.spc_dsp.m.echo_offset ); + out.setValue( "dsp:echolength", smp.dsp.spc_dsp.m.echo_length ); + out.setValue( "dsp:koncache", smp.dsp.spc_dsp.m.new_kon ); + out.setValue( "dsp:endx", smp.dsp.spc_dsp.m.endx_buf ); + out.setValue( "dsp:envx", smp.dsp.spc_dsp.m.envx_buf ); + out.setValue( "dsp:outx", smp.dsp.spc_dsp.m.outx_buf ); + out.setValue( "dsp:pmon", smp.dsp.spc_dsp.m.t_pmon ); + out.setValue( "dsp:non", smp.dsp.spc_dsp.m.t_non ); + out.setValue( "dsp:eon", smp.dsp.spc_dsp.m.t_eon ); + out.setValue( "dsp:dir", smp.dsp.spc_dsp.m.t_dir ); + out.setValue( "dsp:koff", smp.dsp.spc_dsp.m.t_koff ); + out.setValue( "dsp:brrnext", smp.dsp.spc_dsp.m.t_brr_next_addr ); + out.setValue( "dsp:adsr0", smp.dsp.spc_dsp.m.t_adsr0 ); + out.setValue( "dsp:brrheader", smp.dsp.spc_dsp.m.t_brr_header ); + out.setValue( "dsp:brrdata", smp.dsp.spc_dsp.m.t_brr_byte ); + out.setValue( "dsp:srcn", smp.dsp.spc_dsp.m.t_srcn ); + out.setValue( "dsp:esa", smp.dsp.spc_dsp.m.t_esa ); + out.setValue( "dsp:echodisable", !smp.dsp.spc_dsp.m.t_echo_enabled ); + out.setValue( "dsp:diraddr", smp.dsp.spc_dsp.m.t_dir_addr ); + out.setValue( "dsp:pitch", smp.dsp.spc_dsp.m.t_pitch ); + out.setValue( "dsp:output", smp.dsp.spc_dsp.m.t_output ); + out.setValue( "dsp:looped", smp.dsp.spc_dsp.m.t_looped ); + out.setValue( "dsp:echoaddr", smp.dsp.spc_dsp.m.t_echo_ptr ); + +#define META_WRITE_LEVELS(n, o) \ + oss.str(""); \ + oss.clear(); \ + oss << (o)[0] << "," << (o)[1]; \ + out.setValue((n), oss.str().c_str()); + + META_WRITE_LEVELS("dsp:mainout", smp.dsp.spc_dsp.m.t_main_out); + META_WRITE_LEVELS("dsp:echoout", smp.dsp.spc_dsp.m.t_echo_out); + META_WRITE_LEVELS("dsp:echoin", smp.dsp.spc_dsp.m.t_echo_in); + +#undef META_WRITE_LEVELS + + for (int i = 0; i < 8; ++i) + { + oss.str(""); + oss.clear(); + oss << "dsp:voice[" << i << "]:"; + name = oss.str(); + SuperFamicom::SPC_DSP::voice_t const& voice = smp.dsp.spc_dsp.m.voices[i]; + out.setValue( name + "brrhistaddr", voice.buf_pos ); + oss.str(""); + oss.clear(); + for (int j = 0; j < SuperFamicom::SPC_DSP::brr_buf_size; ++j) + { + oss << voice.buf[j]; + if ( j != SuperFamicom::SPC_DSP::brr_buf_size - 1 ) + oss << ","; + } + out.setValue( name + "brrhistdata", oss.str().c_str() ); + out.setValue( name + "interpaddr", voice.interp_pos ); + out.setValue( name + "brraddr", voice.brr_addr ); + out.setValue( name + "brroffset", voice.brr_offset ); + out.setValue( name + "vbit", voice.vbit ); + out.setValue( name + "vidx", voice.regs - smp.dsp.spc_dsp.m.regs); + out.setValue( name + "kondelay", voice.kon_delay ); + out.setValue( name + "envmode", voice.env_mode ); + out.setValue( name + "env", voice.env ); + out.setValue( name + "envxout", voice.t_envx_out ); + out.setValue( name + "envcache", voice.hidden_env ); + } +} + +blargg_err_t Sfm_Emu::save_( gme_writer_t writer, void* your_data ) const +{ + std::string meta_serialized; + + Bml_Parser metadata; + create_updated_metadata( metadata ); + metadata.serialize( meta_serialized ); + + RETURN_ERR( writer( your_data, "SFM1", 4 ) ); + + uint8_t temp[4]; + uint32_t meta_length = (uint32_t) meta_serialized.length(); + set_le32( temp, meta_length ); + RETURN_ERR( writer( your_data, temp, 4 ) ); + + RETURN_ERR( writer( your_data, meta_serialized.c_str(), meta_length ) ); + + RETURN_ERR( writer( your_data, smp.apuram, 65536 ) ); + + RETURN_ERR( writer( your_data, smp.dsp.spc_dsp.m.regs, 128 ) ); + + if ( smp.get_sfm_queue_remain() ) + RETURN_ERR( writer( your_data, smp.get_sfm_queue(), smp.get_sfm_queue_remain() ) ); + + return blargg_ok; +} + +blargg_err_t Sfm_Emu::play_and_filter( int count, sample_t out [] ) +{ + smp.render( out, count ); + filter.run( out, count ); + return blargg_ok; +} + +blargg_err_t Sfm_Emu::skip_( int count ) +{ + if ( sample_rate() != native_sample_rate ) + { + count = (int) (count * resampler.rate()) & ~1; + count -= resampler.skip_input( count ); + } + + // TODO: shouldn't skip be adjusted for the 64 samples read afterwards? + + if ( count > 0 ) + { + smp.skip( count ); + filter.clear(); + } + + if ( sample_rate() != native_sample_rate ) + { + // eliminate pop due to resampler + const int resampler_latency = 64; + sample_t buf [resampler_latency]; + return play_( resampler_latency, buf ); + } + + return blargg_ok; +} + +blargg_err_t Sfm_Emu::play_( int count, sample_t out [] ) +{ + if ( sample_rate() == native_sample_rate ) + return play_and_filter( count, out ); + + int remain = count; + while ( remain > 0 ) + { + remain -= resampler.read( &out [count - remain], remain ); + if ( remain > 0 ) + { + int n = resampler.buffer_free(); + RETURN_ERR( play_and_filter( n, resampler.buffer() ) ); + resampler.write( n ); + } + } + check( remain == 0 ); + return blargg_ok; +} + +blargg_err_t Sfm_Emu::hash_( Hash_Function& out ) const +{ + hash_sfm_file( file_begin(), file_size(), out ); + return blargg_ok; +} + diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Spc_Sfm.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Spc_Sfm.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Spc_Sfm.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Spc_Sfm.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,77 +1,77 @@ -// Super Nintendo SFM music file emulator - -// Game_Music_Emu $vers -#ifndef SPC_SFM_H -#define SPC_SFM_H - -#include "Music_Emu.h" -#include "higan/smp/smp.hpp" -#include "Spc_Filter.h" - -#include "Bml_Parser.h" - -#if GME_SPC_FAST_RESAMPLER - #include "Upsampler.h" - typedef Upsampler Spc_Emu_Resampler; -#else - #include "Fir_Resampler.h" - typedef Fir_Resampler<24> Spc_Emu_Resampler; -#endif - -class Sfm_Emu : public Music_Emu { -public: - // Minimum allowed file size - enum { sfm_min_file_size = 8 + 65536 + 128 }; - - // The Super Nintendo hardware samples at 32kHz. Other sample rates are - // handled by resampling the 32kHz output; emulation accuracy is not affected. - enum { native_sample_rate = 32000 }; - - // This will serialize the current state of the emulator into a new SFM file - blargg_err_t serialize( std::vector & out ); - - // Disables annoying pseudo-surround effect some music uses - void disable_surround( bool disable = true ) { smp.dsp.disable_surround( disable ); } - - // Enables gaussian, cubic or sinc interpolation - void interpolation_level( int level = 0 ) { smp.dsp.spc_dsp.interpolation_level( level ); } - - SuperFamicom::SMP const* get_smp() const; - SuperFamicom::SMP * get_smp(); - - blargg_err_t hash_( Hash_Function& ) const; - - static gme_type_t static_type() { return gme_sfm_type; } - -// Implementation -public: - Sfm_Emu(); - ~Sfm_Emu(); - -protected: - virtual blargg_err_t load_mem_( byte const [], int ); - virtual blargg_err_t track_info_( track_info_t*, int track ) const; - virtual blargg_err_t set_track_info_( const track_info_t*, int track ); - virtual blargg_err_t set_sample_rate_( int ); - virtual blargg_err_t start_track_( int ); - virtual blargg_err_t play_( int, sample_t [] ); - virtual blargg_err_t skip_( int ); - virtual void mute_voices_( int ); - virtual void set_tempo_( double ); - virtual blargg_err_t save_( gme_writer_t, void* ) const; - -private: - Spc_Emu_Resampler resampler; - Spc_Filter filter; - SuperFamicom::SMP smp; - - Bml_Parser metadata; - void create_updated_metadata(Bml_Parser &out) const; - - blargg_err_t play_and_filter( int count, sample_t out [] ); -}; - -inline SuperFamicom::SMP const* Sfm_Emu::get_smp() const { return &smp; } -inline SuperFamicom::SMP * Sfm_Emu::get_smp() { return &smp; } - -#endif // SPC_SFM_H +// Super Nintendo SFM music file emulator + +// Game_Music_Emu $vers +#ifndef SPC_SFM_H +#define SPC_SFM_H + +#include "Music_Emu.h" +#include "higan/smp/smp.hpp" +#include "Spc_Filter.h" + +#include "Bml_Parser.h" + +#if GME_SPC_FAST_RESAMPLER + #include "Upsampler.h" + typedef Upsampler Spc_Emu_Resampler; +#else + #include "Fir_Resampler.h" + typedef Fir_Resampler<24> Spc_Emu_Resampler; +#endif + +class Sfm_Emu : public Music_Emu { +public: + // Minimum allowed file size + enum { sfm_min_file_size = 8 + 65536 + 128 }; + + // The Super Nintendo hardware samples at 32kHz. Other sample rates are + // handled by resampling the 32kHz output; emulation accuracy is not affected. + enum { native_sample_rate = 32000 }; + + // This will serialize the current state of the emulator into a new SFM file + blargg_err_t serialize( std::vector & out ); + + // Disables annoying pseudo-surround effect some music uses + void disable_surround( bool disable = true ) { smp.dsp.disable_surround( disable ); } + + // Enables gaussian, cubic or sinc interpolation + void interpolation_level( int level = 0 ) { smp.dsp.spc_dsp.interpolation_level( level ); } + + SuperFamicom::SMP const* get_smp() const; + SuperFamicom::SMP * get_smp(); + + blargg_err_t hash_( Hash_Function& ) const; + + static gme_type_t static_type() { return gme_sfm_type; } + +// Implementation +public: + Sfm_Emu(); + ~Sfm_Emu(); + +protected: + virtual blargg_err_t load_mem_( byte const [], int ); + virtual blargg_err_t track_info_( track_info_t*, int track ) const; + virtual blargg_err_t set_track_info_( const track_info_t*, int track ); + virtual blargg_err_t set_sample_rate_( int ); + virtual blargg_err_t start_track_( int ); + virtual blargg_err_t play_( int, sample_t [] ); + virtual blargg_err_t skip_( int ); + virtual void mute_voices_( int ); + virtual void set_tempo_( double ); + virtual blargg_err_t save_( gme_writer_t, void* ) const; + +private: + Spc_Emu_Resampler resampler; + Spc_Filter filter; + SuperFamicom::SMP smp; + + Bml_Parser metadata; + void create_updated_metadata(Bml_Parser &out) const; + + blargg_err_t play_and_filter( int count, sample_t out [] ); +}; + +inline SuperFamicom::SMP const* Sfm_Emu::get_smp() const { return &smp; } +inline SuperFamicom::SMP * Sfm_Emu::get_smp() { return &smp; } + +#endif // SPC_SFM_H diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Track_Filter.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Track_Filter.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Track_Filter.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Track_Filter.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,293 +1,293 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Track_Filter.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const fade_block_size = 512; -int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) -int const silence_threshold = 8; - -blargg_err_t Track_Filter::init( callbacks_t* c ) -{ - callbacks = c; - return buf.resize( buf_size ); -} - -void Track_Filter::clear_time_vars() -{ - emu_time = buf_remain; - out_time = 0; - silence_time = 0; - silence_count = 0; -} - -void Track_Filter::stop() -{ - emu_track_ended_ = true; - track_ended_ = true; - fade_start = indefinite_count; - fade_step = 1; - buf_remain = 0; - emu_error = NULL; - clear_time_vars(); -} - -Track_Filter::Track_Filter() : setup_() -{ - callbacks = NULL; - setup_.max_silence = indefinite_count; - silence_ignored_ = false; - stop(); -} - -Track_Filter::~Track_Filter() { } - -blargg_err_t Track_Filter::start_track() -{ - emu_error = NULL; - stop(); - - emu_track_ended_ = false; - track_ended_ = false; - - if ( !silence_ignored_ ) - { - // play until non-silence or end of track - while ( emu_time < setup_.max_initial ) - { - fill_buf(); - if ( buf_remain | emu_track_ended_ ) - break; - } - } - - clear_time_vars(); - return emu_error; -} - -void Track_Filter::end_track_if_error( blargg_err_t err ) -{ - if ( err ) - { - emu_error = err; - emu_track_ended_ = true; - } -} - -blargg_err_t Track_Filter::skip( int count ) -{ - emu_error = NULL; - out_time += count; - - // remove from silence and buf first - { - int n = min( count, silence_count ); - silence_count -= n; - count -= n; - - n = min( count, buf_remain ); - buf_remain -= n; - count -= n; - } - - if ( count && !emu_track_ended_ ) - { - emu_time += count; - silence_time = emu_time; // would otherwise be invalid - end_track_if_error( callbacks->skip_( count ) ); - } - - if ( !(silence_count | buf_remain) ) // caught up to emulator, so update track ended - track_ended_ |= emu_track_ended_; - - return emu_error; -} - -blargg_err_t Track_Filter::skip_( int count ) -{ - while ( count && !emu_track_ended_ ) - { - int n = buf_size; - if ( n > count ) - n = count; - count -= n; - RETURN_ERR( callbacks->play_( n, buf.begin() ) ); - } - return blargg_ok; -} - -// Fading - -void Track_Filter::set_fade( int start, int length ) -{ - fade_start = start; - fade_step = length / (fade_block_size * fade_shift); - if ( fade_step < 1 ) - fade_step = 1; -} - -bool Track_Filter::is_fading() const -{ - return out_time >= fade_start && fade_start != indefinite_count; -} - -// unit / pow( 2.0, (double) x / step ) -static int int_log( int x, int step, int unit ) -{ - int shift = x / step; - int fraction = (x - shift * step) * unit / step; - return ((unit - fraction) + (fraction >> 1)) >> shift; -} - -void Track_Filter::handle_fade( sample_t out [], int out_count ) -{ - for ( int i = 0; i < out_count; i += fade_block_size ) - { - int const shift = 14; - int const unit = 1 << shift; - int gain = int_log( (out_time + i - fade_start) / fade_block_size, - fade_step, unit ); - if ( gain < (unit >> fade_shift) ) - track_ended_ = emu_track_ended_ = true; - - sample_t* io = &out [i]; - for ( int count = min( fade_block_size, out_count - i ); count; --count ) - { - *io = sample_t ((*io * gain) >> shift); - ++io; - } - } -} - -// Silence detection - -void Track_Filter::emu_play( sample_t out [], int count ) -{ - emu_time += count; - if ( !emu_track_ended_ ) - end_track_if_error( callbacks->play_( count, out ) ); - else - memset( out, 0, count * sizeof *out ); -} - -// number of consecutive silent samples at end -static int count_silence( Track_Filter::sample_t begin [], int size ) -{ - Track_Filter::sample_t first = *begin; - *begin = silence_threshold * 2; // sentinel - Track_Filter::sample_t* p = begin + size; - while ( (unsigned) (*--p + silence_threshold) <= (unsigned) silence_threshold * 2 ) { } - *begin = first; - return size - (p - begin); -} - -// fill internal buffer and check it for silence -void Track_Filter::fill_buf() -{ - assert( !buf_remain ); - if ( !emu_track_ended_ ) - { - emu_play( buf.begin(), buf_size ); - int silence = count_silence( buf.begin(), buf_size ); - if ( silence < buf_size ) - { - silence_time = emu_time - silence; - buf_remain = buf_size; - return; - } - } - silence_count += buf_size; -} - -blargg_err_t Track_Filter::play( int out_count, sample_t out [] ) -{ - emu_error = NULL; - if ( track_ended_ ) - { - memset( out, 0, out_count * sizeof *out ); - } - else - { - assert( emu_time >= out_time ); - - // prints nifty graph of how far ahead we are when searching for silence - //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / 44100), "*" ); - - // use any remaining silence samples - int pos = 0; - if ( silence_count ) - { - if ( !silence_ignored_ ) - { - // during a run of silence, run emulator at >=2x speed so it gets ahead - int ahead_time = setup_.lookahead * (out_time + out_count - silence_time) + - silence_time; - while ( emu_time < ahead_time && !(buf_remain | emu_track_ended_) ) - fill_buf(); - - // end track if sufficient silence has been found - if ( emu_time - silence_time > setup_.max_silence ) - { - track_ended_ = emu_track_ended_ = true; - silence_count = out_count; - buf_remain = 0; - } - } - - // fill from remaining silence - pos = min( silence_count, out_count ); - memset( out, 0, pos * sizeof *out ); - silence_count -= pos; - } - - // use any remaining samples from buffer - if ( buf_remain ) - { - int n = min( buf_remain, (int) (out_count - pos) ); - memcpy( out + pos, buf.begin() + (buf_size - buf_remain), n * sizeof *out ); - buf_remain -= n; - pos += n; - } - - // generate remaining samples normally - int remain = out_count - pos; - if ( remain ) - { - emu_play( out + pos, remain ); - track_ended_ |= emu_track_ended_; - - if ( silence_ignored_ && !is_fading() ) - { - // if left unupdated, ahead_time could become too large - silence_time = emu_time; - } - else - { - // check end for a new run of silence - int silence = count_silence( out + pos, remain ); - if ( silence < remain ) - silence_time = emu_time - silence; - - if ( emu_time - silence_time >= buf_size ) - fill_buf(); // cause silence detection on next play() - } - } - - if ( is_fading() ) - handle_fade( out, out_count ); - } - out_time += out_count; - return emu_error; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Track_Filter.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const fade_block_size = 512; +int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) +int const silence_threshold = 8; + +blargg_err_t Track_Filter::init( callbacks_t* c ) +{ + callbacks = c; + return buf.resize( buf_size ); +} + +void Track_Filter::clear_time_vars() +{ + emu_time = buf_remain; + out_time = 0; + silence_time = 0; + silence_count = 0; +} + +void Track_Filter::stop() +{ + emu_track_ended_ = true; + track_ended_ = true; + fade_start = indefinite_count; + fade_step = 1; + buf_remain = 0; + emu_error = NULL; + clear_time_vars(); +} + +Track_Filter::Track_Filter() : setup_() +{ + callbacks = NULL; + setup_.max_silence = indefinite_count; + silence_ignored_ = false; + stop(); +} + +Track_Filter::~Track_Filter() { } + +blargg_err_t Track_Filter::start_track() +{ + emu_error = NULL; + stop(); + + emu_track_ended_ = false; + track_ended_ = false; + + if ( !silence_ignored_ ) + { + // play until non-silence or end of track + while ( emu_time < setup_.max_initial ) + { + fill_buf(); + if ( buf_remain | emu_track_ended_ ) + break; + } + } + + clear_time_vars(); + return emu_error; +} + +void Track_Filter::end_track_if_error( blargg_err_t err ) +{ + if ( err ) + { + emu_error = err; + emu_track_ended_ = true; + } +} + +blargg_err_t Track_Filter::skip( int count ) +{ + emu_error = NULL; + out_time += count; + + // remove from silence and buf first + { + int n = min( count, silence_count ); + silence_count -= n; + count -= n; + + n = min( count, buf_remain ); + buf_remain -= n; + count -= n; + } + + if ( count && !emu_track_ended_ ) + { + emu_time += count; + silence_time = emu_time; // would otherwise be invalid + end_track_if_error( callbacks->skip_( count ) ); + } + + if ( !(silence_count | buf_remain) ) // caught up to emulator, so update track ended + track_ended_ |= emu_track_ended_; + + return emu_error; +} + +blargg_err_t Track_Filter::skip_( int count ) +{ + while ( count && !emu_track_ended_ ) + { + int n = buf_size; + if ( n > count ) + n = count; + count -= n; + RETURN_ERR( callbacks->play_( n, buf.begin() ) ); + } + return blargg_ok; +} + +// Fading + +void Track_Filter::set_fade( int start, int length ) +{ + fade_start = start; + fade_step = length / (fade_block_size * fade_shift); + if ( fade_step < 1 ) + fade_step = 1; +} + +bool Track_Filter::is_fading() const +{ + return out_time >= fade_start && fade_start != indefinite_count; +} + +// unit / pow( 2.0, (double) x / step ) +static int int_log( int x, int step, int unit ) +{ + int shift = x / step; + int fraction = (x - shift * step) * unit / step; + return ((unit - fraction) + (fraction >> 1)) >> shift; +} + +void Track_Filter::handle_fade( sample_t out [], int out_count ) +{ + for ( int i = 0; i < out_count; i += fade_block_size ) + { + int const shift = 14; + int const unit = 1 << shift; + int gain = int_log( (out_time + i - fade_start) / fade_block_size, + fade_step, unit ); + if ( gain < (unit >> fade_shift) ) + track_ended_ = emu_track_ended_ = true; + + sample_t* io = &out [i]; + for ( int count = min( fade_block_size, out_count - i ); count; --count ) + { + *io = sample_t ((*io * gain) >> shift); + ++io; + } + } +} + +// Silence detection + +void Track_Filter::emu_play( sample_t out [], int count ) +{ + emu_time += count; + if ( !emu_track_ended_ ) + end_track_if_error( callbacks->play_( count, out ) ); + else + memset( out, 0, count * sizeof *out ); +} + +// number of consecutive silent samples at end +static int count_silence( Track_Filter::sample_t begin [], int size ) +{ + Track_Filter::sample_t first = *begin; + *begin = silence_threshold * 2; // sentinel + Track_Filter::sample_t* p = begin + size; + while ( (unsigned) (*--p + silence_threshold) <= (unsigned) silence_threshold * 2 ) { } + *begin = first; + return size - (p - begin); +} + +// fill internal buffer and check it for silence +void Track_Filter::fill_buf() +{ + assert( !buf_remain ); + if ( !emu_track_ended_ ) + { + emu_play( buf.begin(), buf_size ); + int silence = count_silence( buf.begin(), buf_size ); + if ( silence < buf_size ) + { + silence_time = emu_time - silence; + buf_remain = buf_size; + return; + } + } + silence_count += buf_size; +} + +blargg_err_t Track_Filter::play( int out_count, sample_t out [] ) +{ + emu_error = NULL; + if ( track_ended_ ) + { + memset( out, 0, out_count * sizeof *out ); + } + else + { + assert( emu_time >= out_time ); + + // prints nifty graph of how far ahead we are when searching for silence + //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / 44100), "*" ); + + // use any remaining silence samples + int pos = 0; + if ( silence_count ) + { + if ( !silence_ignored_ ) + { + // during a run of silence, run emulator at >=2x speed so it gets ahead + int ahead_time = setup_.lookahead * (out_time + out_count - silence_time) + + silence_time; + while ( emu_time < ahead_time && !(buf_remain | emu_track_ended_) ) + fill_buf(); + + // end track if sufficient silence has been found + if ( emu_time - silence_time > setup_.max_silence ) + { + track_ended_ = emu_track_ended_ = true; + silence_count = out_count; + buf_remain = 0; + } + } + + // fill from remaining silence + pos = min( silence_count, out_count ); + memset( out, 0, pos * sizeof *out ); + silence_count -= pos; + } + + // use any remaining samples from buffer + if ( buf_remain ) + { + int n = min( buf_remain, (int) (out_count - pos) ); + memcpy( out + pos, buf.begin() + (buf_size - buf_remain), n * sizeof *out ); + buf_remain -= n; + pos += n; + } + + // generate remaining samples normally + int remain = out_count - pos; + if ( remain ) + { + emu_play( out + pos, remain ); + track_ended_ |= emu_track_ended_; + + if ( silence_ignored_ && !is_fading() ) + { + // if left unupdated, ahead_time could become too large + silence_time = emu_time; + } + else + { + // check end for a new run of silence + int silence = count_silence( out + pos, remain ); + if ( silence < remain ) + silence_time = emu_time - silence; + + if ( emu_time - silence_time >= buf_size ) + fill_buf(); // cause silence detection on next play() + } + } + + if ( is_fading() ) + handle_fade( out, out_count ); + } + out_time += out_count; + return emu_error; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Track_Filter.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Track_Filter.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Track_Filter.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Track_Filter.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,105 +1,105 @@ -// Removes silence from beginning of track, fades end of track. Also looks ahead -// for excessive silence, and if found, ends track. - -// Game_Music_Emu $vers -#ifndef TRACK_FILTER_H -#define TRACK_FILTER_H - -#include "blargg_common.h" - -class Track_Filter { -public: - typedef int sample_count_t; - typedef short sample_t; - - enum { indefinite_count = INT_MAX/2 + 1 }; - - struct callbacks_t { - // Samples may be stereo or mono - virtual blargg_err_t play_( int count, sample_t* out ) BLARGG_PURE( { return blargg_ok; } ) - virtual blargg_err_t skip_( int count ) BLARGG_PURE( { return blargg_ok; } ) - virtual ~callbacks_t() { } // avoids silly "non-virtual dtor" warning - }; - - // Initializes filter. Must be done once before using object. - blargg_err_t init( callbacks_t* ); - - struct setup_t { - sample_count_t max_initial; // maximum silence to strip from beginning of track - sample_count_t max_silence; // maximum silence in middle of track without it ending - int lookahead; // internal speed when looking ahead for silence (2=200% etc.) - }; - - // Gets/sets setup - setup_t const& setup() const { return setup_; } - void setup( setup_t const& s ) { setup_ = s; } - - // Disables automatic end-of-track detection and skipping of silence at beginning - void ignore_silence( bool disable = true ) { silence_ignored_ = disable; } - - // Clears state and skips initial silence in track - blargg_err_t start_track(); - - // Sets time that fade starts, and how long until track ends. - void set_fade( sample_count_t start, sample_count_t length ); - - // Generates n samples into buf - blargg_err_t play( int n, sample_t buf [] ); - - // Skips n samples - blargg_err_t skip( int n ); - - // Number of samples played/skipped since start_track() - int sample_count() const { return out_time; } - - // True if track ended. Causes are end of source samples, end of fade, - // or excessive silence. - bool track_ended() const { return track_ended_; } - - // Clears state - void stop(); - -// For use by callbacks - - // Sets internal "track ended" flag and stops generation of further source samples - void set_track_ended() { emu_track_ended_ = true; } - - // For use by skip_() callback - blargg_err_t skip_( int count ); - -// Implementation -public: - Track_Filter(); - ~Track_Filter(); - -private: - callbacks_t* callbacks; - setup_t setup_; - const char* emu_error; - bool silence_ignored_; - - // Timing - int out_time; // number of samples played since start of track - int emu_time; // number of samples emulator has generated since start of track - int emu_track_ended_; // emulator has reached end of track - volatile int track_ended_; - void clear_time_vars(); - void end_track_if_error( blargg_err_t ); - - // Fading - int fade_start; - int fade_step; - bool is_fading() const; - void handle_fade( sample_t out [], int count ); - - // Silence detection - int silence_time; // absolute number of samples where most recent silence began - int silence_count; // number of samples of silence to play before using buf - int buf_remain; // number of samples left in silence buffer - enum { buf_size = 2048 }; - blargg_vector buf; - void fill_buf(); - void emu_play( sample_t out [], int count ); -}; - -#endif +// Removes silence from beginning of track, fades end of track. Also looks ahead +// for excessive silence, and if found, ends track. + +// Game_Music_Emu $vers +#ifndef TRACK_FILTER_H +#define TRACK_FILTER_H + +#include "blargg_common.h" + +class Track_Filter { +public: + typedef int sample_count_t; + typedef short sample_t; + + enum { indefinite_count = INT_MAX/2 + 1 }; + + struct callbacks_t { + // Samples may be stereo or mono + virtual blargg_err_t play_( int count, sample_t* out ) BLARGG_PURE( { return blargg_ok; } ) + virtual blargg_err_t skip_( int count ) BLARGG_PURE( { return blargg_ok; } ) + virtual ~callbacks_t() { } // avoids silly "non-virtual dtor" warning + }; + + // Initializes filter. Must be done once before using object. + blargg_err_t init( callbacks_t* ); + + struct setup_t { + sample_count_t max_initial; // maximum silence to strip from beginning of track + sample_count_t max_silence; // maximum silence in middle of track without it ending + int lookahead; // internal speed when looking ahead for silence (2=200% etc.) + }; + + // Gets/sets setup + setup_t const& setup() const { return setup_; } + void setup( setup_t const& s ) { setup_ = s; } + + // Disables automatic end-of-track detection and skipping of silence at beginning + void ignore_silence( bool disable = true ) { silence_ignored_ = disable; } + + // Clears state and skips initial silence in track + blargg_err_t start_track(); + + // Sets time that fade starts, and how long until track ends. + void set_fade( sample_count_t start, sample_count_t length ); + + // Generates n samples into buf + blargg_err_t play( int n, sample_t buf [] ); + + // Skips n samples + blargg_err_t skip( int n ); + + // Number of samples played/skipped since start_track() + int sample_count() const { return out_time; } + + // True if track ended. Causes are end of source samples, end of fade, + // or excessive silence. + bool track_ended() const { return track_ended_; } + + // Clears state + void stop(); + +// For use by callbacks + + // Sets internal "track ended" flag and stops generation of further source samples + void set_track_ended() { emu_track_ended_ = true; } + + // For use by skip_() callback + blargg_err_t skip_( int count ); + +// Implementation +public: + Track_Filter(); + ~Track_Filter(); + +private: + callbacks_t* callbacks; + setup_t setup_; + const char* emu_error; + bool silence_ignored_; + + // Timing + int out_time; // number of samples played since start of track + int emu_time; // number of samples emulator has generated since start of track + int emu_track_ended_; // emulator has reached end of track + volatile int track_ended_; + void clear_time_vars(); + void end_track_if_error( blargg_err_t ); + + // Fading + int fade_start; + int fade_step; + bool is_fading() const; + void handle_fade( sample_t out [], int count ); + + // Silence detection + int silence_time; // absolute number of samples where most recent silence began + int silence_count; // number of samples of silence to play before using buf + int buf_remain; // number of samples left in silence buffer + enum { buf_size = 2048 }; + blargg_vector buf; + void fill_buf(); + void emu_play( sample_t out [], int count ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Vgm_Core.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Vgm_Core.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Vgm_Core.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Vgm_Core.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,2307 +1,2304 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Vgm_Core.h" - -#include "dac_control.h" - -#include "blargg_endian.h" -#include - -// Needed for OKIM6295 system detection -#include "Vgm_Emu.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -int const stereo = 2; -int const fm_time_bits = 12; -int const blip_time_bits = 12; - -enum { - cmd_gg_stereo = 0x4F, - cmd_gg_stereo_2 = 0x3F, - cmd_psg = 0x50, - cmd_psg_2 = 0x30, - cmd_ym2413 = 0x51, - cmd_ym2413_2 = 0xA1, - cmd_ym2612_port0 = 0x52, - cmd_ym2612_2_port0 = 0xA2, - cmd_ym2612_port1 = 0x53, - cmd_ym2612_2_port1 = 0xA3, - cmd_ym2151 = 0x54, - cmd_ym2151_2 = 0xA4, - cmd_ym2203 = 0x55, - cmd_ym2203_2 = 0xA5, - cmd_ym2608_port0 = 0x56, - cmd_ym2608_2_port0 = 0xA6, - cmd_ym2608_port1 = 0x57, - cmd_ym2608_2_port1 = 0xA7, - cmd_ym2610_port0 = 0x58, - cmd_ym2610_2_port0 = 0xA8, - cmd_ym2610_port1 = 0x59, - cmd_ym2610_2_port1 = 0xA9, - cmd_ym3812 = 0x5A, - cmd_ym3812_2 = 0xAA, - cmd_ymz280b = 0x5D, - cmd_ymf262_port0 = 0x5E, - cmd_ymf262_2_port0 = 0xAE, - cmd_ymf262_port1 = 0x5F, - cmd_ymf262_2_port1 = 0xAF, - cmd_delay = 0x61, - cmd_delay_735 = 0x62, - cmd_delay_882 = 0x63, - cmd_byte_delay = 0x64, - cmd_end = 0x66, - cmd_data_block = 0x67, - cmd_ram_block = 0x68, - cmd_short_delay = 0x70, - cmd_pcm_delay = 0x80, - cmd_dacctl_setup = 0x90, - cmd_dacctl_data = 0x91, - cmd_dacctl_freq = 0x92, - cmd_dacctl_play = 0x93, - cmd_dacctl_stop = 0x94, - cmd_dacctl_playblock= 0x95, - cmd_ay8910 = 0xA0, - cmd_rf5c68 = 0xB0, - cmd_rf5c164 = 0xB1, - cmd_pwm = 0xB2, - cmd_gbdmg_write = 0xB3, - cmd_okim6258_write = 0xB7, - cmd_okim6295_write = 0xB8, - cmd_huc6280_write = 0xB9, - cmd_k053260_write = 0xBA, - cmd_segapcm_write = 0xC0, - cmd_rf5c68_mem = 0xC1, - cmd_rf5c164_mem = 0xC2, - cmd_qsound_write = 0xC4, - cmd_k051649_write = 0xD2, - cmd_k054539_write = 0xD3, - cmd_c140 = 0xD4, - cmd_pcm_seek = 0xE0, - - rf5c68_ram_block = 0x01, - rf5c164_ram_block = 0x02, - - pcm_block_type = 0x00, - pcm_aux_block_type = 0x40, - rom_block_type = 0x80, - ram_block_type = 0xC0, - - rom_segapcm = 0x80, - rom_ym2608_deltat = 0x81, - rom_ym2610_adpcm = 0x82, - rom_ym2610_deltat = 0x83, - rom_ymz280b = 0x86, - rom_okim6295 = 0x8B, - rom_k054539 = 0x8C, - rom_c140 = 0x8D, - rom_k053260 = 0x8E, - rom_qsound = 0x8F, - - ram_rf5c68 = 0xC0, - ram_rf5c164 = 0xC1, - ram_nesapu = 0xC2, - - ym2612_dac_port = 0x2A, - ym2612_dac_pan_port = 0xB6 -}; - -inline int command_len( int command ) -{ - static byte const lens [0x10] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 1,1,1,2,2,3,1,1,1,1,3,3,4,4,5,5 - }; - int len = lens [command >> 4]; - check( len != 1 ); - return len; -} - -int Vgm_Core::run_ym2151( int chip, int time ) -{ - return ym2151[!!chip].run_until( time ); -} - -int Vgm_Core::run_ym2203( int chip, int time ) -{ - return ym2203[!!chip].run_until( time ); -} - -int Vgm_Core::run_ym2413( int chip, int time ) -{ - return ym2413[!!chip].run_until( time ); -} - -int Vgm_Core::run_ym2612( int chip, int time ) -{ - return ym2612[!!chip].run_until( time ); -} - -int Vgm_Core::run_ym2610( int chip, int time ) -{ - return ym2610[!!chip].run_until( time ); -} - -int Vgm_Core::run_ym2608( int chip, int time ) -{ - return ym2608[!!chip].run_until( time ); -} - -int Vgm_Core::run_ym3812( int chip, int time ) -{ - return ym3812[!!chip].run_until( time ); -} - -int Vgm_Core::run_ymf262( int chip, int time ) -{ - return ymf262[!!chip].run_until( time ); -} - -int Vgm_Core::run_ymz280b( int time ) -{ - return ymz280b.run_until( time ); -} - -int Vgm_Core::run_c140( int time ) -{ - return c140.run_until( time ); -} - -int Vgm_Core::run_segapcm( int time ) -{ - return segapcm.run_until( time ); -} - -int Vgm_Core::run_rf5c68( int time ) -{ - return rf5c68.run_until( time ); -} - -int Vgm_Core::run_rf5c164( int time ) -{ - return rf5c164.run_until( time ); -} - -int Vgm_Core::run_pwm( int time ) -{ - return pwm.run_until( time ); -} - -int Vgm_Core::run_okim6258( int chip, int time ) -{ - chip = !!chip; - if ( okim6258[chip].enabled() ) - { - int current_clock = okim6258[chip].get_clock(); - if ( okim6258_hz[chip] != current_clock ) - { - okim6258_hz[chip] = current_clock; - okim6258[chip].setup( (double)okim6258_hz[chip] / vgm_rate, 0.85, 1.0 ); - } - } - return okim6258[chip].run_until( time ); -} - -int Vgm_Core::run_okim6295( int chip, int time ) -{ - return okim6295[!!chip].run_until( time ); -} - -int Vgm_Core::run_k051649( int time ) -{ - return k051649.run_until( time ); -} - -int Vgm_Core::run_k053260( int time ) -{ - return k053260.run_until( time ); -} - -int Vgm_Core::run_k054539( int time ) -{ - return k054539.run_until( time ); -} - -int Vgm_Core::run_qsound( int chip, int time ) -{ - return qsound[!!chip].run_until( time ); -} - -/* Recursive fun starts here! */ -int Vgm_Core::run_dac_control( int time ) -{ - if (dac_control_recursion) return 1; - - ++dac_control_recursion; - for ( unsigned i = 0; i < DacCtrlUsed; i++ ) - { - int time_start = DacCtrlTime[DacCtrlMap[i]]; - if ( time > time_start ) - { - DacCtrlTime[DacCtrlMap[i]] = time; - daccontrol_update( dac_control [i], time_start, time - time_start ); - } - } - --dac_control_recursion; - - return 1; -} - -Vgm_Core::Vgm_Core() -{ - blip_buf[0] = stereo_buf[0].center(); - blip_buf[1] = blip_buf[0]; - has_looped = false; - DacCtrlUsed = 0; - dac_control = NULL; - memset( PCMBank, 0, sizeof( PCMBank ) ); - memset( &PCMTbl, 0, sizeof( PCMTbl ) ); - memset( DacCtrl, 0, sizeof( DacCtrl ) ); - memset( DacCtrlTime, 0, sizeof( DacCtrlTime ) ); -} - -Vgm_Core::~Vgm_Core() -{ - for (unsigned i = 0; i < DacCtrlUsed; i++) device_stop_daccontrol( dac_control [i] ); - if ( dac_control ) free( dac_control ); - for (unsigned i = 0; i < PCM_BANK_COUNT; i++) - { - if ( PCMBank [i].Bank ) free( PCMBank [i].Bank ); - if ( PCMBank [i].Data ) free( PCMBank [i].Data ); - } - if ( PCMTbl.Entries ) free( PCMTbl.Entries ); -} - -typedef unsigned int FUINT8; -typedef unsigned int FUINT16; - -void Vgm_Core::ReadPCMTable(unsigned DataSize, const byte* Data) -{ - byte ValSize; - unsigned TblSize; - - PCMTbl.ComprType = Data[0x00]; - PCMTbl.CmpSubType = Data[0x01]; - PCMTbl.BitDec = Data[0x02]; - PCMTbl.BitCmp = Data[0x03]; - PCMTbl.EntryCount = get_le16( Data + 0x04 ); - - ValSize = (PCMTbl.BitDec + 7) / 8; - TblSize = PCMTbl.EntryCount * ValSize; - - PCMTbl.Entries = realloc(PCMTbl.Entries, TblSize); - memcpy(PCMTbl.Entries, Data + 0x06, TblSize); -} - -bool Vgm_Core::DecompressDataBlk(VGM_PCM_DATA* Bank, unsigned DataSize, const byte* Data) -{ - UINT8 ComprType; - UINT8 BitDec; - FUINT8 BitCmp; - UINT8 CmpSubType; - UINT16 AddVal; - const UINT8* InPos; - const UINT8* InDataEnd; - UINT8* OutPos; - const UINT8* OutDataEnd; - FUINT16 InVal; - FUINT16 OutVal = 0; - FUINT8 ValSize; - FUINT8 InShift; - FUINT8 OutShift; - UINT8* Ent1B = nullptr; - UINT16* Ent2B = nullptr; - - // ReadBits Variables - FUINT8 BitsToRead; - FUINT8 BitReadVal; - FUINT8 InValB; - FUINT8 BitMask; - FUINT8 OutBit; - - // Variables for DPCM - UINT16 OutMask; - - ComprType = Data[0x00]; - Bank->DataSize = get_le32( Data + 0x01 ); - - switch(ComprType) - { - case 0x00: // n-Bit compression - BitDec = Data[0x05]; - BitCmp = Data[0x06]; - CmpSubType = Data[0x07]; - AddVal = get_le16( Data + 0x08 ); - - if (CmpSubType == 0x02) - { - Ent1B = (UINT8*)PCMTbl.Entries; - Ent2B = (UINT16*)PCMTbl.Entries; - if (! PCMTbl.EntryCount) - { - Bank->DataSize = 0x00; - return false; - } - else if (BitDec != PCMTbl.BitDec || BitCmp != PCMTbl.BitCmp) - { - Bank->DataSize = 0x00; - return false; - } - } - - ValSize = (BitDec + 7) / 8; - InPos = Data + 0x0A; - InDataEnd = Data + DataSize; - InShift = 0; - OutShift = BitDec - BitCmp; - OutDataEnd = Bank->Data + Bank->DataSize; - - for (OutPos = Bank->Data; OutPos < OutDataEnd && InPos < InDataEnd; OutPos += ValSize) - { - //InVal = ReadBits(Data, InPos, &InShift, BitCmp); - // inlined - is 30% faster - OutBit = 0x00; - InVal = 0x0000; - BitsToRead = BitCmp; - while(BitsToRead) - { - BitReadVal = (BitsToRead >= 8) ? 8 : BitsToRead; - BitsToRead -= BitReadVal; - BitMask = (1 << BitReadVal) - 1; - - InShift += BitReadVal; - InValB = (*InPos << InShift >> 8) & BitMask; - if (InShift >= 8) - { - InShift -= 8; - InPos ++; - if (InShift) - InValB |= (*InPos << InShift >> 8) & BitMask; - } - - InVal |= InValB << OutBit; - OutBit += BitReadVal; - } - - switch(CmpSubType) - { - case 0x00: // Copy - OutVal = InVal + AddVal; - break; - case 0x01: // Shift Left - OutVal = (InVal << OutShift) + AddVal; - break; - case 0x02: // Table - switch(ValSize) - { - case 0x01: - OutVal = Ent1B[InVal]; - break; - case 0x02: - OutVal = Ent2B[InVal]; - break; - } - break; - } - - //memcpy(OutPos, &OutVal, ValSize); - if (ValSize == 0x01) - *((UINT8*)OutPos) = (UINT8)OutVal; - else //if (ValSize == 0x02) - *((UINT16*)OutPos) = (UINT16)OutVal; - } - break; - case 0x01: // Delta-PCM - BitDec = Data[0x05]; - BitCmp = Data[0x06]; - OutVal = get_le16( Data + 0x08 ); - - Ent1B = (UINT8*)PCMTbl.Entries; - Ent2B = (UINT16*)PCMTbl.Entries; - if (! PCMTbl.EntryCount) - { - Bank->DataSize = 0x00; - return false; - } - else if (BitDec != PCMTbl.BitDec || BitCmp != PCMTbl.BitCmp) - { - Bank->DataSize = 0x00; - return false; - } - - ValSize = (BitDec + 7) / 8; - OutMask = (1 << BitDec) - 1; - InPos = Data + 0x0A; - InDataEnd = Data + DataSize; - InShift = 0; - OutShift = BitDec - BitCmp; - OutDataEnd = Bank->Data + Bank->DataSize; - AddVal = 0x0000; - - for (OutPos = Bank->Data; OutPos < OutDataEnd && InPos < InDataEnd; OutPos += ValSize) - { - //InVal = ReadBits(Data, InPos, &InShift, BitCmp); - // inlined - is 30% faster - OutBit = 0x00; - InVal = 0x0000; - BitsToRead = BitCmp; - while(BitsToRead) - { - BitReadVal = (BitsToRead >= 8) ? 8 : BitsToRead; - BitsToRead -= BitReadVal; - BitMask = (1 << BitReadVal) - 1; - - InShift += BitReadVal; - InValB = (*InPos << InShift >> 8) & BitMask; - if (InShift >= 8) - { - InShift -= 8; - InPos ++; - if (InShift) - InValB |= (*InPos << InShift >> 8) & BitMask; - } - - InVal |= InValB << OutBit; - OutBit += BitReadVal; - } - - switch(ValSize) - { - case 0x01: - AddVal = Ent1B[InVal]; - OutVal += AddVal; - OutVal &= OutMask; - *((UINT8*)OutPos) = (UINT8)OutVal; - break; - case 0x02: - AddVal = Ent2B[InVal]; - OutVal += AddVal; - OutVal &= OutMask; - *((UINT16*)OutPos) = (UINT16)OutVal; - break; - } - } - break; - default: - return false; - } - - return true; -} - -void Vgm_Core::AddPCMData(byte Type, unsigned DataSize, const byte* Data) -{ - unsigned CurBnk; - VGM_PCM_BANK* TempPCM; - VGM_PCM_DATA* TempBnk; - unsigned BankSize; - bool RetVal; - - - if ((Type & 0x3F) >= PCM_BANK_COUNT || has_looped) - return; - - if (Type == 0x7F) - { - ReadPCMTable( DataSize, Data ); - return; - } - - TempPCM = &PCMBank[Type & 0x3F]; - CurBnk = TempPCM->BankCount; - TempPCM->BankCount ++; - TempPCM->BnkPos ++; - if (TempPCM->BnkPos < TempPCM->BankCount) - return; // Speed hack (for restarting playback) - TempPCM->Bank = (VGM_PCM_DATA*)realloc(TempPCM->Bank, - sizeof(VGM_PCM_DATA) * TempPCM->BankCount); - - if (! (Type & 0x40)) - BankSize = DataSize; - else - BankSize = get_le32( Data + 1 ); - TempPCM->Data = ( byte * ) realloc(TempPCM->Data, TempPCM->DataSize + BankSize); - TempBnk = &TempPCM->Bank[CurBnk]; - TempBnk->DataStart = TempPCM->DataSize; - if (! (Type & 0x40)) - { - TempBnk->DataSize = DataSize; - TempBnk->Data = TempPCM->Data + TempBnk->DataStart; - memcpy(TempBnk->Data, Data, DataSize); - } - else - { - TempBnk->Data = TempPCM->Data + TempBnk->DataStart; - RetVal = DecompressDataBlk(TempBnk, DataSize, Data); - if (! RetVal) - { - TempBnk->Data = NULL; - TempBnk->DataSize = 0x00; - return; - } - } - TempPCM->DataSize += BankSize; -} - -const byte* Vgm_Core::GetPointerFromPCMBank(byte Type, unsigned DataPos) -{ - if (Type >= PCM_BANK_COUNT) - return NULL; - - if (DataPos >= PCMBank[Type].DataSize) - return NULL; - - return &PCMBank[Type].Data[DataPos]; -} - -void Vgm_Core::dac_control_grow(byte chip_id) -{ - for ( unsigned i = 0; i < DacCtrlUsed; i++ ) - { - if ( DacCtrlUsg [i] == chip_id ) - { - device_reset_daccontrol( dac_control [i] ); - return; - } - } - unsigned chip_mapped = DacCtrlUsed; - DacCtrlUsg [DacCtrlUsed++] = chip_id; - DacCtrlMap [chip_id] = chip_mapped; - dac_control = (void**) realloc( dac_control, DacCtrlUsed * sizeof(void*) ); - dac_control [chip_mapped] = device_start_daccontrol( vgm_rate, this ); - device_reset_daccontrol( dac_control [chip_mapped] ); -} - -extern "C" void chip_reg_write(void * context, UINT32 Sample, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset, UINT8 Data) -{ - Vgm_Core * core = (Vgm_Core *) context; - core->chip_reg_write(Sample, ChipType, ChipID, Port, Offset, Data); -} - -void Vgm_Core::chip_reg_write(unsigned Sample, byte ChipType, byte ChipID, byte Port, byte Offset, byte Data) -{ - run_dac_control( Sample ); /* Let's get recursive! */ - ChipID = !!ChipID; - switch (ChipType) - { - case 0x02: - switch (Port) - { - case 0: - if ( Offset == ym2612_dac_port ) - { - write_pcm( Sample, ChipID, Data ); - } - else if ( run_ym2612( ChipID, to_fm_time( Sample ) ) ) - { - if ( Offset == 0x2B ) - { - dac_disabled[ChipID] = (Data >> 7 & 1) - 1; - dac_amp[ChipID] |= dac_disabled[ChipID]; - } - ym2612[ChipID].write0( Offset, Data ); - } - break; - - case 1: - if ( run_ym2612( ChipID, to_fm_time( Sample ) ) ) - { - if ( Offset == ym2612_dac_pan_port ) - { - Blip_Buffer * blip_buf = NULL; - switch ( Data >> 6 ) - { - case 0: blip_buf = NULL; break; - case 1: blip_buf = stereo_buf[0].right(); break; - case 2: blip_buf = stereo_buf[0].left(); break; - case 3: blip_buf = stereo_buf[0].center(); break; - } - /*if ( this->blip_buf != blip_buf ) - { - blip_time_t blip_time = to_psg_time( vgm_time ); - if ( this->blip_buf ) pcm.offset_inline( blip_time, -dac_amp, this->blip_buf ); - if ( blip_buf ) pcm.offset_inline( blip_time, dac_amp, blip_buf ); - }*/ - this->blip_buf[ChipID] = blip_buf; - } - ym2612[ChipID].write1( Offset, Data ); - } - break; - } - break; - - case 0x11: - if ( run_pwm( to_fm_time( Sample ) ) ) - pwm.write( Port, ( ( Offset ) << 8 ) + Data ); - break; - - case 0x00: - psg[ChipID].write_data( to_psg_time( Sample ), Data ); - break; - - case 0x01: - if ( run_ym2413( ChipID, to_fm_time( Sample ) ) ) - ym2413[ChipID].write( Offset, Data ); - break; - - case 0x03: - if ( run_ym2151( ChipID, to_fm_time( Sample ) ) ) - ym2151[ChipID].write( Offset, Data ); - break; - - case 0x06: - if ( run_ym2203( ChipID, to_fm_time( Sample ) ) ) - ym2203[ChipID].write( Offset, Data ); - break; - - case 0x07: - if ( run_ym2608( ChipID, to_fm_time( Sample ) ) ) - { - switch (Port) - { - case 0: ym2608[ChipID].write0( Offset, Data ); break; - case 1: ym2608[ChipID].write1( Offset, Data ); break; - } - } - break; - - case 0x08: - if ( run_ym2610( ChipID, to_fm_time( Sample ) ) ) - { - switch (Port) - { - case 0: ym2610[ChipID].write0( Offset, Data ); break; - case 1: ym2610[ChipID].write1( Offset, Data ); break; - } - } - break; - - case 0x09: - if ( run_ym3812( ChipID, to_fm_time( Sample ) ) ) - ym3812[ChipID].write( Offset, Data ); - break; - - case 0x0C: - if ( run_ymf262( ChipID, to_fm_time( Sample ) ) ) - { - switch (Port) - { - case 0: ymf262[ChipID].write0( Offset, Data ); break; - case 1: ymf262[ChipID].write1( Offset, Data ); break; - } - } - break; - - case 0x0F: - if ( run_ymz280b( to_fm_time( Sample ) ) ) - ymz280b.write( Offset, Data ); - break; - - case 0x12: - ay[ChipID].write_addr( Offset ); - ay[ChipID].write_data( to_ay_time( Sample ), Data ); - break; - - case 0x13: - gbdmg[ChipID].write_register( to_gbdmg_time( Sample ), 0xFF10 + Offset, Data ); - break; - - case 0x17: - if ( run_okim6258( ChipID, to_fm_time( Sample ) ) ) - okim6258[ChipID].write( Offset, Data ); - break; - - case 0x18: - if ( run_okim6295( ChipID, to_fm_time( Sample ) ) ) - okim6295[ChipID].write( Offset, Data ); - break; - - case 0x19: - if ( run_k051649( to_fm_time( Sample ) ) ) - k051649.write( Port, Offset, Data ); - break; - - case 0x1A: - if ( run_k054539( to_fm_time( Sample ) ) ) - k054539.write( ( Port << 8 ) | Offset, Data ); - break; - - case 0x1B: - huc6280[ChipID].write_data( to_huc6280_time( Sample ), 0x800 + Offset, Data ); - break; - - case 0x1D: - if ( run_k053260( to_fm_time( Sample ) ) ) - k053260.write( Offset, Data ); - break; - - case 0x1F: - if ( run_qsound( ChipID, Sample ) ) - qsound[ ChipID ].write( Data, ( Port << 8 ) + Offset ); - break; - } -} - -void Vgm_Core::set_tempo( double t ) -{ - if ( file_begin() ) - { - vgm_rate = (int) (44100 * t + 0.5); - blip_time_factor = (int) ((double) - (1 << blip_time_bits) / vgm_rate * stereo_buf[0].center()->clock_rate() + 0.5); - blip_ay_time_factor = (int) ((double) - (1 << blip_time_bits) / vgm_rate * stereo_buf[1].center()->clock_rate() + 0.5); - blip_huc6280_time_factor = (int) ((double) - (1 << blip_time_bits) / vgm_rate * stereo_buf[2].center()->clock_rate() + 0.5); - blip_gbdmg_time_factor = (int)((double) - (1 << blip_time_bits) / vgm_rate * stereo_buf[3].center()->clock_rate() + 0.5); - //dprintf( "blip_time_factor: %ld\n", blip_time_factor ); - //dprintf( "vgm_rate: %ld\n", vgm_rate ); - // TODO: remove? calculates vgm_rate more accurately (above differs at most by one Hz only) - //blip_time_factor = (int) floor( double (1 << blip_time_bits) * psg_rate_ / 44100 / t + 0.5 ); - //vgm_rate = (int) floor( double (1 << blip_time_bits) * psg_rate_ / blip_time_factor + 0.5 ); - - fm_time_factor = 2 + (int) (fm_rate * (1 << fm_time_bits) / vgm_rate + 0.5); - } -} - -bool Vgm_Core::header_t::valid_tag() const -{ - return !memcmp( tag, "Vgm ", 4 ); -} - -int Vgm_Core::header_t::size() const -{ - unsigned int version = get_le32( this->version ); - unsigned int data_offset; - if ( version >= 0x150 ) - { - data_offset = get_le32( this->data_offset ); - if ( data_offset ) data_offset += offsetof( header_t, data_offset ); - } - else data_offset = 0x40; - unsigned expected_size = ( version > 0x150 ) ? ( ( version > 0x160 ) ? unsigned(size_max) : unsigned(size_151) ) : unsigned(size_min); - if ( expected_size > data_offset ) expected_size = data_offset ? (data_offset > unsigned(size_max) ? unsigned(size_max) : data_offset) : unsigned(size_min); - return expected_size; -} - -void Vgm_Core::header_t::cleanup() -{ - unsigned int version = get_le32( this->version ); - - if ( size() < size_max ) memset( ((byte*)this) + size(), 0, size_max - size() ); - - if ( version < 0x161 ) - { - memset( this->gbdmg_rate, 0, size_max - offsetof(header_t, gbdmg_rate) ); - } - - if ( version < 0x160 ) - { - volume_modifier = 0; - reserved = 0; - loop_base = 0; - } - - if ( version < 0x151 ) memset( this->rf5c68_rate, 0, size_max - size_min ); - - if ( version < 0x150 ) - { - set_le32( data_offset, size_min - offsetof(header_t, data_offset) ); - sn76489_flags = 0; - set_le32( segapcm_rate, 0 ); - set_le32( segapcm_reg, 0 ); - } - - if ( version < 0x110 ) - { - set_le16( noise_feedback, 0 ); - noise_width = 0; - unsigned int rate = get_le32( ym2413_rate ); - set_le32( ym2612_rate, rate ); - set_le32( ym2151_rate, rate ); - } - - if ( version < 0x101 ) - { - set_le32( frame_rate, 0 ); - } -} - -blargg_err_t Vgm_Core::load_mem_( byte const data [], int size ) -{ - assert( offsetof (header_t, rf5c68_rate) == header_t::size_min ); - assert( offsetof (header_t, extra_offset[4]) == header_t::size_max ); - - if ( size <= header_t::size_min ) - return blargg_err_file_type; - - memcpy( &_header, data, header_t::size_min ); - - header_t const& h = header(); - - if ( !h.valid_tag() ) - return blargg_err_file_type; - - int version = get_le32( h.version ); - - check( version < 0x100 ); - - if ( version > 0x150 ) - { - if ( size < header().size() ) - return "Invalid header"; - - memcpy( &_header.rf5c68_rate, data + offsetof (header_t, rf5c68_rate), header().size() - header_t::size_min ); - } - - _header.cleanup(); - - // Get loop - loop_begin = file_end(); - if ( get_le32( h.loop_offset ) ) - loop_begin = &data [get_le32( h.loop_offset ) + offsetof (header_t,loop_offset)]; - - // PSG rate - int psg_rate = get_le32( h.psg_rate ) & 0x3FFFFFFF; - if ( !psg_rate ) - psg_rate = 3579545; - stereo_buf[0].clock_rate( psg_rate ); - - int ay_rate = get_le32( h.ay8910_rate ) & 0xBFFFFFFF; - if ( !ay_rate ) - ay_rate = 2000000; - stereo_buf[1].clock_rate( ay_rate * 2 ); - ay[0].set_type( (Ay_Apu::Ay_Apu_Type) header().ay8910_type ); - ay[1].set_type( (Ay_Apu::Ay_Apu_Type) header().ay8910_type ); - - int huc6280_rate = get_le32( h.huc6280_rate ) & 0xBFFFFFFF; - if ( !huc6280_rate ) - huc6280_rate = 3579545; - stereo_buf[2].clock_rate( huc6280_rate * 2 ); - - int gbdmg_rate = get_le32( h.gbdmg_rate ) & 0xBFFFFFFF; - if ( !gbdmg_rate ) - gbdmg_rate = Gb_Apu::clock_rate; - stereo_buf[3].clock_rate( gbdmg_rate ); - const int gbdmg_hacks = 3; - gbdmg[0].set_hacks( gbdmg_hacks ); - gbdmg[1].set_hacks( gbdmg_hacks ); - - // Disable FM - fm_rate = 0; - ymz280b.enable( false ); - ymf262[0].enable( false ); - ymf262[1].enable( false ); - ym3812[0].enable( false ); - ym3812[1].enable( false ); - ym2612[0].enable( false ); - ym2612[1].enable( false ); - ym2610[0].enable( false ); - ym2610[1].enable( false ); - ym2608[0].enable( false ); - ym2608[1].enable( false ); - ym2413[0].enable( false ); - ym2413[1].enable( false ); - ym2203[0].enable( false ); - ym2203[1].enable( false ); - ym2151[0].enable( false ); - ym2151[1].enable( false ); - c140.enable( false ); - segapcm.enable( false ); - rf5c68.enable( false ); - rf5c164.enable( false ); - pwm.enable( false ); - okim6258[0].enable( false ); - okim6258[1].enable( false ); - okim6295[0].enable( false ); - okim6295[1].enable( false ); - k051649.enable( false ); - k053260.enable( false ); - k054539.enable( false ); - qsound[0].enable( false ); - qsound[1].enable( false ); - - set_tempo( 1 ); - - return blargg_ok; -} - -// Update pre-1.10 header FM rates by scanning commands -void Vgm_Core::update_fm_rates( int* ym2151_rate, int* ym2413_rate, int* ym2612_rate ) const -{ - byte const* p = file_begin() + header().size(); - int data_offset = get_le32( header().data_offset ); - check( data_offset ); - if ( data_offset ) - p += data_offset + offsetof( header_t, data_offset ) - header().size(); - while ( p < file_end() ) - { - switch ( *p ) - { - case cmd_end: - return; - - case cmd_psg: - case cmd_byte_delay: - p += 2; - break; - - case cmd_delay: - p += 3; - break; - - case cmd_data_block: - p += 7 + get_le32( p + 3 ); - break; - - case cmd_ram_block: - p += 12; - break; - - case cmd_ym2413: - *ym2151_rate = 0; - *ym2612_rate = 0; - return; - - case cmd_ym2612_port0: - case cmd_ym2612_port1: - *ym2612_rate = *ym2413_rate; - *ym2413_rate = 0; - *ym2151_rate = 0; - return; - - case cmd_ym2151: - *ym2151_rate = *ym2413_rate; - *ym2413_rate = 0; - *ym2612_rate = 0; - return; - - default: - p += command_len( *p ); - } - } -} - -blargg_err_t Vgm_Core::init_chips( double* rate, bool reinit ) -{ - int ymz280b_rate = get_le32( header().ymz280b_rate ) & 0xBFFFFFFF; - int ymf262_rate = get_le32( header().ymf262_rate ) & 0xBFFFFFFF; - int ym3812_rate = get_le32( header().ym3812_rate ) & 0xBFFFFFFF; - int ym2612_rate = get_le32( header().ym2612_rate ) & 0xBFFFFFFF; - int ym2610_rate = get_le32( header().ym2610_rate ) & 0x3FFFFFFF; - int ym2608_rate = get_le32( header().ym2608_rate ) & 0x3FFFFFFF; - int ym2413_rate = get_le32( header().ym2413_rate ) & 0xBFFFFFFF; - int ym2203_rate = get_le32( header().ym2203_rate ) & 0xBFFFFFFF; - int ym2151_rate = get_le32( header().ym2151_rate ) & 0xBFFFFFFF; - int c140_rate = get_le32( header().c140_rate ) & 0xBFFFFFFF; - int segapcm_rate = get_le32( header().segapcm_rate ) & 0xBFFFFFFF; - int rf5c68_rate = get_le32( header().rf5c68_rate ) & 0xBFFFFFFF; - int rf5c164_rate = get_le32( header().rf5c164_rate ) & 0xBFFFFFFF; - int pwm_rate = get_le32( header().pwm_rate ) & 0xBFFFFFFF; - int okim6258_rate = get_le32( header().okim6258_rate ) & 0xBFFFFFFF; - int okim6295_rate = get_le32( header().okim6295_rate ) & 0xBFFFFFFF; - int k051649_rate = get_le32( header().k051649_rate ) & 0xBFFFFFFF; - int k053260_rate = get_le32( header().k053260_rate ) & 0xBFFFFFFF; - int k054539_rate = get_le32( header().k054539_rate ) & 0xBFFFFFFF; - int qsound_rate = get_le32( header().qsound_rate ) & 0xBFFFFFFF; - if ( ym2413_rate && get_le32( header().version ) < 0x110 ) - update_fm_rates( &ym2151_rate, &ym2413_rate, &ym2612_rate ); - - *rate = vgm_rate; - - if ( ymf262_rate ) - { - bool dual_chip = !!(header().ymf262_rate[3] & 0x40); - double gain = dual_chip ? 0.5 : 1.0; - double fm_rate = ymf262_rate / 288.0; - int result; - if ( !reinit ) - { - result = ymf262[0].set_rate( fm_rate, ymf262_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ymf262[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ymf262[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - result = ymf262[1].set_rate( fm_rate, ymf262_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ymf262[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ymf262[1].enable(); - } - } - if ( ym3812_rate ) - { - bool dual_chip = !!(header().ym3812_rate[3] & 0x40); - double gain = dual_chip ? 0.5 : 1.0; - double fm_rate = ym3812_rate / 72.0; - int result; - if ( !reinit ) - { - result = ym3812[0].set_rate( fm_rate, ym3812_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym3812[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym3812[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - result = ym3812[1].set_rate( fm_rate, ym3812_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym3812[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym3812[1].enable(); - } - } - if ( ym2612_rate ) - { - bool dual_chip = !!(header().ym2612_rate[3] & 0x40); - double gain = dual_chip ? 0.5 : 1.0; - double fm_rate = ym2612_rate / 144.0; - if ( !reinit ) - { - RETURN_ERR( ym2612[0].set_rate( fm_rate, ym2612_rate ) ); - } - RETURN_ERR( ym2612[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2612[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - RETURN_ERR( ym2612[1].set_rate( fm_rate, ym2612_rate ) ); - } - RETURN_ERR( ym2612[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2612[1].enable(); - } - } - if ( ym2610_rate ) - { - bool dual_chip = !!(header().ym2610_rate[3] & 0x40); - bool is_2610b = !!(header().ym2610_rate[3] & 0x80); - double gain = dual_chip ? 0.5 : 1.0; - double fm_rate = ym2610_rate / 72.0; - int result; - if ( !reinit ) - { - result = ym2610[0].set_rate( fm_rate, ym2610_rate, is_2610b ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym2610[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2610[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - result = ym2610[1].set_rate( fm_rate, ym2610_rate, is_2610b ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym2610[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2610[1].enable(); - } - } - if ( ym2608_rate ) - { - bool dual_chip = !!(header().ym2610_rate[3] & 0x40); - double gain = dual_chip ? 1.0 : 2.0; - double fm_rate = ym2608_rate / 72.0; - int result; - if ( !reinit ) - { - result = ym2608[0].set_rate( fm_rate, ym2608_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym2608[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2608[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - result = ym2608[1].set_rate( fm_rate, ym2608_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym2608[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2608[1].enable(); - } - } - if ( ym2413_rate ) - { - bool dual_chip = !!(header().ym2413_rate[3] & 0x40); - double gain = dual_chip ? 0.5 : 1.0; - double fm_rate = ym2413_rate / 72.0; - int result; - if ( !reinit ) - { - result = ym2413[0].set_rate( fm_rate, ym2413_rate ); - if ( result == 2 ) - return "YM2413 FM sound not supported"; - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym2413[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2413[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - result = ym2413[1].set_rate( fm_rate, ym2413_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym2413[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2413[1].enable(); - } - } - if ( ym2151_rate ) - { - bool dual_chip = !!(header().ym2151_rate[3] & 0x40); - double gain = dual_chip ? 0.5 : 1.0; - double fm_rate = ym2151_rate / 64.0; - int result; - if ( !reinit ) - { - result = ym2151[0].set_rate( fm_rate, ym2151_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym2151[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2151[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - result = ym2151[1].set_rate( fm_rate, ym2151_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( ym2151[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2151[1].enable(); - } - } - if ( ym2203_rate ) - { - bool dual_chip = !!(header().ym2203_rate[3] & 0x40); - double gain = dual_chip ? 0.5 : 1.0; - double fm_rate = ym2203_rate / 72.0; - int result; - if ( !reinit ) - { - result = ym2203[0].set_rate( fm_rate, ym2203_rate ); - CHECK_ALLOC ( !result ); - } - RETURN_ERR( ym2203[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2203[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - result = ym2203[1].set_rate( fm_rate, ym2203_rate ); - CHECK_ALLOC ( !result ); - } - RETURN_ERR( ym2203[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); - ym2203[1].enable(); - } - } - - if ( segapcm_rate ) - { - double pcm_rate = segapcm_rate / 128.0; - if ( !reinit ) - { - int result = segapcm.set_rate( get_le32( header().segapcm_reg ) ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( segapcm.setup( pcm_rate / vgm_rate, 0.85, 1.5 ) ); - segapcm.enable(); - } - if ( rf5c68_rate ) - { - double pcm_rate = rf5c68_rate / 384.0; - if ( !reinit ) - { - int result = rf5c68.set_rate(); - CHECK_ALLOC( !result ); - } - RETURN_ERR( rf5c68.setup( pcm_rate / vgm_rate, 0.85, 0.6875 ) ); - rf5c68.enable(); - } - if ( rf5c164_rate ) - { - double pcm_rate = rf5c164_rate / 384.0; - if ( !reinit ) - { - int result = rf5c164.set_rate( rf5c164_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( rf5c164.setup( pcm_rate / vgm_rate, 0.85, 0.5 ) ); - rf5c164.enable(); - } - if ( pwm_rate ) - { - double pcm_rate = 22020.0; - if ( !reinit ) - { - int result = pwm.set_rate( pwm_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( pwm.setup( pcm_rate / vgm_rate, 0.85, 0.875 ) ); - pwm.enable(); - } - if ( okim6258_rate ) - { - bool dual_chip = !!( header().okim6258_rate[3] & 0x40 ); - if ( !reinit ) - { - okim6258_hz[0] = okim6258[0].set_rate( okim6258_rate, header().okim6258_flags & 0x03, ( header().okim6258_flags & 0x04 ) >> 2, ( header().okim6258_flags & 0x08 ) >> 3 ); - CHECK_ALLOC( okim6258_hz[0] ); - } - RETURN_ERR( okim6258[0].setup( (double)okim6258_hz[0] / vgm_rate, 0.85, 1.0 ) ); - okim6258[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - okim6258_hz[1] = okim6258[1].set_rate( okim6258_rate, header().okim6258_flags & 0x03, ( header().okim6258_flags & 0x04 ) >> 2, ( header().okim6258_flags & 0x08 ) >> 3 ); - CHECK_ALLOC( okim6258_hz[1] ); - } - RETURN_ERR( okim6258[1].setup( (double)okim6258_hz[1] / vgm_rate, 0.85, 1.0 ) ); - okim6258[1].enable(); - } - } - if ( okim6295_rate ) - { - // moo - Mem_File_Reader rdr( file_begin(), file_size() ); - Music_Emu * vgm = gme_vgm_type->new_info(); - track_info_t info; - vgm->load( rdr ); - vgm->track_info( &info, 0 ); - delete vgm; - - bool is_cp_system = strncmp( info.system, "CP", 2 ) == 0; - bool dual_chip = !!( header().okim6295_rate[3] & 0x40 ); - double gain = is_cp_system ? 0.4296875 : 1.0; - if ( dual_chip ) gain *= 0.5; - if ( !reinit ) - { - okim6295_hz = okim6295[0].set_rate( okim6295_rate ); - CHECK_ALLOC( okim6295_hz ); - } - RETURN_ERR( okim6295[0].setup( (double)okim6295_hz / vgm_rate, 0.85, gain ) ); - okim6295[0].enable(); - if ( dual_chip ) - { - if ( !reinit ) - { - int result = okim6295[1].set_rate( okim6295_rate ); - CHECK_ALLOC( result ); - } - RETURN_ERR( okim6295[1].setup( (double)okim6295_hz / vgm_rate, 0.85, gain ) ); - okim6295[1].enable(); - } - } - if ( c140_rate ) - { - double pcm_rate = c140_rate; - if ( !reinit ) - { - int result = c140.set_rate( header().c140_type, c140_rate, c140_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( c140.setup( pcm_rate / vgm_rate, 0.85, 1.0 ) ); - c140.enable(); - } - if ( k051649_rate ) - { - double pcm_rate = k051649_rate / 16.0; - if ( !reinit ) - { - int result = k051649.set_rate( k051649_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( k051649.setup( pcm_rate / vgm_rate, 0.85, 1.0 ) ); - k051649.enable(); - } - if ( k053260_rate ) - { - double pcm_rate = k053260_rate / 32.0; - if ( !reinit ) - { - int result = k053260.set_rate( k053260_rate ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( k053260.setup( pcm_rate / vgm_rate, 0.85, 1.0 ) ); - k053260.enable(); - } - if ( k054539_rate ) - { - double pcm_rate = k054539_rate; - if ( !reinit ) - { - int result = k054539.set_rate( k054539_rate, header().k054539_flags ); - CHECK_ALLOC( !result ); - } - RETURN_ERR( k054539.setup( pcm_rate / vgm_rate, 0.85, 1.0 ) ); - k054539.enable(); - } - if ( ymz280b_rate ) - { - if ( !reinit ) - { - ymz280b_hz = ymz280b.set_rate( ymz280b_rate ); - CHECK_ALLOC( ymz280b_hz ); - } - RETURN_ERR( ymz280b.setup( (double)ymz280b_hz / vgm_rate, 0.85, 0.59375 ) ); - ymz280b.enable(); - } - if ( qsound_rate ) - { - /*double pcm_rate = (double)qsound_rate / 166.0;*/ - if ( !reinit ) - { - int result = qsound[0].set_rate( qsound_rate ); - CHECK_ALLOC( result ); - } - qsound[0].set_sample_rate( vgm_rate ); - RETURN_ERR( qsound[0].setup( 1.0, 0.85, 1.0 ) ); - qsound[0].enable(); - } - - fm_rate = *rate; - - return blargg_ok; -} - -void Vgm_Core::start_track() -{ - psg[0].reset( get_le16( header().noise_feedback ), header().noise_width ); - psg[1].reset( get_le16( header().noise_feedback ), header().noise_width ); - ay[0].reset(); - ay[1].reset(); - huc6280[0].reset(); - huc6280[1].reset(); - gbdmg[0].reset(); - gbdmg[1].reset(); - - blip_buf[0] = stereo_buf[0].center(); - blip_buf[1] = blip_buf[0]; - - dac_disabled[0] = -1; - dac_disabled[1] = -1; - pos = file_begin() + header().size(); - dac_amp[0] = -1; - dac_amp[1] = -1; - vgm_time = 0; - int data_offset = get_le32( header().data_offset ); - check( data_offset ); - if ( data_offset ) - pos += data_offset + offsetof (header_t,data_offset) - header().size(); - pcm_pos = pos; - - if ( uses_fm() ) - { - if ( rf5c68.enabled() ) - rf5c68.reset(); - - if ( rf5c164.enabled() ) - rf5c164.reset(); - - if ( segapcm.enabled() ) - segapcm.reset(); - - if ( pwm.enabled() ) - pwm.reset(); - - if ( okim6258[0].enabled() ) - okim6258[0].reset(); - - if ( okim6258[1].enabled() ) - okim6258[1].reset(); - - if ( okim6295[0].enabled() ) - okim6295[0].reset(); - - if ( okim6295[1].enabled() ) - okim6295[1].reset(); - - if ( k051649.enabled() ) - k051649.reset(); - - if ( k053260.enabled() ) - k053260.reset(); - - if ( k054539.enabled() ) - k054539.reset(); - - if ( c140.enabled() ) - c140.reset(); - - if ( ym2151[0].enabled() ) - ym2151[0].reset(); - - if ( ym2151[1].enabled() ) - ym2151[1].reset(); - - if ( ym2203[0].enabled() ) - ym2203[0].reset(); - - if ( ym2203[1].enabled() ) - ym2203[1].reset(); - - if ( ym2413[0].enabled() ) - ym2413[0].reset(); - - if ( ym2413[1].enabled() ) - ym2413[1].reset(); - - if ( ym2612[0].enabled() ) - ym2612[0].reset(); - - if ( ym2612[1].enabled() ) - ym2612[1].reset(); - - if ( ym2610[0].enabled() ) - ym2610[0].reset(); - - if ( ym2610[1].enabled() ) - ym2610[1].reset(); - - if ( ym2608[0].enabled() ) - ym2608[0].reset(); - - if ( ym2608[1].enabled() ) - ym2608[0].reset(); - - if ( ym3812[0].enabled() ) - ym3812[0].reset(); - - if ( ym3812[1].enabled() ) - ym3812[1].reset(); - - if ( ymf262[0].enabled() ) - ymf262[0].reset(); - - if ( ymf262[1].enabled() ) - ymf262[1].reset(); - - if ( ymz280b.enabled() ) - ymz280b.reset(); - - if ( qsound[0].enabled() ) - qsound[0].reset(); - - if ( qsound[1].enabled() ) - qsound[1].reset(); - - stereo_buf[0].clear(); - stereo_buf[1].clear(); - stereo_buf[2].clear(); - stereo_buf[3].clear(); - } - - for ( unsigned i = 0; i < DacCtrlUsed; i++ ) - { - device_reset_daccontrol( dac_control [i] ); - DacCtrlTime[DacCtrlMap[i]] = 0; - } - - for ( unsigned i = 0; i < PCM_BANK_COUNT; i++) - { - // reset PCM Bank, but not the data - // (this way I don't need to decompress the data again when restarting) - PCMBank [i].DataPos = 0; - PCMBank [i].BnkPos = 0; - } - PCMTbl.EntryCount = 0; - - fm_time_offset = 0; - ay_time_offset = 0; - huc6280_time_offset = 0; - gbdmg_time_offset = 0; - - dac_control_recursion = 0; -} - -inline Vgm_Core::fm_time_t Vgm_Core::to_fm_time( vgm_time_t t ) const -{ - return (t * fm_time_factor + fm_time_offset) >> fm_time_bits; -} - -inline blip_time_t Vgm_Core::to_psg_time( vgm_time_t t ) const -{ - return (t * blip_time_factor) >> blip_time_bits; -} - -inline blip_time_t Vgm_Core::to_ay_time( vgm_time_t t ) const -{ - return (t * blip_ay_time_factor) >> blip_time_bits; -} - -inline blip_time_t Vgm_Core::to_huc6280_time( vgm_time_t t ) const -{ - return (t * blip_huc6280_time_factor) >> blip_time_bits; -} - -inline blip_time_t Vgm_Core::to_gbdmg_time( vgm_time_t t ) const -{ - return (t * blip_gbdmg_time_factor) >> blip_time_bits; -} - -void Vgm_Core::write_pcm( vgm_time_t vgm_time, int chip, int amp ) -{ - chip = !!chip; - if ( blip_buf[chip] ) - { - check( amp >= 0 ); - blip_time_t blip_time = to_psg_time( vgm_time ); - int old = dac_amp[chip]; - int delta = amp - old; - dac_amp[chip] = amp; - blip_buf[chip]->set_modified(); - if ( old >= 0 ) // first write is ignored, to avoid click - pcm.offset_inline( blip_time, delta, blip_buf[chip] ); - else - dac_amp[chip] |= dac_disabled[chip]; - } -} - -blip_time_t Vgm_Core::run( vgm_time_t end_time ) -{ - vgm_time_t vgm_time = this->vgm_time; - vgm_time_t vgm_loop_time = ~0; - int ChipID; - byte const* pos = this->pos; - if ( pos > file_end() ) - set_warning( "Stream lacked end event" ); - - while ( vgm_time < end_time && pos < file_end() ) - { - // TODO: be sure there are enough bytes left in stream for particular command - // so we don't read past end - switch ( *pos++ ) - { - case cmd_end: - if ( vgm_loop_time == ~0 ) vgm_loop_time = vgm_time; - else if ( vgm_loop_time == vgm_time ) loop_begin = file_end(); // XXX some files may loop forever on a region without any delay commands - pos = loop_begin; // if not looped, loop_begin == file_end() - if ( pos != file_end() ) has_looped = true; - break; - - case cmd_delay_735: - vgm_time += 735; - break; - - case cmd_delay_882: - vgm_time += 882; - break; - - case cmd_gg_stereo: - psg[0].write_ggstereo( to_psg_time( vgm_time ), *pos++ ); - break; - - case cmd_gg_stereo_2: - psg[1].write_ggstereo( to_psg_time( vgm_time ), *pos++ ); - break; - - case cmd_psg: - psg[0].write_data( to_psg_time( vgm_time ), *pos++ ); - break; - - case cmd_psg_2: - psg[1].write_data( to_psg_time( vgm_time ), *pos++ ); - break; - - case cmd_ay8910: - ChipID = !!(pos [0] & 0x80); - chip_reg_write( vgm_time, 0x12, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); - pos += 2; - break; - - case cmd_delay: - vgm_time += pos [1] * 0x100 + pos [0]; - pos += 2; - break; - - case cmd_byte_delay: - vgm_time += *pos++; - break; - - case cmd_segapcm_write: - if ( get_le32( header().segapcm_rate ) > 0 ) - if ( run_segapcm( to_fm_time( vgm_time ) ) ) - segapcm.write( get_le16( pos ), pos [2] ); - pos += 3; - break; - - case cmd_rf5c68: - if ( run_rf5c68( to_fm_time( vgm_time ) ) ) - rf5c68.write( pos [0], pos [1] ); - pos += 2; - break; - - case cmd_rf5c68_mem: - if ( run_rf5c68( to_fm_time( vgm_time ) ) ) - rf5c68.write_mem( get_le16( pos ), pos [2] ); - pos += 3; - break; - - case cmd_rf5c164: - if ( run_rf5c164( to_fm_time( vgm_time ) ) ) - rf5c164.write( pos [0], pos [1] ); - pos += 2; - break; - - case cmd_rf5c164_mem: - if ( run_rf5c164( to_fm_time( vgm_time ) ) ) - rf5c164.write_mem( get_le16( pos ), pos [2] ); - pos += 3; - break; - - case cmd_pwm: - chip_reg_write( vgm_time, 0x11, 0x00, pos [0] >> 4, pos [0] & 0x0F, pos [1] ); - pos += 2; - break; - - case cmd_c140: - if ( get_le32( header().c140_rate ) > 0 ) - if ( run_c140( to_fm_time( vgm_time ) ) ) - c140.write( get_be16( pos ), pos [2] ); - pos += 3; - break; - - case cmd_ym2151: - chip_reg_write( vgm_time, 0x03, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2151_2: - chip_reg_write( vgm_time, 0x03, 0x01, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2203: - chip_reg_write( vgm_time, 0x06, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2203_2: - chip_reg_write( vgm_time, 0x06, 0x01, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2413: - chip_reg_write( vgm_time, 0x01, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2413_2: - chip_reg_write( vgm_time, 0x01, 0x01, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym3812: - chip_reg_write( vgm_time, 0x09, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym3812_2: - chip_reg_write( vgm_time, 0x09, 0x01, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ymf262_port0: - chip_reg_write( vgm_time, 0x0C, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ymf262_2_port0: - chip_reg_write( vgm_time, 0x0C, 0x01, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ymf262_port1: - chip_reg_write( vgm_time, 0x0C, 0x00, 0x01, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ymf262_2_port1: - chip_reg_write( vgm_time, 0x0C, 0x01, 0x01, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ymz280b: - chip_reg_write( vgm_time, 0x0F, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2612_port0: - chip_reg_write( vgm_time, 0x02, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2612_2_port0: - chip_reg_write( vgm_time, 0x02, 0x01, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2612_port1: - chip_reg_write( vgm_time, 0x02, 0x00, 0x01, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2612_2_port1: - chip_reg_write( vgm_time, 0x02, 0x01, 0x01, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2610_port0: - chip_reg_write( vgm_time, 0x08, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2610_2_port0: - chip_reg_write( vgm_time, 0x08, 0x01, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2610_port1: - chip_reg_write( vgm_time, 0x08, 0x00, 0x01, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2610_2_port1: - chip_reg_write( vgm_time, 0x08, 0x01, 0x01, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2608_port0: - chip_reg_write( vgm_time, 0x07, 0x00, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2608_2_port0: - chip_reg_write( vgm_time, 0x07, 0x01, 0x00, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2608_port1: - chip_reg_write( vgm_time, 0x07, 0x00, 0x01, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2608_2_port1: - chip_reg_write( vgm_time, 0x07, 0x01, 0x01, pos [0], pos [1] ); - pos += 2; - break; - - case cmd_okim6258_write: - chip_reg_write( vgm_time, 0x17, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); - pos += 2; - break; - - case cmd_okim6295_write: - ChipID = (pos [0] & 0x80) ? 1 : 0; - chip_reg_write( vgm_time, 0x18, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); - pos += 2; - break; - - case cmd_huc6280_write: - ChipID = (pos [0] & 0x80) ? 1 : 0; - chip_reg_write( vgm_time, 0x1B, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); - pos += 2; - break; - - case cmd_gbdmg_write: - ChipID = (pos [0] & 0x80) ? 1 : 0; - chip_reg_write( vgm_time, 0x13, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); - pos += 2; - break; - - case cmd_k051649_write: - chip_reg_write( vgm_time, 0x19, 0x00, pos [0] & 0x7F, pos [1], pos [2] ); - pos += 3; - break; - - case cmd_k053260_write: - chip_reg_write( vgm_time, 0x1D, 0x00, 0x00, pos [0] & 0x7F, pos [1] ); - pos += 2; - break; - - case cmd_k054539_write: - chip_reg_write( vgm_time, 0x1A, 0x00, pos [0] & 0x7F, pos [1], pos [2] ); - pos += 3; - break; - - case cmd_qsound_write: - chip_reg_write( vgm_time, 0x1F, 0x00, pos [0], pos [1], pos [2] ); - pos += 3; - break; - - case cmd_dacctl_setup: - if ( run_dac_control( vgm_time ) ) - { - unsigned chip = pos [0]; - if ( chip < 0xFF ) - { - if ( ! DacCtrl [chip].Enable ) - { - dac_control_grow( chip ); - DacCtrl [chip].Enable = true; - } - daccontrol_setup_chip( dac_control [DacCtrlMap [chip]], pos [1] & 0x7F, ( pos [1] & 0x80 ) >> 7, get_be16( pos + 2 ) ); - } - } - pos += 4; - break; - - case cmd_dacctl_data: - if ( run_dac_control( vgm_time ) ) - { - unsigned chip = pos [0]; - if ( chip < 0xFF && DacCtrl [chip].Enable ) - { - DacCtrl [chip].Bank = pos [1]; - if ( DacCtrl [chip].Bank >= 0x40 ) - DacCtrl [chip].Bank = 0x00; - - VGM_PCM_BANK * TempPCM = &PCMBank [DacCtrl [chip].Bank]; - daccontrol_set_data( dac_control [DacCtrlMap [chip]], TempPCM->Data, TempPCM->DataSize, pos [2], pos [3] ); - } - } - pos += 4; - break; - case cmd_dacctl_freq: - if ( run_dac_control( vgm_time ) ) - { - unsigned chip = pos [0]; - if ( chip < 0xFF && DacCtrl [chip].Enable ) - { - daccontrol_set_frequency( dac_control [DacCtrlMap [chip]], get_le32( pos + 1 ) ); - } - } - pos += 5; - break; - case cmd_dacctl_play: - if ( run_dac_control( vgm_time ) ) - { - unsigned chip = pos [0]; - if ( chip < 0xFF && DacCtrl [chip].Enable && PCMBank [DacCtrl [chip].Bank].BankCount ) - { - daccontrol_start( dac_control [DacCtrlMap [chip]], get_le32( pos + 1 ), pos [5], get_le32( pos + 6 ) ); - } - } - pos += 10; - break; - case cmd_dacctl_stop: - if ( run_dac_control( vgm_time ) ) - { - unsigned chip = pos [0]; - if ( chip < 0xFF && DacCtrl [chip].Enable ) - { - daccontrol_stop( dac_control [DacCtrlMap [chip]] ); - } - else if ( chip == 0xFF ) - { - for ( unsigned i = 0; i < DacCtrlUsed; i++ ) - { - daccontrol_stop( dac_control [i] ); - } - } - } - pos++; - break; - case cmd_dacctl_playblock: - if ( run_dac_control( vgm_time ) ) - { - unsigned chip = pos [0]; - if ( chip < 0xFF && DacCtrl [chip].Enable && PCMBank [DacCtrl [chip].Bank].BankCount ) - { - VGM_PCM_BANK * TempPCM = &PCMBank [DacCtrl [chip].Bank]; - unsigned block_number = get_le16( pos + 1 ); - if ( block_number >= TempPCM->BankCount ) - block_number = 0; - VGM_PCM_DATA * TempBnk = &TempPCM->Bank [block_number]; - unsigned flags = DCTRL_LMODE_BYTES | ((pos [4] & 1) << 7); - daccontrol_start( dac_control [DacCtrlMap [chip]], TempBnk->DataStart, flags, TempBnk->DataSize ); - } - } - pos += 4; - break; - - case cmd_data_block: { - check( *pos == cmd_end ); - int type = pos [1]; - int size = get_le32( pos + 2 ); - int chipid = 0; - if ( size & 0x80000000 ) - { - size &= 0x7FFFFFFF; - chipid = 1; - } - pos += 6; - switch ( type & 0xC0 ) - { - case pcm_block_type: - case pcm_aux_block_type: - AddPCMData( type, size, pos ); - break; - - case rom_block_type: - if ( size >= 8 ) - { - int rom_size = get_le32( pos ); - int data_start = get_le32( pos + 4 ); - int data_size = size - 8; - void * rom_data = ( void * ) ( pos + 8 ); - - switch ( type ) - { - case rom_segapcm: - if ( segapcm.enabled() ) - segapcm.write_rom( rom_size, data_start, data_size, rom_data ); - break; - - case rom_ym2608_deltat: - if ( ym2608[chipid].enabled() ) - { - ym2608[chipid].write_rom( 0x02, rom_size, data_start, data_size, rom_data ); - } - break; - - case rom_ym2610_adpcm: - case rom_ym2610_deltat: - if ( ym2610[chipid].enabled() ) - { - int rom_id = 0x01 + ( type - rom_ym2610_adpcm ); - ym2610[chipid].write_rom( rom_id, rom_size, data_start, data_size, rom_data ); - } - break; - - case rom_ymz280b: - if ( ymz280b.enabled() ) - ymz280b.write_rom( rom_size, data_start, data_size, rom_data ); - break; - - case rom_okim6295: - if ( okim6295[chipid].enabled() ) - okim6295[chipid].write_rom( rom_size, data_start, data_size, rom_data ); - break; - - case rom_k054539: - if ( k054539.enabled() ) - k054539.write_rom( rom_size, data_start, data_size, rom_data ); - break; - - case rom_c140: - if ( c140.enabled() ) - c140.write_rom( rom_size, data_start, data_size, rom_data ); - break; - - case rom_k053260: - if ( k053260.enabled() ) - k053260.write_rom( rom_size, data_start, data_size, rom_data ); - break; - - case rom_qsound: - if ( qsound[chipid].enabled() ) - qsound[chipid].write_rom( rom_size, data_start, data_size, rom_data ); - break; - } - } - break; - - case ram_block_type: - if ( size >= 2 ) - { - int data_start = get_le16( pos ); - int data_size = size - 2; - void * ram_data = ( void * ) ( pos + 2 ); - - switch ( type ) - { - case ram_rf5c68: - if ( rf5c68.enabled() ) - rf5c68.write_ram( data_start, data_size, ram_data ); - break; - - case ram_rf5c164: - if ( rf5c164.enabled() ) - rf5c164.write_ram( data_start, data_size, ram_data ); - break; - } - } - break; - } - pos += size; - break; - } - - case cmd_ram_block: { - check( *pos == cmd_end ); - int type = pos[ 1 ]; - int data_start = get_le24( pos + 2 ); - int data_addr = get_le24( pos + 5 ); - int data_size = get_le24( pos + 8 ); - if ( !data_size ) data_size += 0x01000000; - void * data_ptr = (void *) GetPointerFromPCMBank( type, data_start ); - switch ( type ) - { - case rf5c68_ram_block: - if ( rf5c68.enabled() ) - rf5c68.write_ram( data_addr, data_size, data_ptr ); - break; - - case rf5c164_ram_block: - if ( rf5c164.enabled() ) - rf5c164.write_ram( data_addr, data_size, data_ptr ); - break; - } - pos += 11; - break; - } - - case cmd_pcm_seek: - pcm_pos = GetPointerFromPCMBank( 0, get_le32( pos ) ); - pos += 4; - break; - - default: - int cmd = pos [-1]; - switch ( cmd & 0xF0 ) - { - case cmd_pcm_delay: - chip_reg_write( vgm_time, 0x02, 0x00, 0x00, ym2612_dac_port, *pcm_pos++ ); - vgm_time += cmd & 0x0F; - break; - - case cmd_short_delay: - vgm_time += (cmd & 0x0F) + 1; - break; - - case 0x50: - pos += 2; - break; - - default: - pos += command_len( cmd ) - 1; - set_warning( "Unknown stream event" ); - } - } - } - vgm_time -= end_time; - this->pos = pos; - this->vgm_time = vgm_time; - - return to_psg_time( end_time ); -} - -blip_time_t Vgm_Core::run_psg( int msec ) -{ - blip_time_t t = run( msec * vgm_rate / 1000 ); - psg[0].end_frame( t ); - psg[1].end_frame( t ); - return t; -} - -int Vgm_Core::play_frame( blip_time_t blip_time, int sample_count, blip_sample_t out [] ) -{ - // to do: timing is working mostly by luck - int min_pairs = (unsigned) sample_count / 2; - int vgm_time = (min_pairs << fm_time_bits) / fm_time_factor - 1; - assert( to_fm_time( vgm_time ) <= min_pairs ); - int pairs; - while ( (pairs = to_fm_time( vgm_time )) < min_pairs ) - vgm_time++; - //dprintf( "pairs: %d, min_pairs: %d\n", pairs, min_pairs ); - - memset( out, 0, pairs * stereo * sizeof *out ); - - if ( ymf262[0].enabled() ) - { - ymf262[0].begin_frame( out ); - if ( ymf262[1].enabled() ) - { - ymf262[1].begin_frame( out ); - } - } - if ( ym3812[0].enabled() ) - { - ym3812[0].begin_frame( out ); - if ( ym3812[1].enabled() ) - { - ym3812[1].begin_frame( out ); - } - } - if ( ym2612[0].enabled() ) - { - ym2612[0].begin_frame( out ); - if ( ym2612[1].enabled() ) - { - ym2612[1].begin_frame( out ); - } - } - if ( ym2610[0].enabled() ) - { - ym2610[0].begin_frame( out ); - if ( ym2610[1].enabled() ) - { - ym2610[1].begin_frame( out ); - } - } - if ( ym2608[0].enabled() ) - { - ym2608[0].begin_frame( out ); - if ( ym2608[1].enabled() ) - { - ym2608[1].begin_frame( out ); - } - } - if ( ym2413[0].enabled() ) - { - ym2413[0].begin_frame( out ); - if ( ym2413[1].enabled() ) - { - ym2413[1].begin_frame( out ); - } - } - if ( ym2203[0].enabled() ) - { - ym2203[0].begin_frame( out ); - if ( ym2203[1].enabled() ) - { - ym2203[1].begin_frame( out ); - } - } - if ( ym2151[0].enabled() ) - { - ym2151[0].begin_frame( out ); - if ( ym2151[1].enabled() ) - { - ym2151[1].begin_frame( out ); - } - } - - if ( c140.enabled() ) - { - c140.begin_frame( out ); - } - if ( segapcm.enabled() ) - { - segapcm.begin_frame( out ); - } - if ( rf5c68.enabled() ) - { - rf5c68.begin_frame( out ); - } - if ( rf5c164.enabled() ) - { - rf5c164.begin_frame( out ); - } - if ( pwm.enabled() ) - { - pwm.begin_frame( out ); - } - if ( okim6258[0].enabled() ) - { - okim6258[0].begin_frame( out ); - if ( okim6258[1].enabled() ) - { - okim6258[1].begin_frame( out ); - } - } - if ( okim6295[0].enabled() ) - { - okim6295[0].begin_frame( out ); - if ( okim6295[1].enabled() ) - { - okim6295[1].begin_frame( out ); - } - } - if ( k051649.enabled() ) - { - k051649.begin_frame( out ); - } - if ( k053260.enabled() ) - { - k053260.begin_frame( out ); - } - if ( k054539.enabled() ) - { - k054539.begin_frame( out ); - } - if ( ymz280b.enabled() ) - { - ymz280b.begin_frame( out ); - } - if ( qsound[0].enabled() ) - { - qsound[0].begin_frame( out ); - if ( qsound[1].enabled() ) - { - qsound[1].begin_frame( out ); - } - } - - run( vgm_time ); - - run_dac_control( vgm_time ); - - run_ymf262( 0, pairs ); run_ymf262( 1, pairs ); - run_ym3812( 0, pairs ); run_ym3812( 1, pairs ); - run_ym2612( 0, pairs ); run_ym2612( 1, pairs ); - run_ym2610( 0, pairs ); run_ym2610( 1, pairs ); - run_ym2608( 0, pairs ); run_ym2608( 1, pairs ); - run_ym2413( 0, pairs ); run_ym2413( 1, pairs ); - run_ym2203( 0, pairs ); run_ym2203( 1, pairs ); - run_ym2151( 0, pairs ); run_ym2151( 1, pairs ); - run_c140( pairs ); - run_segapcm( pairs ); - run_rf5c68( pairs ); - run_rf5c164( pairs ); - run_pwm( pairs ); - run_okim6258( 0, pairs ); run_okim6258( 1, pairs ); - run_okim6295( 0, pairs ); run_okim6295( 1, pairs ); - run_k051649( pairs ); - run_k053260( pairs ); - run_k054539( pairs ); - run_ymz280b( pairs ); - run_qsound( 0, pairs ); run_qsound( 1, pairs ); - - fm_time_offset = (vgm_time * fm_time_factor + fm_time_offset) - (pairs << fm_time_bits); - - psg[0].end_frame( blip_time ); - psg[1].end_frame( blip_time ); - - ay_time_offset = (vgm_time * blip_ay_time_factor + ay_time_offset) - (pairs << blip_time_bits); - - blip_time_t ay_end_time = to_ay_time( vgm_time ); - ay[0].end_frame( ay_end_time ); - ay[1].end_frame( ay_end_time ); - - huc6280_time_offset = (vgm_time * blip_huc6280_time_factor + huc6280_time_offset) - (pairs << blip_time_bits); - - blip_time_t huc6280_end_time = to_huc6280_time( vgm_time ); - huc6280[0].end_frame( huc6280_end_time ); - huc6280[1].end_frame( huc6280_end_time ); - - gbdmg_time_offset = (vgm_time * blip_gbdmg_time_factor + gbdmg_time_offset) - (pairs << blip_time_bits); - - blip_time_t gbdmg_end_time = to_gbdmg_time( vgm_time ); - gbdmg[0].end_frame( gbdmg_end_time ); - gbdmg[1].end_frame( gbdmg_end_time ); - - memset( DacCtrlTime, 0, sizeof(DacCtrlTime) ); - - return pairs * stereo; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Vgm_Core.h" + +#include "dac_control.h" + +#include "blargg_endian.h" +#include + +// Needed for OKIM6295 system detection +#include "Vgm_Emu.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +int const stereo = 2; +int const fm_time_bits = 12; +int const blip_time_bits = 12; + +enum { + cmd_gg_stereo = 0x4F, + cmd_gg_stereo_2 = 0x3F, + cmd_psg = 0x50, + cmd_psg_2 = 0x30, + cmd_ym2413 = 0x51, + cmd_ym2413_2 = 0xA1, + cmd_ym2612_port0 = 0x52, + cmd_ym2612_2_port0 = 0xA2, + cmd_ym2612_port1 = 0x53, + cmd_ym2612_2_port1 = 0xA3, + cmd_ym2151 = 0x54, + cmd_ym2151_2 = 0xA4, + cmd_ym2203 = 0x55, + cmd_ym2203_2 = 0xA5, + cmd_ym2608_port0 = 0x56, + cmd_ym2608_2_port0 = 0xA6, + cmd_ym2608_port1 = 0x57, + cmd_ym2608_2_port1 = 0xA7, + cmd_ym2610_port0 = 0x58, + cmd_ym2610_2_port0 = 0xA8, + cmd_ym2610_port1 = 0x59, + cmd_ym2610_2_port1 = 0xA9, + cmd_ym3812 = 0x5A, + cmd_ym3812_2 = 0xAA, + cmd_ymz280b = 0x5D, + cmd_ymf262_port0 = 0x5E, + cmd_ymf262_2_port0 = 0xAE, + cmd_ymf262_port1 = 0x5F, + cmd_ymf262_2_port1 = 0xAF, + cmd_delay = 0x61, + cmd_delay_735 = 0x62, + cmd_delay_882 = 0x63, + cmd_byte_delay = 0x64, + cmd_end = 0x66, + cmd_data_block = 0x67, + cmd_ram_block = 0x68, + cmd_short_delay = 0x70, + cmd_pcm_delay = 0x80, + cmd_dacctl_setup = 0x90, + cmd_dacctl_data = 0x91, + cmd_dacctl_freq = 0x92, + cmd_dacctl_play = 0x93, + cmd_dacctl_stop = 0x94, + cmd_dacctl_playblock= 0x95, + cmd_ay8910 = 0xA0, + cmd_rf5c68 = 0xB0, + cmd_rf5c164 = 0xB1, + cmd_pwm = 0xB2, + cmd_gbdmg_write = 0xB3, + cmd_okim6258_write = 0xB7, + cmd_okim6295_write = 0xB8, + cmd_huc6280_write = 0xB9, + cmd_k053260_write = 0xBA, + cmd_segapcm_write = 0xC0, + cmd_rf5c68_mem = 0xC1, + cmd_rf5c164_mem = 0xC2, + cmd_qsound_write = 0xC4, + cmd_k051649_write = 0xD2, + cmd_k054539_write = 0xD3, + cmd_c140 = 0xD4, + cmd_pcm_seek = 0xE0, + + rf5c68_ram_block = 0x01, + rf5c164_ram_block = 0x02, + + pcm_block_type = 0x00, + pcm_aux_block_type = 0x40, + rom_block_type = 0x80, + ram_block_type = 0xC0, + + rom_segapcm = 0x80, + rom_ym2608_deltat = 0x81, + rom_ym2610_adpcm = 0x82, + rom_ym2610_deltat = 0x83, + rom_ymz280b = 0x86, + rom_okim6295 = 0x8B, + rom_k054539 = 0x8C, + rom_c140 = 0x8D, + rom_k053260 = 0x8E, + rom_qsound = 0x8F, + + ram_rf5c68 = 0xC0, + ram_rf5c164 = 0xC1, + ram_nesapu = 0xC2, + + ym2612_dac_port = 0x2A, + ym2612_dac_pan_port = 0xB6 +}; + +inline int command_len( int command ) +{ + static byte const lens [0x10] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 1,1,1,2,2,3,1,1,1,1,3,3,4,4,5,5 + }; + int len = lens [command >> 4]; + check( len != 1 ); + return len; +} + +int Vgm_Core::run_ym2151( int chip, int time ) +{ + return ym2151[!!chip].run_until( time ); +} + +int Vgm_Core::run_ym2203( int chip, int time ) +{ + return ym2203[!!chip].run_until( time ); +} + +int Vgm_Core::run_ym2413( int chip, int time ) +{ + return ym2413[!!chip].run_until( time ); +} + +int Vgm_Core::run_ym2612( int chip, int time ) +{ + return ym2612[!!chip].run_until( time ); +} + +int Vgm_Core::run_ym2610( int chip, int time ) +{ + return ym2610[!!chip].run_until( time ); +} + +int Vgm_Core::run_ym2608( int chip, int time ) +{ + return ym2608[!!chip].run_until( time ); +} + +int Vgm_Core::run_ym3812( int chip, int time ) +{ + return ym3812[!!chip].run_until( time ); +} + +int Vgm_Core::run_ymf262( int chip, int time ) +{ + return ymf262[!!chip].run_until( time ); +} + +int Vgm_Core::run_ymz280b( int time ) +{ + return ymz280b.run_until( time ); +} + +int Vgm_Core::run_c140( int time ) +{ + return c140.run_until( time ); +} + +int Vgm_Core::run_segapcm( int time ) +{ + return segapcm.run_until( time ); +} + +int Vgm_Core::run_rf5c68( int time ) +{ + return rf5c68.run_until( time ); +} + +int Vgm_Core::run_rf5c164( int time ) +{ + return rf5c164.run_until( time ); +} + +int Vgm_Core::run_pwm( int time ) +{ + return pwm.run_until( time ); +} + +int Vgm_Core::run_okim6258( int chip, int time ) +{ + chip = !!chip; + if ( okim6258[chip].enabled() ) + { + int current_clock = okim6258[chip].get_clock(); + if ( okim6258_hz[chip] != current_clock ) + { + okim6258_hz[chip] = current_clock; + okim6258[chip].setup( (double)okim6258_hz[chip] / vgm_rate, 0.85, 1.0 ); + } + } + return okim6258[chip].run_until( time ); +} + +int Vgm_Core::run_okim6295( int chip, int time ) +{ + return okim6295[!!chip].run_until( time ); +} + +int Vgm_Core::run_k051649( int time ) +{ + return k051649.run_until( time ); +} + +int Vgm_Core::run_k053260( int time ) +{ + return k053260.run_until( time ); +} + +int Vgm_Core::run_k054539( int time ) +{ + return k054539.run_until( time ); +} + +int Vgm_Core::run_qsound( int chip, int time ) +{ + return qsound[!!chip].run_until( time ); +} + +/* Recursive fun starts here! */ +int Vgm_Core::run_dac_control( int time ) +{ + if (dac_control_recursion) return 1; + + ++dac_control_recursion; + for ( unsigned i = 0; i < DacCtrlUsed; i++ ) + { + int time_start = DacCtrlTime[DacCtrlMap[i]]; + if ( time > time_start ) + { + DacCtrlTime[DacCtrlMap[i]] = time; + daccontrol_update( dac_control [i], time_start, time - time_start ); + } + } + --dac_control_recursion; + + return 1; +} + +Vgm_Core::Vgm_Core() +{ + blip_buf[0] = stereo_buf[0].center(); + blip_buf[1] = blip_buf[0]; + has_looped = false; + DacCtrlUsed = 0; + dac_control = NULL; + memset( PCMBank, 0, sizeof( PCMBank ) ); + memset( &PCMTbl, 0, sizeof( PCMTbl ) ); + memset( DacCtrl, 0, sizeof( DacCtrl ) ); + memset( DacCtrlTime, 0, sizeof( DacCtrlTime ) ); +} + +Vgm_Core::~Vgm_Core() +{ + for (unsigned i = 0; i < DacCtrlUsed; i++) device_stop_daccontrol( dac_control [i] ); + if ( dac_control ) free( dac_control ); + for (unsigned i = 0; i < PCM_BANK_COUNT; i++) + { + if ( PCMBank [i].Bank ) free( PCMBank [i].Bank ); + if ( PCMBank [i].Data ) free( PCMBank [i].Data ); + } + if ( PCMTbl.Entries ) free( PCMTbl.Entries ); +} + +typedef unsigned int FUINT8; +typedef unsigned int FUINT16; + +void Vgm_Core::ReadPCMTable(unsigned DataSize, const byte* Data) +{ + byte ValSize; + unsigned TblSize; + + PCMTbl.ComprType = Data[0x00]; + PCMTbl.CmpSubType = Data[0x01]; + PCMTbl.BitDec = Data[0x02]; + PCMTbl.BitCmp = Data[0x03]; + PCMTbl.EntryCount = get_le16( Data + 0x04 ); + + ValSize = (PCMTbl.BitDec + 7) / 8; + TblSize = PCMTbl.EntryCount * ValSize; + + PCMTbl.Entries = realloc(PCMTbl.Entries, TblSize); + memcpy(PCMTbl.Entries, Data + 0x06, TblSize); +} + +bool Vgm_Core::DecompressDataBlk(VGM_PCM_DATA* Bank, unsigned DataSize, const byte* Data) +{ + UINT8 ComprType; + UINT8 BitDec; + FUINT8 BitCmp; + UINT8 CmpSubType; + UINT16 AddVal; + const UINT8* InPos; + const UINT8* InDataEnd; + UINT8* OutPos; + const UINT8* OutDataEnd; + FUINT16 InVal; + FUINT16 OutVal = 0; + FUINT8 ValSize; + FUINT8 InShift; + FUINT8 OutShift; + UINT8* Ent1B = nullptr; + UINT16* Ent2B = nullptr; + + // ReadBits Variables + FUINT8 BitsToRead; + FUINT8 BitReadVal; + FUINT8 InValB; + FUINT8 BitMask; + FUINT8 OutBit; + + // Variables for DPCM + UINT16 OutMask; + + ComprType = Data[0x00]; + Bank->DataSize = get_le32( Data + 0x01 ); + + switch(ComprType) + { + case 0x00: // n-Bit compression + BitDec = Data[0x05]; + BitCmp = Data[0x06]; + CmpSubType = Data[0x07]; + AddVal = get_le16( Data + 0x08 ); + + if (CmpSubType == 0x02) + { + Ent1B = (UINT8*)PCMTbl.Entries; + Ent2B = (UINT16*)PCMTbl.Entries; + if (! PCMTbl.EntryCount) + { + Bank->DataSize = 0x00; + return false; + } + else if (BitDec != PCMTbl.BitDec || BitCmp != PCMTbl.BitCmp) + { + Bank->DataSize = 0x00; + return false; + } + } + + ValSize = (BitDec + 7) / 8; + InPos = Data + 0x0A; + InDataEnd = Data + DataSize; + InShift = 0; + OutShift = BitDec - BitCmp; + OutDataEnd = Bank->Data + Bank->DataSize; + + for (OutPos = Bank->Data; OutPos < OutDataEnd && InPos < InDataEnd; OutPos += ValSize) + { + //InVal = ReadBits(Data, InPos, &InShift, BitCmp); + // inlined - is 30% faster + OutBit = 0x00; + InVal = 0x0000; + BitsToRead = BitCmp; + while(BitsToRead) + { + BitReadVal = (BitsToRead >= 8) ? 8 : BitsToRead; + BitsToRead -= BitReadVal; + BitMask = (1 << BitReadVal) - 1; + + InShift += BitReadVal; + InValB = (*InPos << InShift >> 8) & BitMask; + if (InShift >= 8) + { + InShift -= 8; + InPos ++; + if (InShift) + InValB |= (*InPos << InShift >> 8) & BitMask; + } + + InVal |= InValB << OutBit; + OutBit += BitReadVal; + } + + switch(CmpSubType) + { + case 0x00: // Copy + OutVal = InVal + AddVal; + break; + case 0x01: // Shift Left + OutVal = (InVal << OutShift) + AddVal; + break; + case 0x02: // Table + switch(ValSize) + { + case 0x01: + OutVal = Ent1B[InVal]; + break; + case 0x02: + OutVal = Ent2B[InVal]; + break; + } + break; + } + + //memcpy(OutPos, &OutVal, ValSize); + if (ValSize == 0x01) + *((UINT8*)OutPos) = (UINT8)OutVal; + else //if (ValSize == 0x02) + *((UINT16*)OutPos) = (UINT16)OutVal; + } + break; + case 0x01: // Delta-PCM + BitDec = Data[0x05]; + BitCmp = Data[0x06]; + OutVal = get_le16( Data + 0x08 ); + + Ent1B = (UINT8*)PCMTbl.Entries; + Ent2B = (UINT16*)PCMTbl.Entries; + if (! PCMTbl.EntryCount) + { + Bank->DataSize = 0x00; + return false; + } + else if (BitDec != PCMTbl.BitDec || BitCmp != PCMTbl.BitCmp) + { + Bank->DataSize = 0x00; + return false; + } + + ValSize = (BitDec + 7) / 8; + OutMask = (1 << BitDec) - 1; + InPos = Data + 0x0A; + InDataEnd = Data + DataSize; + InShift = 0; + OutShift = BitDec - BitCmp; + OutDataEnd = Bank->Data + Bank->DataSize; + AddVal = 0x0000; + + for (OutPos = Bank->Data; OutPos < OutDataEnd && InPos < InDataEnd; OutPos += ValSize) + { + //InVal = ReadBits(Data, InPos, &InShift, BitCmp); + // inlined - is 30% faster + OutBit = 0x00; + InVal = 0x0000; + BitsToRead = BitCmp; + while(BitsToRead) + { + BitReadVal = (BitsToRead >= 8) ? 8 : BitsToRead; + BitsToRead -= BitReadVal; + BitMask = (1 << BitReadVal) - 1; + + InShift += BitReadVal; + InValB = (*InPos << InShift >> 8) & BitMask; + if (InShift >= 8) + { + InShift -= 8; + InPos ++; + if (InShift) + InValB |= (*InPos << InShift >> 8) & BitMask; + } + + InVal |= InValB << OutBit; + OutBit += BitReadVal; + } + + switch(ValSize) + { + case 0x01: + AddVal = Ent1B[InVal]; + OutVal += AddVal; + OutVal &= OutMask; + *((UINT8*)OutPos) = (UINT8)OutVal; + break; + case 0x02: + AddVal = Ent2B[InVal]; + OutVal += AddVal; + OutVal &= OutMask; + *((UINT16*)OutPos) = (UINT16)OutVal; + break; + } + } + break; + default: + return false; + } + + return true; +} + +void Vgm_Core::AddPCMData(byte Type, unsigned DataSize, const byte* Data) +{ + unsigned CurBnk; + VGM_PCM_BANK* TempPCM; + VGM_PCM_DATA* TempBnk; + unsigned BankSize; + bool RetVal; + + + if ((Type & 0x3F) >= PCM_BANK_COUNT || has_looped) + return; + + if (Type == 0x7F) + { + ReadPCMTable( DataSize, Data ); + return; + } + + TempPCM = &PCMBank[Type & 0x3F]; + CurBnk = TempPCM->BankCount; + TempPCM->BankCount ++; + TempPCM->BnkPos ++; + if (TempPCM->BnkPos < TempPCM->BankCount) + return; // Speed hack (for restarting playback) + TempPCM->Bank = (VGM_PCM_DATA*)realloc(TempPCM->Bank, + sizeof(VGM_PCM_DATA) * TempPCM->BankCount); + + if (! (Type & 0x40)) + BankSize = DataSize; + else + BankSize = get_le32( Data + 1 ); + TempPCM->Data = ( byte * ) realloc(TempPCM->Data, TempPCM->DataSize + BankSize); + TempBnk = &TempPCM->Bank[CurBnk]; + TempBnk->DataStart = TempPCM->DataSize; + if (! (Type & 0x40)) + { + TempBnk->DataSize = DataSize; + TempBnk->Data = TempPCM->Data + TempBnk->DataStart; + memcpy(TempBnk->Data, Data, DataSize); + } + else + { + TempBnk->Data = TempPCM->Data + TempBnk->DataStart; + RetVal = DecompressDataBlk(TempBnk, DataSize, Data); + if (! RetVal) + { + TempBnk->Data = NULL; + TempBnk->DataSize = 0x00; + return; + } + } + TempPCM->DataSize += BankSize; +} + +const byte* Vgm_Core::GetPointerFromPCMBank(byte Type, unsigned DataPos) +{ + if (Type >= PCM_BANK_COUNT) + return NULL; + + if (DataPos >= PCMBank[Type].DataSize) + return NULL; + + return &PCMBank[Type].Data[DataPos]; +} + +void Vgm_Core::dac_control_grow(byte chip_id) +{ + for ( unsigned i = 0; i < DacCtrlUsed; i++ ) + { + if ( DacCtrlUsg [i] == chip_id ) + { + device_reset_daccontrol( dac_control [i] ); + return; + } + } + unsigned chip_mapped = DacCtrlUsed; + DacCtrlUsg [DacCtrlUsed++] = chip_id; + DacCtrlMap [chip_id] = chip_mapped; + dac_control = (void**) realloc( dac_control, DacCtrlUsed * sizeof(void*) ); + dac_control [chip_mapped] = device_start_daccontrol( vgm_rate, this ); + device_reset_daccontrol( dac_control [chip_mapped] ); +} + +extern "C" void chip_reg_write(void * context, UINT32 Sample, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset, UINT8 Data) +{ + Vgm_Core * core = (Vgm_Core *) context; + core->chip_reg_write(Sample, ChipType, ChipID, Port, Offset, Data); +} + +void Vgm_Core::chip_reg_write(unsigned Sample, byte ChipType, byte ChipID, byte Port, byte Offset, byte Data) +{ + run_dac_control( Sample ); /* Let's get recursive! */ + ChipID = !!ChipID; + switch (ChipType) + { + case 0x02: + switch (Port) + { + case 0: + if ( Offset == ym2612_dac_port ) + { + write_pcm( Sample, ChipID, Data ); + } + else if ( run_ym2612( ChipID, to_fm_time( Sample ) ) ) + { + if ( Offset == 0x2B ) + { + dac_disabled[ChipID] = (Data >> 7 & 1) - 1; + dac_amp[ChipID] |= dac_disabled[ChipID]; + } + ym2612[ChipID].write0( Offset, Data ); + } + break; + + case 1: + if ( run_ym2612( ChipID, to_fm_time( Sample ) ) ) + { + if ( Offset == ym2612_dac_pan_port ) + { + Blip_Buffer * blip_buf = NULL; + switch ( Data >> 6 ) + { + case 0: blip_buf = NULL; break; + case 1: blip_buf = stereo_buf[0].right(); break; + case 2: blip_buf = stereo_buf[0].left(); break; + case 3: blip_buf = stereo_buf[0].center(); break; + } + /*if ( this->blip_buf != blip_buf ) + { + blip_time_t blip_time = to_psg_time( vgm_time ); + if ( this->blip_buf ) pcm.offset_inline( blip_time, -dac_amp, this->blip_buf ); + if ( blip_buf ) pcm.offset_inline( blip_time, dac_amp, blip_buf ); + }*/ + this->blip_buf[ChipID] = blip_buf; + } + ym2612[ChipID].write1( Offset, Data ); + } + break; + } + break; + + case 0x11: + if ( run_pwm( to_fm_time( Sample ) ) ) + pwm.write( Port, ( ( Offset ) << 8 ) + Data ); + break; + + case 0x00: + psg[ChipID].write_data( to_psg_time( Sample ), Data ); + break; + + case 0x01: + if ( run_ym2413( ChipID, to_fm_time( Sample ) ) ) + ym2413[ChipID].write( Offset, Data ); + break; + + case 0x03: + if ( run_ym2151( ChipID, to_fm_time( Sample ) ) ) + ym2151[ChipID].write( Offset, Data ); + break; + + case 0x06: + if ( run_ym2203( ChipID, to_fm_time( Sample ) ) ) + ym2203[ChipID].write( Offset, Data ); + break; + + case 0x07: + if ( run_ym2608( ChipID, to_fm_time( Sample ) ) ) + { + switch (Port) + { + case 0: ym2608[ChipID].write0( Offset, Data ); break; + case 1: ym2608[ChipID].write1( Offset, Data ); break; + } + } + break; + + case 0x08: + if ( run_ym2610( ChipID, to_fm_time( Sample ) ) ) + { + switch (Port) + { + case 0: ym2610[ChipID].write0( Offset, Data ); break; + case 1: ym2610[ChipID].write1( Offset, Data ); break; + } + } + break; + + case 0x09: + if ( run_ym3812( ChipID, to_fm_time( Sample ) ) ) + ym3812[ChipID].write( Offset, Data ); + break; + + case 0x0C: + if ( run_ymf262( ChipID, to_fm_time( Sample ) ) ) + { + switch (Port) + { + case 0: ymf262[ChipID].write0( Offset, Data ); break; + case 1: ymf262[ChipID].write1( Offset, Data ); break; + } + } + break; + + case 0x0F: + if ( run_ymz280b( to_fm_time( Sample ) ) ) + ymz280b.write( Offset, Data ); + break; + + case 0x12: + ay[ChipID].write_addr( Offset ); + ay[ChipID].write_data( to_ay_time( Sample ), Data ); + break; + + case 0x13: + gbdmg[ChipID].write_register( to_gbdmg_time( Sample ), 0xFF10 + Offset, Data ); + break; + + case 0x17: + if ( run_okim6258( ChipID, to_fm_time( Sample ) ) ) + okim6258[ChipID].write( Offset, Data ); + break; + + case 0x18: + if ( run_okim6295( ChipID, to_fm_time( Sample ) ) ) + okim6295[ChipID].write( Offset, Data ); + break; + + case 0x19: + if ( run_k051649( to_fm_time( Sample ) ) ) + k051649.write( Port, Offset, Data ); + break; + + case 0x1A: + if ( run_k054539( to_fm_time( Sample ) ) ) + k054539.write( ( Port << 8 ) | Offset, Data ); + break; + + case 0x1B: + huc6280[ChipID].write_data( to_huc6280_time( Sample ), 0x800 + Offset, Data ); + break; + + case 0x1D: + if ( run_k053260( to_fm_time( Sample ) ) ) + k053260.write( Offset, Data ); + break; + + case 0x1F: + if ( run_qsound( ChipID, Sample ) ) + qsound[ ChipID ].write( Data, ( Port << 8 ) + Offset ); + break; + } +} + +void Vgm_Core::set_tempo( double t ) +{ + if ( file_begin() ) + { + vgm_rate = (int) (44100 * t + 0.5); + blip_time_factor = (int) ((double) + (1 << blip_time_bits) / vgm_rate * stereo_buf[0].center()->clock_rate() + 0.5); + blip_ay_time_factor = (int) ((double) + (1 << blip_time_bits) / vgm_rate * stereo_buf[1].center()->clock_rate() + 0.5); + blip_huc6280_time_factor = (int) ((double) + (1 << blip_time_bits) / vgm_rate * stereo_buf[2].center()->clock_rate() + 0.5); + blip_gbdmg_time_factor = (int)((double) + (1 << blip_time_bits) / vgm_rate * stereo_buf[3].center()->clock_rate() + 0.5); + //dprintf( "blip_time_factor: %ld\n", blip_time_factor ); + //dprintf( "vgm_rate: %ld\n", vgm_rate ); + // TODO: remove? calculates vgm_rate more accurately (above differs at most by one Hz only) + //blip_time_factor = (int) floor( double (1 << blip_time_bits) * psg_rate_ / 44100 / t + 0.5 ); + //vgm_rate = (int) floor( double (1 << blip_time_bits) * psg_rate_ / blip_time_factor + 0.5 ); + + fm_time_factor = 2 + (int) (fm_rate * (1 << fm_time_bits) / vgm_rate + 0.5); + } +} + +bool Vgm_Core::header_t::valid_tag() const +{ + return !memcmp( tag, "Vgm ", 4 ); +} + +int Vgm_Core::header_t::size() const +{ + unsigned int version = get_le32( this->version ); + unsigned int data_offset; + if ( version >= 0x150 ) + { + data_offset = get_le32( this->data_offset ); + if ( data_offset ) data_offset += offsetof( header_t, data_offset ); + } + else data_offset = 0x40; + unsigned expected_size = ( version > 0x150 ) ? ( ( version > 0x160 ) ? unsigned(size_max) : unsigned(size_151) ) : unsigned(size_min); + if ( expected_size > data_offset ) expected_size = data_offset ? (data_offset > unsigned(size_max) ? unsigned(size_max) : data_offset) : unsigned(size_min); + return expected_size; +} + +void Vgm_Core::header_t::cleanup() +{ + unsigned int version = get_le32( this->version ); + + if ( size() < size_max ) memset( ((byte*)this) + size(), 0, size_max - size() ); + + if ( version < 0x161 ) + { + memset( this->gbdmg_rate, 0, size_max - offsetof(header_t, gbdmg_rate) ); + } + + if ( version < 0x160 ) + { + volume_modifier = 0; + reserved = 0; + loop_base = 0; + } + + if ( version < 0x151 ) memset( this->rf5c68_rate, 0, size_max - size_min ); + + if ( version < 0x150 ) + { + set_le32( data_offset, size_min - offsetof(header_t, data_offset) ); + sn76489_flags = 0; + set_le32( segapcm_rate, 0 ); + set_le32( segapcm_reg, 0 ); + } + + if ( version < 0x110 ) + { + set_le16( noise_feedback, 0 ); + noise_width = 0; + unsigned int rate = get_le32( ym2413_rate ); + set_le32( ym2612_rate, rate ); + set_le32( ym2151_rate, rate ); + } + + if ( version < 0x101 ) + { + set_le32( frame_rate, 0 ); + } +} + +blargg_err_t Vgm_Core::load_mem_( byte const data [], int size ) +{ + assert( offsetof (header_t, rf5c68_rate) == header_t::size_min ); + assert( offsetof (header_t, extra_offset[4]) == header_t::size_max ); + + if ( size <= header_t::size_min ) + return blargg_err_file_type; + + memcpy( &_header, data, header_t::size_min ); + + header_t const& h = header(); + + if ( !h.valid_tag() ) + return blargg_err_file_type; + + int version = get_le32( h.version ); + + check( version < 0x100 ); + + if ( version > 0x150 ) + { + if ( size < header().size() ) + return "Invalid header"; + + memcpy( &_header.rf5c68_rate, data + offsetof (header_t, rf5c68_rate), header().size() - header_t::size_min ); + } + + _header.cleanup(); + + // Get loop + loop_begin = file_end(); + if ( get_le32( h.loop_offset ) ) + loop_begin = &data [get_le32( h.loop_offset ) + offsetof (header_t,loop_offset)]; + + // PSG rate + int psg_rate = get_le32( h.psg_rate ) & 0x3FFFFFFF; + if ( !psg_rate ) + psg_rate = 3579545; + stereo_buf[0].clock_rate( psg_rate ); + + int ay_rate = get_le32( h.ay8910_rate ) & 0xBFFFFFFF; + if ( !ay_rate ) + ay_rate = 2000000; + stereo_buf[1].clock_rate( ay_rate * 2 ); + ay[0].set_type( (Ay_Apu::Ay_Apu_Type) header().ay8910_type ); + ay[1].set_type( (Ay_Apu::Ay_Apu_Type) header().ay8910_type ); + + int huc6280_rate = get_le32( h.huc6280_rate ) & 0xBFFFFFFF; + if ( !huc6280_rate ) + huc6280_rate = 3579545; + stereo_buf[2].clock_rate( huc6280_rate * 2 ); + + int gbdmg_rate = get_le32( h.gbdmg_rate ) & 0xBFFFFFFF; + if ( !gbdmg_rate ) + gbdmg_rate = Gb_Apu::clock_rate; + stereo_buf[3].clock_rate( gbdmg_rate ); + + // Disable FM + fm_rate = 0; + ymz280b.enable( false ); + ymf262[0].enable( false ); + ymf262[1].enable( false ); + ym3812[0].enable( false ); + ym3812[1].enable( false ); + ym2612[0].enable( false ); + ym2612[1].enable( false ); + ym2610[0].enable( false ); + ym2610[1].enable( false ); + ym2608[0].enable( false ); + ym2608[1].enable( false ); + ym2413[0].enable( false ); + ym2413[1].enable( false ); + ym2203[0].enable( false ); + ym2203[1].enable( false ); + ym2151[0].enable( false ); + ym2151[1].enable( false ); + c140.enable( false ); + segapcm.enable( false ); + rf5c68.enable( false ); + rf5c164.enable( false ); + pwm.enable( false ); + okim6258[0].enable( false ); + okim6258[1].enable( false ); + okim6295[0].enable( false ); + okim6295[1].enable( false ); + k051649.enable( false ); + k053260.enable( false ); + k054539.enable( false ); + qsound[0].enable( false ); + qsound[1].enable( false ); + + set_tempo( 1 ); + + return blargg_ok; +} + +// Update pre-1.10 header FM rates by scanning commands +void Vgm_Core::update_fm_rates( int* ym2151_rate, int* ym2413_rate, int* ym2612_rate ) const +{ + byte const* p = file_begin() + header().size(); + int data_offset = get_le32( header().data_offset ); + check( data_offset ); + if ( data_offset ) + p += data_offset + offsetof( header_t, data_offset ) - header().size(); + while ( p < file_end() ) + { + switch ( *p ) + { + case cmd_end: + return; + + case cmd_psg: + case cmd_byte_delay: + p += 2; + break; + + case cmd_delay: + p += 3; + break; + + case cmd_data_block: + p += 7 + get_le32( p + 3 ); + break; + + case cmd_ram_block: + p += 12; + break; + + case cmd_ym2413: + *ym2151_rate = 0; + *ym2612_rate = 0; + return; + + case cmd_ym2612_port0: + case cmd_ym2612_port1: + *ym2612_rate = *ym2413_rate; + *ym2413_rate = 0; + *ym2151_rate = 0; + return; + + case cmd_ym2151: + *ym2151_rate = *ym2413_rate; + *ym2413_rate = 0; + *ym2612_rate = 0; + return; + + default: + p += command_len( *p ); + } + } +} + +blargg_err_t Vgm_Core::init_chips( double* rate, bool reinit ) +{ + int ymz280b_rate = get_le32( header().ymz280b_rate ) & 0xBFFFFFFF; + int ymf262_rate = get_le32( header().ymf262_rate ) & 0xBFFFFFFF; + int ym3812_rate = get_le32( header().ym3812_rate ) & 0xBFFFFFFF; + int ym2612_rate = get_le32( header().ym2612_rate ) & 0xBFFFFFFF; + int ym2610_rate = get_le32( header().ym2610_rate ) & 0x3FFFFFFF; + int ym2608_rate = get_le32( header().ym2608_rate ) & 0x3FFFFFFF; + int ym2413_rate = get_le32( header().ym2413_rate ) & 0xBFFFFFFF; + int ym2203_rate = get_le32( header().ym2203_rate ) & 0xBFFFFFFF; + int ym2151_rate = get_le32( header().ym2151_rate ) & 0xBFFFFFFF; + int c140_rate = get_le32( header().c140_rate ) & 0xBFFFFFFF; + int segapcm_rate = get_le32( header().segapcm_rate ) & 0xBFFFFFFF; + int rf5c68_rate = get_le32( header().rf5c68_rate ) & 0xBFFFFFFF; + int rf5c164_rate = get_le32( header().rf5c164_rate ) & 0xBFFFFFFF; + int pwm_rate = get_le32( header().pwm_rate ) & 0xBFFFFFFF; + int okim6258_rate = get_le32( header().okim6258_rate ) & 0xBFFFFFFF; + int okim6295_rate = get_le32( header().okim6295_rate ) & 0xBFFFFFFF; + int k051649_rate = get_le32( header().k051649_rate ) & 0xBFFFFFFF; + int k053260_rate = get_le32( header().k053260_rate ) & 0xBFFFFFFF; + int k054539_rate = get_le32( header().k054539_rate ) & 0xBFFFFFFF; + int qsound_rate = get_le32( header().qsound_rate ) & 0xBFFFFFFF; + if ( ym2413_rate && get_le32( header().version ) < 0x110 ) + update_fm_rates( &ym2151_rate, &ym2413_rate, &ym2612_rate ); + + *rate = vgm_rate; + + if ( ymf262_rate ) + { + bool dual_chip = !!(header().ymf262_rate[3] & 0x40); + double gain = dual_chip ? 0.5 : 1.0; + double fm_rate = ymf262_rate / 288.0; + int result; + if ( !reinit ) + { + result = ymf262[0].set_rate( fm_rate, ymf262_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ymf262[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ymf262[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + result = ymf262[1].set_rate( fm_rate, ymf262_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ymf262[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ymf262[1].enable(); + } + } + if ( ym3812_rate ) + { + bool dual_chip = !!(header().ym3812_rate[3] & 0x40); + double gain = dual_chip ? 0.5 : 1.0; + double fm_rate = ym3812_rate / 72.0; + int result; + if ( !reinit ) + { + result = ym3812[0].set_rate( fm_rate, ym3812_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym3812[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym3812[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + result = ym3812[1].set_rate( fm_rate, ym3812_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym3812[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym3812[1].enable(); + } + } + if ( ym2612_rate ) + { + bool dual_chip = !!(header().ym2612_rate[3] & 0x40); + double gain = dual_chip ? 0.5 : 1.0; + double fm_rate = ym2612_rate / 144.0; + if ( !reinit ) + { + RETURN_ERR( ym2612[0].set_rate( fm_rate, ym2612_rate ) ); + } + RETURN_ERR( ym2612[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2612[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + RETURN_ERR( ym2612[1].set_rate( fm_rate, ym2612_rate ) ); + } + RETURN_ERR( ym2612[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2612[1].enable(); + } + } + if ( ym2610_rate ) + { + bool dual_chip = !!(header().ym2610_rate[3] & 0x40); + bool is_2610b = !!(header().ym2610_rate[3] & 0x80); + double gain = dual_chip ? 0.5 : 1.0; + double fm_rate = ym2610_rate / 72.0; + int result; + if ( !reinit ) + { + result = ym2610[0].set_rate( fm_rate, ym2610_rate, is_2610b ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym2610[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2610[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + result = ym2610[1].set_rate( fm_rate, ym2610_rate, is_2610b ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym2610[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2610[1].enable(); + } + } + if ( ym2608_rate ) + { + bool dual_chip = !!(header().ym2610_rate[3] & 0x40); + double gain = dual_chip ? 1.0 : 2.0; + double fm_rate = ym2608_rate / 72.0; + int result; + if ( !reinit ) + { + result = ym2608[0].set_rate( fm_rate, ym2608_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym2608[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2608[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + result = ym2608[1].set_rate( fm_rate, ym2608_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym2608[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2608[1].enable(); + } + } + if ( ym2413_rate ) + { + bool dual_chip = !!(header().ym2413_rate[3] & 0x40); + double gain = dual_chip ? 0.5 : 1.0; + double fm_rate = ym2413_rate / 72.0; + int result; + if ( !reinit ) + { + result = ym2413[0].set_rate( fm_rate, ym2413_rate ); + if ( result == 2 ) + return "YM2413 FM sound not supported"; + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym2413[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2413[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + result = ym2413[1].set_rate( fm_rate, ym2413_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym2413[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2413[1].enable(); + } + } + if ( ym2151_rate ) + { + bool dual_chip = !!(header().ym2151_rate[3] & 0x40); + double gain = dual_chip ? 0.5 : 1.0; + double fm_rate = ym2151_rate / 64.0; + int result; + if ( !reinit ) + { + result = ym2151[0].set_rate( fm_rate, ym2151_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym2151[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2151[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + result = ym2151[1].set_rate( fm_rate, ym2151_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( ym2151[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2151[1].enable(); + } + } + if ( ym2203_rate ) + { + bool dual_chip = !!(header().ym2203_rate[3] & 0x40); + double gain = dual_chip ? 0.5 : 1.0; + double fm_rate = ym2203_rate / 72.0; + int result; + if ( !reinit ) + { + result = ym2203[0].set_rate( fm_rate, ym2203_rate ); + CHECK_ALLOC ( !result ); + } + RETURN_ERR( ym2203[0].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2203[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + result = ym2203[1].set_rate( fm_rate, ym2203_rate ); + CHECK_ALLOC ( !result ); + } + RETURN_ERR( ym2203[1].setup( fm_rate / vgm_rate, 0.85, gain ) ); + ym2203[1].enable(); + } + } + + if ( segapcm_rate ) + { + double pcm_rate = segapcm_rate / 128.0; + if ( !reinit ) + { + int result = segapcm.set_rate( get_le32( header().segapcm_reg ) ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( segapcm.setup( pcm_rate / vgm_rate, 0.85, 1.5 ) ); + segapcm.enable(); + } + if ( rf5c68_rate ) + { + double pcm_rate = rf5c68_rate / 384.0; + if ( !reinit ) + { + int result = rf5c68.set_rate(); + CHECK_ALLOC( !result ); + } + RETURN_ERR( rf5c68.setup( pcm_rate / vgm_rate, 0.85, 0.6875 ) ); + rf5c68.enable(); + } + if ( rf5c164_rate ) + { + double pcm_rate = rf5c164_rate / 384.0; + if ( !reinit ) + { + int result = rf5c164.set_rate( rf5c164_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( rf5c164.setup( pcm_rate / vgm_rate, 0.85, 0.5 ) ); + rf5c164.enable(); + } + if ( pwm_rate ) + { + double pcm_rate = 22020.0; + if ( !reinit ) + { + int result = pwm.set_rate( pwm_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( pwm.setup( pcm_rate / vgm_rate, 0.85, 0.875 ) ); + pwm.enable(); + } + if ( okim6258_rate ) + { + bool dual_chip = !!( header().okim6258_rate[3] & 0x40 ); + if ( !reinit ) + { + okim6258_hz[0] = okim6258[0].set_rate( okim6258_rate, header().okim6258_flags & 0x03, ( header().okim6258_flags & 0x04 ) >> 2, ( header().okim6258_flags & 0x08 ) >> 3 ); + CHECK_ALLOC( okim6258_hz[0] ); + } + RETURN_ERR( okim6258[0].setup( (double)okim6258_hz[0] / vgm_rate, 0.85, 1.0 ) ); + okim6258[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + okim6258_hz[1] = okim6258[1].set_rate( okim6258_rate, header().okim6258_flags & 0x03, ( header().okim6258_flags & 0x04 ) >> 2, ( header().okim6258_flags & 0x08 ) >> 3 ); + CHECK_ALLOC( okim6258_hz[1] ); + } + RETURN_ERR( okim6258[1].setup( (double)okim6258_hz[1] / vgm_rate, 0.85, 1.0 ) ); + okim6258[1].enable(); + } + } + if ( okim6295_rate ) + { + // moo + Mem_File_Reader rdr( file_begin(), file_size() ); + Music_Emu * vgm = gme_vgm_type->new_info(); + track_info_t info; + vgm->load( rdr ); + vgm->track_info( &info, 0 ); + delete vgm; + + bool is_cp_system = strncmp( info.system, "CP", 2 ) == 0; + bool dual_chip = !!( header().okim6295_rate[3] & 0x40 ); + double gain = is_cp_system ? 0.4296875 : 1.0; + if ( dual_chip ) gain *= 0.5; + if ( !reinit ) + { + okim6295_hz = okim6295[0].set_rate( okim6295_rate ); + CHECK_ALLOC( okim6295_hz ); + } + RETURN_ERR( okim6295[0].setup( (double)okim6295_hz / vgm_rate, 0.85, gain ) ); + okim6295[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + int result = okim6295[1].set_rate( okim6295_rate ); + CHECK_ALLOC( result ); + } + RETURN_ERR( okim6295[1].setup( (double)okim6295_hz / vgm_rate, 0.85, gain ) ); + okim6295[1].enable(); + } + } + if ( c140_rate ) + { + double pcm_rate = c140_rate; + if ( !reinit ) + { + int result = c140.set_rate( header().c140_type, c140_rate, c140_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( c140.setup( pcm_rate / vgm_rate, 0.85, 1.0 ) ); + c140.enable(); + } + if ( k051649_rate ) + { + double pcm_rate = k051649_rate / 16.0; + if ( !reinit ) + { + int result = k051649.set_rate( k051649_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( k051649.setup( pcm_rate / vgm_rate, 0.85, 1.0 ) ); + k051649.enable(); + } + if ( k053260_rate ) + { + double pcm_rate = k053260_rate / 32.0; + if ( !reinit ) + { + int result = k053260.set_rate( k053260_rate ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( k053260.setup( pcm_rate / vgm_rate, 0.85, 1.0 ) ); + k053260.enable(); + } + if ( k054539_rate ) + { + double pcm_rate = k054539_rate; + if ( !reinit ) + { + int result = k054539.set_rate( k054539_rate, header().k054539_flags ); + CHECK_ALLOC( !result ); + } + RETURN_ERR( k054539.setup( pcm_rate / vgm_rate, 0.85, 1.0 ) ); + k054539.enable(); + } + if ( ymz280b_rate ) + { + if ( !reinit ) + { + ymz280b_hz = ymz280b.set_rate( ymz280b_rate ); + CHECK_ALLOC( ymz280b_hz ); + } + RETURN_ERR( ymz280b.setup( (double)ymz280b_hz / vgm_rate, 0.85, 0.59375 ) ); + ymz280b.enable(); + } + if ( qsound_rate ) + { + /*double pcm_rate = (double)qsound_rate / 166.0;*/ + if ( !reinit ) + { + int result = qsound[0].set_rate( qsound_rate ); + CHECK_ALLOC( result ); + } + qsound[0].set_sample_rate( vgm_rate ); + RETURN_ERR( qsound[0].setup( 1.0, 0.85, 1.0 ) ); + qsound[0].enable(); + } + + fm_rate = *rate; + + return blargg_ok; +} + +void Vgm_Core::start_track() +{ + psg[0].reset( get_le16( header().noise_feedback ), header().noise_width ); + psg[1].reset( get_le16( header().noise_feedback ), header().noise_width ); + ay[0].reset(); + ay[1].reset(); + huc6280[0].reset(); + huc6280[1].reset(); + gbdmg[0].reset(); + gbdmg[1].reset(); + + blip_buf[0] = stereo_buf[0].center(); + blip_buf[1] = blip_buf[0]; + + dac_disabled[0] = -1; + dac_disabled[1] = -1; + pos = file_begin() + header().size(); + dac_amp[0] = -1; + dac_amp[1] = -1; + vgm_time = 0; + int data_offset = get_le32( header().data_offset ); + check( data_offset ); + if ( data_offset ) + pos += data_offset + offsetof (header_t,data_offset) - header().size(); + pcm_pos = pos; + + if ( uses_fm() ) + { + if ( rf5c68.enabled() ) + rf5c68.reset(); + + if ( rf5c164.enabled() ) + rf5c164.reset(); + + if ( segapcm.enabled() ) + segapcm.reset(); + + if ( pwm.enabled() ) + pwm.reset(); + + if ( okim6258[0].enabled() ) + okim6258[0].reset(); + + if ( okim6258[1].enabled() ) + okim6258[1].reset(); + + if ( okim6295[0].enabled() ) + okim6295[0].reset(); + + if ( okim6295[1].enabled() ) + okim6295[1].reset(); + + if ( k051649.enabled() ) + k051649.reset(); + + if ( k053260.enabled() ) + k053260.reset(); + + if ( k054539.enabled() ) + k054539.reset(); + + if ( c140.enabled() ) + c140.reset(); + + if ( ym2151[0].enabled() ) + ym2151[0].reset(); + + if ( ym2151[1].enabled() ) + ym2151[1].reset(); + + if ( ym2203[0].enabled() ) + ym2203[0].reset(); + + if ( ym2203[1].enabled() ) + ym2203[1].reset(); + + if ( ym2413[0].enabled() ) + ym2413[0].reset(); + + if ( ym2413[1].enabled() ) + ym2413[1].reset(); + + if ( ym2612[0].enabled() ) + ym2612[0].reset(); + + if ( ym2612[1].enabled() ) + ym2612[1].reset(); + + if ( ym2610[0].enabled() ) + ym2610[0].reset(); + + if ( ym2610[1].enabled() ) + ym2610[1].reset(); + + if ( ym2608[0].enabled() ) + ym2608[0].reset(); + + if ( ym2608[1].enabled() ) + ym2608[1].reset(); + + if ( ym3812[0].enabled() ) + ym3812[0].reset(); + + if ( ym3812[1].enabled() ) + ym3812[1].reset(); + + if ( ymf262[0].enabled() ) + ymf262[0].reset(); + + if ( ymf262[1].enabled() ) + ymf262[1].reset(); + + if ( ymz280b.enabled() ) + ymz280b.reset(); + + if ( qsound[0].enabled() ) + qsound[0].reset(); + + if ( qsound[1].enabled() ) + qsound[1].reset(); + + stereo_buf[0].clear(); + stereo_buf[1].clear(); + stereo_buf[2].clear(); + stereo_buf[3].clear(); + } + + for ( unsigned i = 0; i < DacCtrlUsed; i++ ) + { + device_reset_daccontrol( dac_control [i] ); + DacCtrlTime[DacCtrlMap[i]] = 0; + } + + for ( unsigned i = 0; i < PCM_BANK_COUNT; i++) + { + // reset PCM Bank, but not the data + // (this way I don't need to decompress the data again when restarting) + PCMBank [i].DataPos = 0; + PCMBank [i].BnkPos = 0; + } + PCMTbl.EntryCount = 0; + + fm_time_offset = 0; + ay_time_offset = 0; + huc6280_time_offset = 0; + gbdmg_time_offset = 0; + + dac_control_recursion = 0; +} + +inline Vgm_Core::fm_time_t Vgm_Core::to_fm_time( vgm_time_t t ) const +{ + return (t * fm_time_factor + fm_time_offset) >> fm_time_bits; +} + +inline blip_time_t Vgm_Core::to_psg_time( vgm_time_t t ) const +{ + return (t * blip_time_factor) >> blip_time_bits; +} + +inline blip_time_t Vgm_Core::to_ay_time( vgm_time_t t ) const +{ + return (t * blip_ay_time_factor) >> blip_time_bits; +} + +inline blip_time_t Vgm_Core::to_huc6280_time( vgm_time_t t ) const +{ + return (t * blip_huc6280_time_factor) >> blip_time_bits; +} + +inline blip_time_t Vgm_Core::to_gbdmg_time( vgm_time_t t ) const +{ + return (t * blip_gbdmg_time_factor) >> blip_time_bits; +} + +void Vgm_Core::write_pcm( vgm_time_t vgm_time, int chip, int amp ) +{ + chip = !!chip; + if ( blip_buf[chip] ) + { + check( amp >= 0 ); + blip_time_t blip_time = to_psg_time( vgm_time ); + int old = dac_amp[chip]; + int delta = amp - old; + dac_amp[chip] = amp; + blip_buf[chip]->set_modified(); + if ( old >= 0 ) // first write is ignored, to avoid click + pcm.offset_inline( blip_time, delta, blip_buf[chip] ); + else + dac_amp[chip] |= dac_disabled[chip]; + } +} + +blip_time_t Vgm_Core::run( vgm_time_t end_time ) +{ + vgm_time_t vgm_time = this->vgm_time; + vgm_time_t vgm_loop_time = ~0; + int ChipID; + byte const* pos = this->pos; + if ( pos > file_end() ) + set_warning( "Stream lacked end event" ); + + while ( vgm_time < end_time && pos < file_end() ) + { + // TODO: be sure there are enough bytes left in stream for particular command + // so we don't read past end + switch ( *pos++ ) + { + case cmd_end: + if ( vgm_loop_time == ~0 ) vgm_loop_time = vgm_time; + else if ( vgm_loop_time == vgm_time ) loop_begin = file_end(); // XXX some files may loop forever on a region without any delay commands + pos = loop_begin; // if not looped, loop_begin == file_end() + if ( pos != file_end() ) has_looped = true; + break; + + case cmd_delay_735: + vgm_time += 735; + break; + + case cmd_delay_882: + vgm_time += 882; + break; + + case cmd_gg_stereo: + psg[0].write_ggstereo( to_psg_time( vgm_time ), *pos++ ); + break; + + case cmd_gg_stereo_2: + psg[1].write_ggstereo( to_psg_time( vgm_time ), *pos++ ); + break; + + case cmd_psg: + psg[0].write_data( to_psg_time( vgm_time ), *pos++ ); + break; + + case cmd_psg_2: + psg[1].write_data( to_psg_time( vgm_time ), *pos++ ); + break; + + case cmd_ay8910: + ChipID = !!(pos [0] & 0x80); + chip_reg_write( vgm_time, 0x12, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); + pos += 2; + break; + + case cmd_delay: + vgm_time += pos [1] * 0x100 + pos [0]; + pos += 2; + break; + + case cmd_byte_delay: + vgm_time += *pos++; + break; + + case cmd_segapcm_write: + if ( get_le32( header().segapcm_rate ) > 0 ) + if ( run_segapcm( to_fm_time( vgm_time ) ) ) + segapcm.write( get_le16( pos ), pos [2] ); + pos += 3; + break; + + case cmd_rf5c68: + if ( run_rf5c68( to_fm_time( vgm_time ) ) ) + rf5c68.write( pos [0], pos [1] ); + pos += 2; + break; + + case cmd_rf5c68_mem: + if ( run_rf5c68( to_fm_time( vgm_time ) ) ) + rf5c68.write_mem( get_le16( pos ), pos [2] ); + pos += 3; + break; + + case cmd_rf5c164: + if ( run_rf5c164( to_fm_time( vgm_time ) ) ) + rf5c164.write( pos [0], pos [1] ); + pos += 2; + break; + + case cmd_rf5c164_mem: + if ( run_rf5c164( to_fm_time( vgm_time ) ) ) + rf5c164.write_mem( get_le16( pos ), pos [2] ); + pos += 3; + break; + + case cmd_pwm: + chip_reg_write( vgm_time, 0x11, 0x00, pos [0] >> 4, pos [0] & 0x0F, pos [1] ); + pos += 2; + break; + + case cmd_c140: + if ( get_le32( header().c140_rate ) > 0 ) + if ( run_c140( to_fm_time( vgm_time ) ) ) + c140.write( get_be16( pos ), pos [2] ); + pos += 3; + break; + + case cmd_ym2151: + chip_reg_write( vgm_time, 0x03, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2151_2: + chip_reg_write( vgm_time, 0x03, 0x01, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2203: + chip_reg_write( vgm_time, 0x06, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2203_2: + chip_reg_write( vgm_time, 0x06, 0x01, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2413: + chip_reg_write( vgm_time, 0x01, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2413_2: + chip_reg_write( vgm_time, 0x01, 0x01, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym3812: + chip_reg_write( vgm_time, 0x09, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym3812_2: + chip_reg_write( vgm_time, 0x09, 0x01, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ymf262_port0: + chip_reg_write( vgm_time, 0x0C, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ymf262_2_port0: + chip_reg_write( vgm_time, 0x0C, 0x01, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ymf262_port1: + chip_reg_write( vgm_time, 0x0C, 0x00, 0x01, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ymf262_2_port1: + chip_reg_write( vgm_time, 0x0C, 0x01, 0x01, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ymz280b: + chip_reg_write( vgm_time, 0x0F, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2612_port0: + chip_reg_write( vgm_time, 0x02, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2612_2_port0: + chip_reg_write( vgm_time, 0x02, 0x01, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2612_port1: + chip_reg_write( vgm_time, 0x02, 0x00, 0x01, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2612_2_port1: + chip_reg_write( vgm_time, 0x02, 0x01, 0x01, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2610_port0: + chip_reg_write( vgm_time, 0x08, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2610_2_port0: + chip_reg_write( vgm_time, 0x08, 0x01, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2610_port1: + chip_reg_write( vgm_time, 0x08, 0x00, 0x01, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2610_2_port1: + chip_reg_write( vgm_time, 0x08, 0x01, 0x01, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2608_port0: + chip_reg_write( vgm_time, 0x07, 0x00, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2608_2_port0: + chip_reg_write( vgm_time, 0x07, 0x01, 0x00, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2608_port1: + chip_reg_write( vgm_time, 0x07, 0x00, 0x01, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_ym2608_2_port1: + chip_reg_write( vgm_time, 0x07, 0x01, 0x01, pos [0], pos [1] ); + pos += 2; + break; + + case cmd_okim6258_write: + chip_reg_write( vgm_time, 0x17, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); + pos += 2; + break; + + case cmd_okim6295_write: + ChipID = (pos [0] & 0x80) ? 1 : 0; + chip_reg_write( vgm_time, 0x18, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); + pos += 2; + break; + + case cmd_huc6280_write: + ChipID = (pos [0] & 0x80) ? 1 : 0; + chip_reg_write( vgm_time, 0x1B, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); + pos += 2; + break; + + case cmd_gbdmg_write: + ChipID = (pos [0] & 0x80) ? 1 : 0; + chip_reg_write( vgm_time, 0x13, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); + pos += 2; + break; + + case cmd_k051649_write: + chip_reg_write( vgm_time, 0x19, 0x00, pos [0] & 0x7F, pos [1], pos [2] ); + pos += 3; + break; + + case cmd_k053260_write: + chip_reg_write( vgm_time, 0x1D, 0x00, 0x00, pos [0] & 0x7F, pos [1] ); + pos += 2; + break; + + case cmd_k054539_write: + chip_reg_write( vgm_time, 0x1A, 0x00, pos [0] & 0x7F, pos [1], pos [2] ); + pos += 3; + break; + + case cmd_qsound_write: + chip_reg_write( vgm_time, 0x1F, 0x00, pos [0], pos [1], pos [2] ); + pos += 3; + break; + + case cmd_dacctl_setup: + if ( run_dac_control( vgm_time ) ) + { + unsigned chip = pos [0]; + if ( chip < 0xFF ) + { + if ( ! DacCtrl [chip].Enable ) + { + dac_control_grow( chip ); + DacCtrl [chip].Enable = true; + } + daccontrol_setup_chip( dac_control [DacCtrlMap [chip]], pos [1] & 0x7F, ( pos [1] & 0x80 ) >> 7, get_be16( pos + 2 ) ); + } + } + pos += 4; + break; + + case cmd_dacctl_data: + if ( run_dac_control( vgm_time ) ) + { + unsigned chip = pos [0]; + if ( chip < 0xFF && DacCtrl [chip].Enable ) + { + DacCtrl [chip].Bank = pos [1]; + if ( DacCtrl [chip].Bank >= 0x40 ) + DacCtrl [chip].Bank = 0x00; + + VGM_PCM_BANK * TempPCM = &PCMBank [DacCtrl [chip].Bank]; + daccontrol_set_data( dac_control [DacCtrlMap [chip]], TempPCM->Data, TempPCM->DataSize, pos [2], pos [3] ); + } + } + pos += 4; + break; + case cmd_dacctl_freq: + if ( run_dac_control( vgm_time ) ) + { + unsigned chip = pos [0]; + if ( chip < 0xFF && DacCtrl [chip].Enable ) + { + daccontrol_set_frequency( dac_control [DacCtrlMap [chip]], get_le32( pos + 1 ) ); + } + } + pos += 5; + break; + case cmd_dacctl_play: + if ( run_dac_control( vgm_time ) ) + { + unsigned chip = pos [0]; + if ( chip < 0xFF && DacCtrl [chip].Enable && PCMBank [DacCtrl [chip].Bank].BankCount ) + { + daccontrol_start( dac_control [DacCtrlMap [chip]], get_le32( pos + 1 ), pos [5], get_le32( pos + 6 ) ); + } + } + pos += 10; + break; + case cmd_dacctl_stop: + if ( run_dac_control( vgm_time ) ) + { + unsigned chip = pos [0]; + if ( chip < 0xFF && DacCtrl [chip].Enable ) + { + daccontrol_stop( dac_control [DacCtrlMap [chip]] ); + } + else if ( chip == 0xFF ) + { + for ( unsigned i = 0; i < DacCtrlUsed; i++ ) + { + daccontrol_stop( dac_control [i] ); + } + } + } + pos++; + break; + case cmd_dacctl_playblock: + if ( run_dac_control( vgm_time ) ) + { + unsigned chip = pos [0]; + if ( chip < 0xFF && DacCtrl [chip].Enable && PCMBank [DacCtrl [chip].Bank].BankCount ) + { + VGM_PCM_BANK * TempPCM = &PCMBank [DacCtrl [chip].Bank]; + unsigned block_number = get_le16( pos + 1 ); + if ( block_number >= TempPCM->BankCount ) + block_number = 0; + VGM_PCM_DATA * TempBnk = &TempPCM->Bank [block_number]; + unsigned flags = DCTRL_LMODE_BYTES | ((pos [4] & 1) << 7); + daccontrol_start( dac_control [DacCtrlMap [chip]], TempBnk->DataStart, flags, TempBnk->DataSize ); + } + } + pos += 4; + break; + + case cmd_data_block: { + check( *pos == cmd_end ); + int type = pos [1]; + int size = get_le32( pos + 2 ); + int chipid = 0; + if ( size & 0x80000000 ) + { + size &= 0x7FFFFFFF; + chipid = 1; + } + pos += 6; + switch ( type & 0xC0 ) + { + case pcm_block_type: + case pcm_aux_block_type: + AddPCMData( type, size, pos ); + break; + + case rom_block_type: + if ( size >= 8 ) + { + int rom_size = get_le32( pos ); + int data_start = get_le32( pos + 4 ); + int data_size = size - 8; + void * rom_data = ( void * ) ( pos + 8 ); + + switch ( type ) + { + case rom_segapcm: + if ( segapcm.enabled() ) + segapcm.write_rom( rom_size, data_start, data_size, rom_data ); + break; + + case rom_ym2608_deltat: + if ( ym2608[chipid].enabled() ) + { + ym2608[chipid].write_rom( 0x02, rom_size, data_start, data_size, rom_data ); + } + break; + + case rom_ym2610_adpcm: + case rom_ym2610_deltat: + if ( ym2610[chipid].enabled() ) + { + int rom_id = 0x01 + ( type - rom_ym2610_adpcm ); + ym2610[chipid].write_rom( rom_id, rom_size, data_start, data_size, rom_data ); + } + break; + + case rom_ymz280b: + if ( ymz280b.enabled() ) + ymz280b.write_rom( rom_size, data_start, data_size, rom_data ); + break; + + case rom_okim6295: + if ( okim6295[chipid].enabled() ) + okim6295[chipid].write_rom( rom_size, data_start, data_size, rom_data ); + break; + + case rom_k054539: + if ( k054539.enabled() ) + k054539.write_rom( rom_size, data_start, data_size, rom_data ); + break; + + case rom_c140: + if ( c140.enabled() ) + c140.write_rom( rom_size, data_start, data_size, rom_data ); + break; + + case rom_k053260: + if ( k053260.enabled() ) + k053260.write_rom( rom_size, data_start, data_size, rom_data ); + break; + + case rom_qsound: + if ( qsound[chipid].enabled() ) + qsound[chipid].write_rom( rom_size, data_start, data_size, rom_data ); + break; + } + } + break; + + case ram_block_type: + if ( size >= 2 ) + { + int data_start = get_le16( pos ); + int data_size = size - 2; + void * ram_data = ( void * ) ( pos + 2 ); + + switch ( type ) + { + case ram_rf5c68: + if ( rf5c68.enabled() ) + rf5c68.write_ram( data_start, data_size, ram_data ); + break; + + case ram_rf5c164: + if ( rf5c164.enabled() ) + rf5c164.write_ram( data_start, data_size, ram_data ); + break; + } + } + break; + } + pos += size; + break; + } + + case cmd_ram_block: { + check( *pos == cmd_end ); + int type = pos[ 1 ]; + int data_start = get_le24( pos + 2 ); + int data_addr = get_le24( pos + 5 ); + int data_size = get_le24( pos + 8 ); + if ( !data_size ) data_size += 0x01000000; + void * data_ptr = (void *) GetPointerFromPCMBank( type, data_start ); + switch ( type ) + { + case rf5c68_ram_block: + if ( rf5c68.enabled() ) + rf5c68.write_ram( data_addr, data_size, data_ptr ); + break; + + case rf5c164_ram_block: + if ( rf5c164.enabled() ) + rf5c164.write_ram( data_addr, data_size, data_ptr ); + break; + } + pos += 11; + break; + } + + case cmd_pcm_seek: + pcm_pos = GetPointerFromPCMBank( 0, get_le32( pos ) ); + pos += 4; + break; + + default: + int cmd = pos [-1]; + switch ( cmd & 0xF0 ) + { + case cmd_pcm_delay: + chip_reg_write( vgm_time, 0x02, 0x00, 0x00, ym2612_dac_port, *pcm_pos++ ); + vgm_time += cmd & 0x0F; + break; + + case cmd_short_delay: + vgm_time += (cmd & 0x0F) + 1; + break; + + case 0x50: + pos += 2; + break; + + default: + pos += command_len( cmd ) - 1; + set_warning( "Unknown stream event" ); + } + } + } + vgm_time -= end_time; + this->pos = pos; + this->vgm_time = vgm_time; + + return to_psg_time( end_time ); +} + +blip_time_t Vgm_Core::run_psg( int msec ) +{ + blip_time_t t = run( msec * vgm_rate / 1000 ); + psg[0].end_frame( t ); + psg[1].end_frame( t ); + return t; +} + +int Vgm_Core::play_frame( blip_time_t blip_time, int sample_count, blip_sample_t out [] ) +{ + // to do: timing is working mostly by luck + int min_pairs = (unsigned) sample_count / 2; + int vgm_time = (min_pairs << fm_time_bits) / fm_time_factor - 1; + assert( to_fm_time( vgm_time ) <= min_pairs ); + int pairs; + while ( (pairs = to_fm_time( vgm_time )) < min_pairs ) + vgm_time++; + //dprintf( "pairs: %d, min_pairs: %d\n", pairs, min_pairs ); + + memset( out, 0, pairs * stereo * sizeof *out ); + + if ( ymf262[0].enabled() ) + { + ymf262[0].begin_frame( out ); + if ( ymf262[1].enabled() ) + { + ymf262[1].begin_frame( out ); + } + } + if ( ym3812[0].enabled() ) + { + ym3812[0].begin_frame( out ); + if ( ym3812[1].enabled() ) + { + ym3812[1].begin_frame( out ); + } + } + if ( ym2612[0].enabled() ) + { + ym2612[0].begin_frame( out ); + if ( ym2612[1].enabled() ) + { + ym2612[1].begin_frame( out ); + } + } + if ( ym2610[0].enabled() ) + { + ym2610[0].begin_frame( out ); + if ( ym2610[1].enabled() ) + { + ym2610[1].begin_frame( out ); + } + } + if ( ym2608[0].enabled() ) + { + ym2608[0].begin_frame( out ); + if ( ym2608[1].enabled() ) + { + ym2608[1].begin_frame( out ); + } + } + if ( ym2413[0].enabled() ) + { + ym2413[0].begin_frame( out ); + if ( ym2413[1].enabled() ) + { + ym2413[1].begin_frame( out ); + } + } + if ( ym2203[0].enabled() ) + { + ym2203[0].begin_frame( out ); + if ( ym2203[1].enabled() ) + { + ym2203[1].begin_frame( out ); + } + } + if ( ym2151[0].enabled() ) + { + ym2151[0].begin_frame( out ); + if ( ym2151[1].enabled() ) + { + ym2151[1].begin_frame( out ); + } + } + + if ( c140.enabled() ) + { + c140.begin_frame( out ); + } + if ( segapcm.enabled() ) + { + segapcm.begin_frame( out ); + } + if ( rf5c68.enabled() ) + { + rf5c68.begin_frame( out ); + } + if ( rf5c164.enabled() ) + { + rf5c164.begin_frame( out ); + } + if ( pwm.enabled() ) + { + pwm.begin_frame( out ); + } + if ( okim6258[0].enabled() ) + { + okim6258[0].begin_frame( out ); + if ( okim6258[1].enabled() ) + { + okim6258[1].begin_frame( out ); + } + } + if ( okim6295[0].enabled() ) + { + okim6295[0].begin_frame( out ); + if ( okim6295[1].enabled() ) + { + okim6295[1].begin_frame( out ); + } + } + if ( k051649.enabled() ) + { + k051649.begin_frame( out ); + } + if ( k053260.enabled() ) + { + k053260.begin_frame( out ); + } + if ( k054539.enabled() ) + { + k054539.begin_frame( out ); + } + if ( ymz280b.enabled() ) + { + ymz280b.begin_frame( out ); + } + if ( qsound[0].enabled() ) + { + qsound[0].begin_frame( out ); + if ( qsound[1].enabled() ) + { + qsound[1].begin_frame( out ); + } + } + + run( vgm_time ); + + run_dac_control( vgm_time ); + + run_ymf262( 0, pairs ); run_ymf262( 1, pairs ); + run_ym3812( 0, pairs ); run_ym3812( 1, pairs ); + run_ym2612( 0, pairs ); run_ym2612( 1, pairs ); + run_ym2610( 0, pairs ); run_ym2610( 1, pairs ); + run_ym2608( 0, pairs ); run_ym2608( 1, pairs ); + run_ym2413( 0, pairs ); run_ym2413( 1, pairs ); + run_ym2203( 0, pairs ); run_ym2203( 1, pairs ); + run_ym2151( 0, pairs ); run_ym2151( 1, pairs ); + run_c140( pairs ); + run_segapcm( pairs ); + run_rf5c68( pairs ); + run_rf5c164( pairs ); + run_pwm( pairs ); + run_okim6258( 0, pairs ); run_okim6258( 1, pairs ); + run_okim6295( 0, pairs ); run_okim6295( 1, pairs ); + run_k051649( pairs ); + run_k053260( pairs ); + run_k054539( pairs ); + run_ymz280b( pairs ); + run_qsound( 0, pairs ); run_qsound( 1, pairs ); + + fm_time_offset = (vgm_time * fm_time_factor + fm_time_offset) - (pairs << fm_time_bits); + + psg[0].end_frame( blip_time ); + psg[1].end_frame( blip_time ); + + ay_time_offset = (vgm_time * blip_ay_time_factor + ay_time_offset) - (pairs << blip_time_bits); + + blip_time_t ay_end_time = to_ay_time( vgm_time ); + ay[0].end_frame( ay_end_time ); + ay[1].end_frame( ay_end_time ); + + huc6280_time_offset = (vgm_time * blip_huc6280_time_factor + huc6280_time_offset) - (pairs << blip_time_bits); + + blip_time_t huc6280_end_time = to_huc6280_time( vgm_time ); + huc6280[0].end_frame( huc6280_end_time ); + huc6280[1].end_frame( huc6280_end_time ); + + gbdmg_time_offset = (vgm_time * blip_gbdmg_time_factor + gbdmg_time_offset) - (pairs << blip_time_bits); + + blip_time_t gbdmg_end_time = to_gbdmg_time( vgm_time ); + gbdmg[0].end_frame( gbdmg_end_time ); + gbdmg[1].end_frame( gbdmg_end_time ); + + memset( DacCtrlTime, 0, sizeof(DacCtrlTime) ); + + return pairs * stereo; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Vgm_Core.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Vgm_Core.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Vgm_Core.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Vgm_Core.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,353 +1,353 @@ -// Sega VGM music file emulator core - -// Game_Music_Emu $vers -#ifndef VGM_CORE_H -#define VGM_CORE_H - -#include "Gme_Loader.h" -#include "Ymz280b_Emu.h" -#include "Ymf262_Emu.h" -#include "Ym2612_Emu.h" -#include "Ym2610b_Emu.h" -#include "Ym2608_Emu.h" -#include "Ym3812_Emu.h" -#include "Ym2413_Emu.h" -#include "Ym2151_Emu.h" -#include "C140_Emu.h" -#include "SegaPcm_Emu.h" -#include "Rf5C68_Emu.h" -#include "Rf5C164_Emu.h" -#include "Pwm_Emu.h" -#include "Okim6258_Emu.h" -#include "Okim6295_Emu.h" -#include "K051649_Emu.h" -#include "K053260_Emu.h" -#include "K054539_Emu.h" -#include "Qsound_Apu.h" -#include "Ym2203_Emu.h" -#include "Ay_Apu.h" -#include "Gb_Apu.h" -#include "Hes_Apu.h" -#include "Sms_Apu.h" -#include "Multi_Buffer.h" -#include "Chip_Resampler.h" - - template - class Chip_Emu : public Emu { - int last_time; - short* out; - enum { disabled_time = -1 }; - public: - Chip_Emu() { last_time = disabled_time; out = NULL; } - void enable( bool b = true ) { last_time = b ? 0 : disabled_time; } - bool enabled() const { return last_time != disabled_time; } - void begin_frame( short* buf ) { out = buf; last_time = 0; } - - int run_until( int time ) - { - int count = time - last_time; - if ( count > 0 ) - { - if ( last_time < 0 ) - return false; - last_time = time; - short* p = out; - out += count * Emu::out_chan_count; - Emu::run( count, p ); - } - return true; - } - }; - -class Vgm_Core : public Gme_Loader { -public: - - // VGM file header - struct header_t - { - enum { size_min = 0x40 }; - enum { size_151 = 0x80 }; - enum { size_max = 0xC0 }; - - char tag [4]; // 0x00 - byte data_size [4]; // 0x04 - byte version [4]; // 0x08 - byte psg_rate [4]; // 0x0C - byte ym2413_rate [4]; // 0x10 - byte gd3_offset [4]; // 0x14 - byte track_duration [4]; // 0x18 - byte loop_offset [4]; // 0x1C - byte loop_duration [4]; // 0x20 - byte frame_rate [4]; // 0x24 v1.01 V - byte noise_feedback [2]; // 0x28 v1.10 V - byte noise_width; // 0x2A - byte sn76489_flags; // 0x2B v1.51 < - byte ym2612_rate [4]; // 0x2C v1.10 V - byte ym2151_rate [4]; // 0x30 - byte data_offset [4]; // 0x34 v1.50 V - byte segapcm_rate [4]; // 0x38 v1.51 V - byte segapcm_reg [4]; // 0x3C - byte rf5c68_rate [4]; // 0x40 - byte ym2203_rate [4]; // 0x44 - byte ym2608_rate [4]; // 0x48 - byte ym2610_rate [4]; // 0x4C - byte ym3812_rate [4]; // 0x50 - byte ym3526_rate [4]; // 0x54 - byte y8950_rate [4]; // 0x58 - byte ymf262_rate [4]; // 0x5C - byte ymf278b_rate [4]; // 0x60 - byte ymf271_rate [4]; // 0x64 - byte ymz280b_rate [4]; // 0x68 - byte rf5c164_rate [4]; // 0x6C - byte pwm_rate [4]; // 0x70 - byte ay8910_rate [4]; // 0x74 - byte ay8910_type; // 0x78 - byte ay8910_flags; // 0x79 - byte ym2203_ay8910_flags;// 0x7A - byte ym2608_ay8910_flags;// 0x7B - byte volume_modifier; // 0x7C v1.60 V - byte reserved; // 0x7D - byte loop_base; // 0x7E - byte loop_modifier; // 0x7F v1.51 < - byte gbdmg_rate [4]; // 0x80 v1.61 V - byte nesapu_rate [4]; // 0x84 - byte multipcm_rate [4]; // 0x88 - byte upd7759_rate [4]; // 0x8C - byte okim6258_rate [4]; // 0x90 - byte okim6258_flags; // 0x94 - byte k054539_flags; // 0x95 - byte c140_type; // 0x96 - byte reserved_flags; // 0x97 - byte okim6295_rate [4]; // 0x98 - byte k051649_rate [4]; // 0x9C - byte k054539_rate [4]; // 0xA0 - byte huc6280_rate [4]; // 0xA4 - byte c140_rate [4]; // 0xA8 - byte k053260_rate [4]; // 0xAC - byte pokey_rate [4]; // 0xB0 - byte qsound_rate [4]; // 0xB4 - byte reserved2 [4]; // 0xB8 - byte extra_offset [4]; // 0xBC - - // True if header has valid file signature - bool valid_tag() const; - int size() const; - void cleanup(); - }; - - // Header for currently loaded file - header_t const& header() const { return _header; } - - // Raw file data, for parsing GD3 tags - byte const* file_begin() const { return Gme_Loader::file_begin(); } - byte const* file_end () const { return Gme_Loader::file_end(); } - - // If file uses FM, initializes FM sound emulator using *sample_rate. If - // *sample_rate is zero, sets *sample_rate to the proper accurate rate and - // uses that. The output of the FM sound emulator is resampled to the - // final sampling rate. - blargg_err_t init_chips( double* fm_rate, bool reinit = false ); - - // True if any FM chips are used by file. Always false until init_fm() - // is called. - bool uses_fm() const { return ym2612[0].enabled() || ym2413[0].enabled() || ym2151[0].enabled() || c140.enabled() || - segapcm.enabled() || rf5c68.enabled() || rf5c164.enabled() || pwm.enabled() || okim6258[0].enabled() || okim6295[0].enabled() || - k051649.enabled() || k053260.enabled() || k054539.enabled() || ym2203[0].enabled() || ym3812[0].enabled() || ymf262[0].enabled() || - ymz280b.enabled() || ym2610[0].enabled() || ym2608[0].enabled() || qsound[0].enabled() || - (header().ay8910_rate[0] | header().ay8910_rate[1] | header().ay8910_rate[2] | header().ay8910_rate[3]) || - (header().huc6280_rate[0] | header().huc6280_rate[1] | header().huc6280_rate[2] | header().huc6280_rate[3]) || - (header().gbdmg_rate[0] | header().gbdmg_rate[1] | header().gbdmg_rate[2] | header().gbdmg_rate[3]); } - - // Adjusts music tempo, where 1.0 is normal. Can be changed while playing. - // Loading a file resets tempo to 1.0. - void set_tempo( double ); - - void set_sample_rate( int r ) { sample_rate = r; } - - // Starts track - void start_track(); - - // Runs PSG-only VGM for msec and returns number of clocks it ran for - blip_time_t run_psg( int msec ); - - // Plays FM for at most count samples into *out, and returns number of - // samples actually generated (always even). Also runs PSG for blip_time. - int play_frame( blip_time_t blip_time, int count, blip_sample_t out [] ); - - // True if all of file data has been played - bool track_ended() const { return pos >= file_end(); } - - // 0 for PSG and YM2612 DAC, 1 for AY, 2 for HuC6280, 3 for GB DMG - Stereo_Buffer stereo_buf[4]; - - // PCM sound is always generated here - Blip_Buffer * blip_buf[2]; - - // PSG sound chips, for assigning to Blip_Buffer, and setting volume and EQ - Sms_Apu psg[2]; - Ay_Apu ay[2]; - Hes_Apu huc6280[2]; - Gb_Apu gbdmg[2]; - - // PCM synth, for setting volume and EQ - Blip_Synth_Fast pcm; - - // FM sound chips - Chip_Resampler_Emu ymf262[2]; - Chip_Resampler_Emu ym3812[2]; - Chip_Resampler_Emu ym2612[2]; - Chip_Resampler_Emu ym2610[2]; - Chip_Resampler_Emu ym2608[2]; - Chip_Resampler_Emu ym2413[2]; - Chip_Resampler_Emu ym2151[2]; - Chip_Resampler_Emu ym2203[2]; - - // PCM sound chips - Chip_Resampler_Emu c140; - Chip_Resampler_Emu segapcm; - Chip_Resampler_Emu rf5c68; - Chip_Resampler_Emu rf5c164; - Chip_Resampler_Emu pwm; - Chip_Resampler_Emu okim6258[2]; int okim6258_hz[2]; - Chip_Resampler_Emu okim6295[2]; int okim6295_hz; - Chip_Resampler_Emu k051649; - Chip_Resampler_Emu k053260; - Chip_Resampler_Emu k054539; - Chip_Resampler_Emu ymz280b; int ymz280b_hz; - Chip_Resampler_Emu qsound[2]; - - // DAC control - typedef struct daccontrol_data - { - bool Enable; - byte Bank; - } DACCTRL_DATA; - - byte DacCtrlUsed; - byte DacCtrlUsg[0xFF]; - DACCTRL_DATA DacCtrl[0xFF]; - byte DacCtrlMap[0xFF]; - int DacCtrlTime[0xFF]; - void ** dac_control; - - void dac_control_grow(byte chip_id); - - int dac_control_recursion; - - int run_dac_control( int time ); - -public: - void chip_reg_write(unsigned Sample, byte ChipType, byte ChipID, byte Port, byte Offset, byte Data); - -// Implementation -public: - Vgm_Core(); - ~Vgm_Core(); - -protected: - virtual blargg_err_t load_mem_( byte const [], int ); - -private: - // blip_time_t // PSG clocks - typedef int vgm_time_t; // 44100 per second, REGARDLESS of sample rate - typedef int fm_time_t; // FM sample count - - int sample_rate; - int vgm_rate; // rate of log, 44100 normally, adjusted by tempo - double fm_rate; // FM samples per second - - header_t _header; - - // VGM to FM time - int fm_time_factor; - int fm_time_offset; - fm_time_t to_fm_time( vgm_time_t ) const; - - // VGM to PSG time - int blip_time_factor; - blip_time_t to_psg_time( vgm_time_t ) const; - - int blip_ay_time_factor; - int ay_time_offset; - blip_time_t to_ay_time( vgm_time_t ) const; - - int blip_huc6280_time_factor; - int huc6280_time_offset; - blip_time_t to_huc6280_time( vgm_time_t ) const; - - int blip_gbdmg_time_factor; - int gbdmg_time_offset; - blip_time_t to_gbdmg_time( vgm_time_t ) const; - - // Current time and position in log - vgm_time_t vgm_time; - byte const* pos; - byte const* loop_begin; - bool has_looped; - - // PCM - enum { PCM_BANK_COUNT = 0x40 }; - typedef struct _vgm_pcm_bank_data - { - unsigned DataSize; - byte* Data; - unsigned DataStart; - } VGM_PCM_DATA; - typedef struct _vgm_pcm_bank - { - unsigned BankCount; - VGM_PCM_DATA* Bank; - unsigned DataSize; - byte* Data; - unsigned DataPos; - unsigned BnkPos; - } VGM_PCM_BANK; - - typedef struct pcmbank_table - { - byte ComprType; - byte CmpSubType; - byte BitDec; - byte BitCmp; - unsigned EntryCount; - void* Entries; - } PCMBANK_TBL; - - VGM_PCM_BANK PCMBank[PCM_BANK_COUNT]; - PCMBANK_TBL PCMTbl; - - void ReadPCMTable(unsigned DataSize, const byte* Data); - void AddPCMData(byte Type, unsigned DataSize, const byte* Data); - bool DecompressDataBlk(VGM_PCM_DATA* Bank, unsigned DataSize, const byte* Data); - const byte* GetPointerFromPCMBank(byte Type, unsigned DataPos); - - byte const* pcm_pos; // current position in PCM data - int dac_amp[2]; - int dac_disabled[2]; // -1 if disabled - void write_pcm( vgm_time_t, int chip, int amp ); - - blip_time_t run( vgm_time_t ); - int run_ym2151( int chip, int time ); - int run_ym2203( int chip, int time ); - int run_ym2413( int chip, int time ); - int run_ym2612( int chip, int time ); - int run_ym3812( int chip, int time ); - int run_ymf262( int chip, int time ); - int run_ym2610( int chip, int time ); - int run_ym2608( int chip, int time ); - int run_ymz280b( int time ); - int run_c140( int time ); - int run_segapcm( int time ); - int run_rf5c68( int time ); - int run_rf5c164( int time ); - int run_pwm( int time ); - int run_okim6258( int chip, int time ); - int run_okim6295( int chip, int time ); - int run_k051649( int time ); - int run_k053260( int time ); - int run_k054539( int time ); - int run_qsound( int chip, int time ); - void update_fm_rates( int* ym2151_rate, int* ym2413_rate, int* ym2612_rate ) const; -}; - -#endif +// Sega VGM music file emulator core + +// Game_Music_Emu $vers +#ifndef VGM_CORE_H +#define VGM_CORE_H + +#include "Gme_Loader.h" +#include "Ymz280b_Emu.h" +#include "Ymf262_Emu.h" +#include "Ym2612_Emu.h" +#include "Ym2610b_Emu.h" +#include "Ym2608_Emu.h" +#include "Ym3812_Emu.h" +#include "Ym2413_Emu.h" +#include "Ym2151_Emu.h" +#include "C140_Emu.h" +#include "SegaPcm_Emu.h" +#include "Rf5C68_Emu.h" +#include "Rf5C164_Emu.h" +#include "Pwm_Emu.h" +#include "Okim6258_Emu.h" +#include "Okim6295_Emu.h" +#include "K051649_Emu.h" +#include "K053260_Emu.h" +#include "K054539_Emu.h" +#include "Qsound_Apu.h" +#include "Ym2203_Emu.h" +#include "Ay_Apu.h" +#include "Gb_Apu.h" +#include "Hes_Apu.h" +#include "Sms_Apu.h" +#include "Multi_Buffer.h" +#include "Chip_Resampler.h" + + template + class Chip_Emu : public Emu { + int last_time; + short* out; + enum { disabled_time = -1 }; + public: + Chip_Emu() { last_time = disabled_time; out = NULL; } + void enable( bool b = true ) { last_time = b ? 0 : disabled_time; } + bool enabled() const { return last_time != disabled_time; } + void begin_frame( short* buf ) { out = buf; last_time = 0; } + + int run_until( int time ) + { + int count = time - last_time; + if ( count > 0 ) + { + if ( last_time < 0 ) + return false; + last_time = time; + short* p = out; + out += count * Emu::out_chan_count; + Emu::run( count, p ); + } + return true; + } + }; + +class Vgm_Core : public Gme_Loader { +public: + + // VGM file header + struct header_t + { + enum { size_min = 0x40 }; + enum { size_151 = 0x80 }; + enum { size_max = 0xC0 }; + + char tag [4]; // 0x00 + byte data_size [4]; // 0x04 + byte version [4]; // 0x08 + byte psg_rate [4]; // 0x0C + byte ym2413_rate [4]; // 0x10 + byte gd3_offset [4]; // 0x14 + byte track_duration [4]; // 0x18 + byte loop_offset [4]; // 0x1C + byte loop_duration [4]; // 0x20 + byte frame_rate [4]; // 0x24 v1.01 V + byte noise_feedback [2]; // 0x28 v1.10 V + byte noise_width; // 0x2A + byte sn76489_flags; // 0x2B v1.51 < + byte ym2612_rate [4]; // 0x2C v1.10 V + byte ym2151_rate [4]; // 0x30 + byte data_offset [4]; // 0x34 v1.50 V + byte segapcm_rate [4]; // 0x38 v1.51 V + byte segapcm_reg [4]; // 0x3C + byte rf5c68_rate [4]; // 0x40 + byte ym2203_rate [4]; // 0x44 + byte ym2608_rate [4]; // 0x48 + byte ym2610_rate [4]; // 0x4C + byte ym3812_rate [4]; // 0x50 + byte ym3526_rate [4]; // 0x54 + byte y8950_rate [4]; // 0x58 + byte ymf262_rate [4]; // 0x5C + byte ymf278b_rate [4]; // 0x60 + byte ymf271_rate [4]; // 0x64 + byte ymz280b_rate [4]; // 0x68 + byte rf5c164_rate [4]; // 0x6C + byte pwm_rate [4]; // 0x70 + byte ay8910_rate [4]; // 0x74 + byte ay8910_type; // 0x78 + byte ay8910_flags; // 0x79 + byte ym2203_ay8910_flags;// 0x7A + byte ym2608_ay8910_flags;// 0x7B + byte volume_modifier; // 0x7C v1.60 V + byte reserved; // 0x7D + byte loop_base; // 0x7E + byte loop_modifier; // 0x7F v1.51 < + byte gbdmg_rate [4]; // 0x80 v1.61 V + byte nesapu_rate [4]; // 0x84 + byte multipcm_rate [4]; // 0x88 + byte upd7759_rate [4]; // 0x8C + byte okim6258_rate [4]; // 0x90 + byte okim6258_flags; // 0x94 + byte k054539_flags; // 0x95 + byte c140_type; // 0x96 + byte reserved_flags; // 0x97 + byte okim6295_rate [4]; // 0x98 + byte k051649_rate [4]; // 0x9C + byte k054539_rate [4]; // 0xA0 + byte huc6280_rate [4]; // 0xA4 + byte c140_rate [4]; // 0xA8 + byte k053260_rate [4]; // 0xAC + byte pokey_rate [4]; // 0xB0 + byte qsound_rate [4]; // 0xB4 + byte reserved2 [4]; // 0xB8 + byte extra_offset [4]; // 0xBC + + // True if header has valid file signature + bool valid_tag() const; + int size() const; + void cleanup(); + }; + + // Header for currently loaded file + header_t const& header() const { return _header; } + + // Raw file data, for parsing GD3 tags + byte const* file_begin() const { return Gme_Loader::file_begin(); } + byte const* file_end () const { return Gme_Loader::file_end(); } + + // If file uses FM, initializes FM sound emulator using *sample_rate. If + // *sample_rate is zero, sets *sample_rate to the proper accurate rate and + // uses that. The output of the FM sound emulator is resampled to the + // final sampling rate. + blargg_err_t init_chips( double* fm_rate, bool reinit = false ); + + // True if any FM chips are used by file. Always false until init_fm() + // is called. + bool uses_fm() const { return ym2612[0].enabled() || ym2413[0].enabled() || ym2151[0].enabled() || c140.enabled() || + segapcm.enabled() || rf5c68.enabled() || rf5c164.enabled() || pwm.enabled() || okim6258[0].enabled() || okim6295[0].enabled() || + k051649.enabled() || k053260.enabled() || k054539.enabled() || ym2203[0].enabled() || ym3812[0].enabled() || ymf262[0].enabled() || + ymz280b.enabled() || ym2610[0].enabled() || ym2608[0].enabled() || qsound[0].enabled() || + (header().ay8910_rate[0] | header().ay8910_rate[1] | header().ay8910_rate[2] | header().ay8910_rate[3]) || + (header().huc6280_rate[0] | header().huc6280_rate[1] | header().huc6280_rate[2] | header().huc6280_rate[3]) || + (header().gbdmg_rate[0] | header().gbdmg_rate[1] | header().gbdmg_rate[2] | header().gbdmg_rate[3]); } + + // Adjusts music tempo, where 1.0 is normal. Can be changed while playing. + // Loading a file resets tempo to 1.0. + void set_tempo( double ); + + void set_sample_rate( int r ) { sample_rate = r; } + + // Starts track + void start_track(); + + // Runs PSG-only VGM for msec and returns number of clocks it ran for + blip_time_t run_psg( int msec ); + + // Plays FM for at most count samples into *out, and returns number of + // samples actually generated (always even). Also runs PSG for blip_time. + int play_frame( blip_time_t blip_time, int count, blip_sample_t out [] ); + + // True if all of file data has been played + bool track_ended() const { return pos >= file_end(); } + + // 0 for PSG and YM2612 DAC, 1 for AY, 2 for HuC6280, 3 for GB DMG + Stereo_Buffer stereo_buf[4]; + + // PCM sound is always generated here + Blip_Buffer * blip_buf[2]; + + // PSG sound chips, for assigning to Blip_Buffer, and setting volume and EQ + Sms_Apu psg[2]; + Ay_Apu ay[2]; + Hes_Apu huc6280[2]; + Gb_Apu gbdmg[2]; + + // PCM synth, for setting volume and EQ + Blip_Synth_Fast pcm; + + // FM sound chips + Chip_Resampler_Emu ymf262[2]; + Chip_Resampler_Emu ym3812[2]; + Chip_Resampler_Emu ym2612[2]; + Chip_Resampler_Emu ym2610[2]; + Chip_Resampler_Emu ym2608[2]; + Chip_Resampler_Emu ym2413[2]; + Chip_Resampler_Emu ym2151[2]; + Chip_Resampler_Emu ym2203[2]; + + // PCM sound chips + Chip_Resampler_Emu c140; + Chip_Resampler_Emu segapcm; + Chip_Resampler_Emu rf5c68; + Chip_Resampler_Emu rf5c164; + Chip_Resampler_Emu pwm; + Chip_Resampler_Emu okim6258[2]; int okim6258_hz[2]; + Chip_Resampler_Emu okim6295[2]; int okim6295_hz; + Chip_Resampler_Emu k051649; + Chip_Resampler_Emu k053260; + Chip_Resampler_Emu k054539; + Chip_Resampler_Emu ymz280b; int ymz280b_hz; + Chip_Resampler_Emu qsound[2]; + + // DAC control + typedef struct daccontrol_data + { + bool Enable; + byte Bank; + } DACCTRL_DATA; + + byte DacCtrlUsed; + byte DacCtrlUsg[0xFF]; + DACCTRL_DATA DacCtrl[0xFF]; + byte DacCtrlMap[0xFF]; + int DacCtrlTime[0xFF]; + void ** dac_control; + + void dac_control_grow(byte chip_id); + + int dac_control_recursion; + + int run_dac_control( int time ); + +public: + void chip_reg_write(unsigned Sample, byte ChipType, byte ChipID, byte Port, byte Offset, byte Data); + +// Implementation +public: + Vgm_Core(); + ~Vgm_Core(); + +protected: + virtual blargg_err_t load_mem_( byte const [], int ); + +private: + // blip_time_t // PSG clocks + typedef int vgm_time_t; // 44100 per second, REGARDLESS of sample rate + typedef int fm_time_t; // FM sample count + + int sample_rate; + int vgm_rate; // rate of log, 44100 normally, adjusted by tempo + double fm_rate; // FM samples per second + + header_t _header; + + // VGM to FM time + int fm_time_factor; + int fm_time_offset; + fm_time_t to_fm_time( vgm_time_t ) const; + + // VGM to PSG time + int blip_time_factor; + blip_time_t to_psg_time( vgm_time_t ) const; + + int blip_ay_time_factor; + int ay_time_offset; + blip_time_t to_ay_time( vgm_time_t ) const; + + int blip_huc6280_time_factor; + int huc6280_time_offset; + blip_time_t to_huc6280_time( vgm_time_t ) const; + + int blip_gbdmg_time_factor; + int gbdmg_time_offset; + blip_time_t to_gbdmg_time( vgm_time_t ) const; + + // Current time and position in log + vgm_time_t vgm_time; + byte const* pos; + byte const* loop_begin; + bool has_looped; + + // PCM + enum { PCM_BANK_COUNT = 0x40 }; + typedef struct _vgm_pcm_bank_data + { + unsigned DataSize; + byte* Data; + unsigned DataStart; + } VGM_PCM_DATA; + typedef struct _vgm_pcm_bank + { + unsigned BankCount; + VGM_PCM_DATA* Bank; + unsigned DataSize; + byte* Data; + unsigned DataPos; + unsigned BnkPos; + } VGM_PCM_BANK; + + typedef struct pcmbank_table + { + byte ComprType; + byte CmpSubType; + byte BitDec; + byte BitCmp; + unsigned EntryCount; + void* Entries; + } PCMBANK_TBL; + + VGM_PCM_BANK PCMBank[PCM_BANK_COUNT]; + PCMBANK_TBL PCMTbl; + + void ReadPCMTable(unsigned DataSize, const byte* Data); + void AddPCMData(byte Type, unsigned DataSize, const byte* Data); + bool DecompressDataBlk(VGM_PCM_DATA* Bank, unsigned DataSize, const byte* Data); + const byte* GetPointerFromPCMBank(byte Type, unsigned DataPos); + + byte const* pcm_pos; // current position in PCM data + int dac_amp[2]; + int dac_disabled[2]; // -1 if disabled + void write_pcm( vgm_time_t, int chip, int amp ); + + blip_time_t run( vgm_time_t ); + int run_ym2151( int chip, int time ); + int run_ym2203( int chip, int time ); + int run_ym2413( int chip, int time ); + int run_ym2612( int chip, int time ); + int run_ym3812( int chip, int time ); + int run_ymf262( int chip, int time ); + int run_ym2610( int chip, int time ); + int run_ym2608( int chip, int time ); + int run_ymz280b( int time ); + int run_c140( int time ); + int run_segapcm( int time ); + int run_rf5c68( int time ); + int run_rf5c164( int time ); + int run_pwm( int time ); + int run_okim6258( int chip, int time ); + int run_okim6295( int chip, int time ); + int run_k051649( int time ); + int run_k053260( int time ); + int run_k054539( int time ); + int run_qsound( int chip, int time ); + void update_fm_rates( int* ym2151_rate, int* ym2413_rate, int* ym2612_rate ) const; +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Vgm_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Vgm_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Vgm_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Vgm_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,551 +1,551 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Vgm_Emu.h" - -#include "blargg_endian.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// FM emulators are internally quieter to avoid 16-bit overflow -double const fm_gain = 3.0; -double const rolloff = 0.990; -double const oversample_factor = 1.5; - -Vgm_Emu::Vgm_Emu() -{ - resampler.set_callback( play_frame_, this ); - disable_oversampling_ = false; - muted_voices = 0; - set_type( gme_vgm_type ); - set_max_initial_silence( 1 ); - set_silence_lookahead( 1 ); // tracks should already be trimmed - - static equalizer_t const eq = { -14.0, 80 , 0,0,0,0,0,0,0,0 }; - set_equalizer( eq ); -} - -Vgm_Emu::~Vgm_Emu() { } - -void Vgm_Emu::unload() -{ - core.unload(); - Classic_Emu::unload(); -} - -// Track info - -static byte const* skip_gd3_str( byte const in [], byte const* end ) -{ - while ( end - in >= 2 ) - { - in += 2; - if ( !(in [-2] | in [-1]) ) - break; - } - return in; -} - -static byte const* get_gd3_str( byte const* in, byte const* end, char field [] ) -{ - byte const* mid = skip_gd3_str( in, end ); - int len = (mid - in) / 2 - 1; - if ( len > 0 ) - { - len = min( len, (int) Gme_File::max_field_ ); - field [len] = 0; - for ( int i = 0; i < len; i++ ) - field [i] = (in [i * 2 + 1] ? '?' : in [i * 2]); // TODO: convert to utf-8 - } - return mid; -} - -static byte const* get_gd3_pair( byte const* in, byte const* end, char field [] ) -{ - return skip_gd3_str( get_gd3_str( in, end, field ), end ); -} - -static void parse_gd3( byte const in [], byte const* end, track_info_t* out ) -{ - in = get_gd3_pair( in, end, out->song ); - in = get_gd3_pair( in, end, out->game ); - in = get_gd3_pair( in, end, out->system ); - in = get_gd3_pair( in, end, out->author ); - in = get_gd3_str ( in, end, out->copyright ); - in = get_gd3_pair( in, end, out->dumper ); - in = get_gd3_str ( in, end, out->comment ); -} - -int const gd3_header_size = 12; - -static int check_gd3_header( byte const h [], int remain ) -{ - if ( remain < gd3_header_size ) return 0; - if ( memcmp( h, "Gd3 ", 4 ) ) return 0; - if ( get_le32( h + 4 ) >= 0x200 ) return 0; - - int gd3_size = get_le32( h + 8 ); - if ( gd3_size > remain - gd3_header_size ) return 0; - - return gd3_size; -} - -static void get_vgm_length( Vgm_Emu::header_t const& h, track_info_t* out ) -{ - int length = get_le32( h.track_duration ) * 10 / 441; // 1000 / 44100 - if ( length > 0 ) - { - int loop = get_le32( h.loop_duration ); - if ( loop > 0 && get_le32( h.loop_offset ) ) - { - out->loop_length = loop * 10 / 441; - out->intro_length = length - out->loop_length; - check( out->loop_length <= length ); - // TODO: Also set out->length? We now have play_length for suggested play time. - } - else - { - out->length = length; - out->intro_length = length; - out->loop_length = 0; - } - } -} - -blargg_err_t Vgm_Emu::track_info_( track_info_t* out, int ) const -{ - get_vgm_length( header(), out ); - - int gd3_offset = get_le32( header().gd3_offset ); - if ( gd3_offset <= 0 ) - return blargg_ok; - - byte const* gd3 = core.file_begin() + gd3_offset + offsetof( header_t, gd3_offset ); - int gd3_size = check_gd3_header( gd3, core.file_end() - gd3 ); - if ( gd3_size ) - { - byte const* gd3_data = gd3 + gd3_header_size; - parse_gd3( gd3_data, gd3_data + gd3_size, out ); - } - - return blargg_ok; -} - -blargg_err_t Vgm_Emu::gd3_data( const unsigned char ** data, int * size ) -{ - *data = 0; - *size = 0; - - int gd3_offset = get_le32( header().gd3_offset ); - if ( gd3_offset <= 0 ) - return blargg_ok; - - byte const* gd3 = core.file_begin() + gd3_offset + offsetof( header_t, gd3_offset ); - int gd3_size = check_gd3_header( gd3, core.file_end() - gd3 ); - if ( gd3_size ) - { - *data = gd3; - *size = gd3_size + gd3_header_size; - } - - return blargg_ok; -} - -static void hash_vgm_file( Vgm_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( &h.data_size[0], sizeof(h.data_size) ); - out.hash_( &h.version[0], sizeof(h.version) ); - out.hash_( &h.psg_rate[0], sizeof(h.psg_rate) ); - out.hash_( &h.ym2413_rate[0], sizeof(h.ym2413_rate) ); - out.hash_( &h.track_duration[0], sizeof(h.track_duration) ); - out.hash_( &h.loop_offset[0], sizeof(h.loop_offset) ); - out.hash_( &h.loop_duration[0], sizeof(h.loop_duration) ); - out.hash_( &h.frame_rate[0], sizeof(h.frame_rate) ); - out.hash_( &h.noise_feedback[0], sizeof(h.noise_feedback) ); - out.hash_( &h.noise_width, sizeof(h.noise_width) ); - out.hash_( &h.sn76489_flags, sizeof(h.sn76489_flags) ); - out.hash_( &h.ym2612_rate[0], sizeof(h.ym2612_rate) ); - out.hash_( &h.ym2151_rate[0], sizeof(h.ym2151_rate) ); - out.hash_( &h.data_offset[0], sizeof(h.data_offset) ); - out.hash_( &h.segapcm_rate[0], sizeof(h.segapcm_rate) ); - out.hash_( &h.segapcm_reg[0], sizeof(h.segapcm_reg) ); - out.hash_( &h.rf5c68_rate[0], sizeof(h.rf5c68_rate) ); - out.hash_( &h.ym2203_rate[0], sizeof(h.ym2203_rate) ); - out.hash_( &h.ym2608_rate[0], sizeof(h.ym2608_rate) ); - out.hash_( &h.ym2610_rate[0], sizeof(h.ym2610_rate) ); - out.hash_( &h.ym3812_rate[0], sizeof(h.ym3812_rate) ); - out.hash_( &h.ym3526_rate[0], sizeof(h.ym3526_rate) ); - out.hash_( &h.y8950_rate[0], sizeof(h.y8950_rate) ); - out.hash_( &h.ymf262_rate[0], sizeof(h.ymf262_rate) ); - out.hash_( &h.ymf278b_rate[0], sizeof(h.ymf278b_rate) ); - out.hash_( &h.ymf271_rate[0], sizeof(h.ymf271_rate) ); - out.hash_( &h.ymz280b_rate[0], sizeof(h.ymz280b_rate) ); - out.hash_( &h.rf5c164_rate[0], sizeof(h.rf5c164_rate) ); - out.hash_( &h.pwm_rate[0], sizeof(h.pwm_rate) ); - out.hash_( &h.ay8910_rate[0], sizeof(h.ay8910_rate) ); - out.hash_( &h.ay8910_type, sizeof(h.ay8910_type) ); - out.hash_( &h.ay8910_flags, sizeof(h.ay8910_flags) ); - out.hash_( &h.ym2203_ay8910_flags, sizeof(h.ym2203_ay8910_flags) ); - out.hash_( &h.ym2608_ay8910_flags, sizeof(h.ym2608_ay8910_flags) ); - out.hash_( &h.reserved, sizeof(h.reserved) ); - out.hash_( &h.gbdmg_rate[0], sizeof(h.gbdmg_rate) ); - out.hash_( &h.nesapu_rate[0], sizeof(h.nesapu_rate) ); - out.hash_( &h.multipcm_rate[0], sizeof(h.multipcm_rate) ); - out.hash_( &h.upd7759_rate[0], sizeof(h.upd7759_rate) ); - out.hash_( &h.okim6258_rate[0], sizeof(h.okim6258_rate) ); - out.hash_( &h.okim6258_flags, sizeof(h.okim6258_flags) ); - out.hash_( &h.k054539_flags, sizeof(h.k054539_flags) ); - out.hash_( &h.c140_type, sizeof(h.c140_type) ); - out.hash_( &h.reserved_flags, sizeof(h.reserved_flags) ); - out.hash_( &h.okim6295_rate[0], sizeof(h.okim6295_rate) ); - out.hash_( &h.k051649_rate[0], sizeof(h.k051649_rate) ); - out.hash_( &h.k054539_rate[0], sizeof(h.k054539_rate) ); - out.hash_( &h.huc6280_rate[0], sizeof(h.huc6280_rate) ); - out.hash_( &h.c140_rate[0], sizeof(h.c140_rate) ); - out.hash_( &h.k053260_rate[0], sizeof(h.k053260_rate) ); - out.hash_( &h.pokey_rate[0], sizeof(h.pokey_rate) ); - out.hash_( &h.qsound_rate[0], sizeof(h.qsound_rate) ); - out.hash_( &h.reserved2[0], sizeof(h.reserved2) ); - out.hash_( &h.extra_offset[0], sizeof(h.extra_offset) ); - out.hash_( data, data_size ); -} - -struct Vgm_File : Gme_Info_ -{ - Vgm_Emu::header_t h; - blargg_vector data; - blargg_vector gd3; - - Vgm_File() { set_type( gme_vgm_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - int file_size = in.remain(); - if ( file_size <= h.size_min ) - return blargg_err_file_type; - - RETURN_ERR( in.read( &h, h.size_min ) ); - if ( !h.valid_tag() ) - return blargg_err_file_type; - - if ( h.size() > h.size_min ) - RETURN_ERR( in.read( &h.rf5c68_rate, h.size() - h.size_min ) ); - - h.cleanup(); - - int data_offset = get_le32( h.data_offset ) + offsetof( Vgm_Core::header_t, data_offset ); - int data_size = file_size - offsetof( Vgm_Core::header_t, data_offset ) - data_offset; - int gd3_offset = get_le32( h.gd3_offset ); - if ( gd3_offset > 0 ) - gd3_offset += offsetof( Vgm_Core::header_t, gd3_offset ); - - int amount_to_skip = gd3_offset - h.size(); - - if ( gd3_offset > 0 && gd3_offset > data_offset ) - { - data_size = gd3_offset - data_offset; - amount_to_skip = 0; - - RETURN_ERR( data.resize( data_size ) ); - RETURN_ERR( in.skip( data_offset - h.size() ) ); - RETURN_ERR( in.read( data.begin(), data_size ) ); - } - - int remain = file_size - gd3_offset; - byte gd3_h [gd3_header_size]; - if ( gd3_offset > 0 && remain >= gd3_header_size ) - { - RETURN_ERR( in.skip( amount_to_skip ) ); - RETURN_ERR( in.read( gd3_h, sizeof gd3_h ) ); - int gd3_size = check_gd3_header( gd3_h, remain ); - if ( gd3_size ) - { - RETURN_ERR( gd3.resize( gd3_size ) ); - RETURN_ERR( in.read( gd3.begin(), gd3.size() ) ); - } - - if ( data_offset > gd3_offset ) - { - RETURN_ERR( data.resize( data_size ) ); - RETURN_ERR( in.skip( data_offset - gd3_offset - sizeof gd3_h - gd3.size() ) ); - RETURN_ERR( in.read( data.begin(), data.end() - data.begin() ) ); - } - } - - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - get_vgm_length( h, out ); - if ( gd3.size() ) - parse_gd3( gd3.begin(), gd3.end(), out ); - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_vgm_file( h, data.begin(), data.end() - data.begin(), out ); - return blargg_ok; - } -}; - -static Music_Emu* new_vgm_emu () { return BLARGG_NEW Vgm_Emu ; } -static Music_Emu* new_vgm_file() { return BLARGG_NEW Vgm_File; } - -gme_type_t_ const gme_vgm_type [1] = {{ "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGM", 1 }}; - -gme_type_t_ const gme_vgz_type [1] = {{ "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGZ", 1 }}; - -// Setup - -void Vgm_Emu::set_tempo_( double t ) -{ - core.set_tempo( t ); -} - -blargg_err_t Vgm_Emu::set_sample_rate_( int sample_rate ) -{ - RETURN_ERR( core.stereo_buf[0].set_sample_rate( sample_rate, 1000 / 30 ) ); - RETURN_ERR( core.stereo_buf[1].set_sample_rate( sample_rate, 1000 / 30 ) ); - RETURN_ERR( core.stereo_buf[2].set_sample_rate( sample_rate, 1000 / 30 ) ); - RETURN_ERR( core.stereo_buf[3].set_sample_rate( sample_rate, 1000 / 30 ) ); - core.set_sample_rate(sample_rate); - return Classic_Emu::set_sample_rate_( sample_rate ); -} - -void Vgm_Emu::update_eq( blip_eq_t const& eq ) -{ - core.psg[0].treble_eq( eq ); - core.psg[1].treble_eq( eq ); - core.ay[0].treble_eq( eq ); - core.ay[1].treble_eq( eq ); - core.huc6280[0].treble_eq( eq ); - core.huc6280[1].treble_eq( eq ); - core.gbdmg[0].treble_eq( eq ); - core.gbdmg[1].treble_eq( eq ); - core.pcm.treble_eq( eq ); -} - -void Vgm_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) -{ - if ( i < core.psg[0].osc_count ) - { - core.psg[0].set_output( i, c, l, r ); - core.psg[1].set_output( i, c, l, r ); - } -} - -void Vgm_Emu::mute_voices_( int mask ) -{ - muted_voices = mask; - - Classic_Emu::mute_voices_( mask ); - - // TODO: what was this for? - //core.pcm.output( &core.blip_buf ); - - // TODO: silence PCM if FM isn't used? - if ( core.uses_fm() ) - { - core.psg[0].set_output( ( mask & 0x80 ) ? 0 : core.stereo_buf[0].center() ); - core.psg[1].set_output( ( mask & 0x80 ) ? 0 : core.stereo_buf[0].center() ); - core.ay[0].set_output( ( mask & 0x80 ) ? 0 : core.stereo_buf[1].center() ); - core.ay[1].set_output( ( mask & 0x80 ) ? 0 : core.stereo_buf[1].center() ); - for ( unsigned i = 0, j = 1; i < core.huc6280[0].osc_count; i++, j <<= 1) - { - Blip_Buffer * center = ( mask & j ) ? 0 : core.stereo_buf[2].center(); - Blip_Buffer * left = ( mask & j ) ? 0 : core.stereo_buf[2].left(); - Blip_Buffer * right = ( mask & j ) ? 0 : core.stereo_buf[2].right(); - core.huc6280[0].set_output( i, center, left, right ); - core.huc6280[1].set_output( i, center, left, right ); - } - for (unsigned i = 0, j = 1; i < core.gbdmg[0].osc_count; i++, j <<= 1) - { - Blip_Buffer * center = (mask & j) ? 0 : core.stereo_buf[3].center(); - Blip_Buffer * left = (mask & j) ? 0 : core.stereo_buf[3].left(); - Blip_Buffer * right = (mask & j) ? 0 : core.stereo_buf[3].right(); - core.gbdmg[0].set_output(i, center, left, right); - core.gbdmg[1].set_output(i, center, left, right); - } - if (core.ym2612[0].enabled()) - { - core.pcm.volume( (mask & 0x40) ? 0.0 : 0.1115 / 256 * fm_gain * gain() ); - core.ym2612[0].mute_voices( mask ); - if ( core.ym2612[1].enabled() ) - core.ym2612[1].mute_voices( mask ); - } - - if ( core.ym2413[0].enabled() ) - { - int m = mask & 0x3F; - if ( mask & 0x20 ) - m |= 0x01E0; // channels 5-8 - if ( mask & 0x40 ) - m |= 0x3E00; - core.ym2413[0].mute_voices( m ); - if ( core.ym2413[1].enabled() ) - core.ym2413[1].mute_voices( m ); - } - - if ( core.ym2151[0].enabled() ) - { - core.ym2151[0].mute_voices( mask ); - if ( core.ym2151[1].enabled() ) - core.ym2151[1].mute_voices( mask ); - } - - if ( core.c140.enabled() ) - { - int m = 0; - int m_add = 7; - for ( unsigned i = 0; i < 8; i++, m_add <<= 3 ) - { - if ( mask & ( 1 << i ) ) m += m_add; - } - core.c140.mute_voices( m ); - } - - if ( core.rf5c68.enabled() ) - { - core.rf5c68.mute_voices( mask ); - } - - if ( core.rf5c164.enabled() ) - { - core.rf5c164.mute_voices( mask ); - } - } -} - -blargg_err_t Vgm_Emu::load_mem_( byte const data [], int size ) -{ - RETURN_ERR( core.load_mem( data, size ) ); - - set_voice_count( core.psg[0].osc_count ); - - double fm_rate = 0.0; - if ( !disable_oversampling_ ) - fm_rate = sample_rate() * oversample_factor; - RETURN_ERR( core.init_chips( &fm_rate ) ); - - double psg_gain = ( ( core.header().psg_rate[3] & 0xC0 ) == 0x40 ) ? 0.5 : 1.0; - - if ( core.uses_fm() ) - { - set_voice_count( 8 ); - RETURN_ERR( resampler.setup( fm_rate / sample_rate(), rolloff, gain() ) ); - RETURN_ERR( resampler.reset( core.stereo_buf[0].length() * sample_rate() / 1000 ) ); - core.psg[0].volume( 0.135 * fm_gain * psg_gain * gain() ); - core.psg[1].volume( 0.135 * fm_gain * psg_gain * gain() ); - core.ay[0].volume( 0.135 * fm_gain * gain() ); - core.ay[1].volume( 0.135 * fm_gain * gain() ); - core.huc6280[0].volume( 0.135 * fm_gain * gain() ); - core.huc6280[1].volume( 0.135 * fm_gain * gain() ); - core.gbdmg[0].volume( 0.135 * fm_gain * gain() ); - core.gbdmg[1].volume( 0.135 * fm_gain * gain() ); - } - else - { - core.psg[0].volume( psg_gain * gain() ); - core.psg[1].volume( psg_gain * gain() ); - } - - static const char* const fm_names [] = { - "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG" - }; - static const char* const psg_names [] = { "Square 1", "Square 2", "Square 3", "Noise" }; - set_voice_names( core.uses_fm() ? fm_names : psg_names ); - - static int const types [8] = { - wave_type+1, wave_type+2, wave_type+3, noise_type+1, - 0, 0, 0, 0 - }; - set_voice_types( types ); - - return Classic_Emu::setup_buffer( core.stereo_buf[0].center()->clock_rate() ); -} - -// Emulation - -blargg_err_t Vgm_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - core.start_track(); - - mute_voices_(muted_voices); - - if ( core.uses_fm() ) - resampler.clear(); - - return blargg_ok; -} - -inline void Vgm_Emu::check_end() -{ - if ( core.track_ended() ) - set_track_ended(); -} - -inline void Vgm_Emu::check_warning() -{ - const char* w = core.warning(); - if ( w ) - set_warning( w ); -} - -blargg_err_t Vgm_Emu::run_clocks( blip_time_t& time_io, int msec ) -{ - check_end(); - time_io = core.run_psg( msec ); - check_warning(); - return blargg_ok; -} - -inline int Vgm_Emu::play_frame( blip_time_t blip_time, int sample_count, sample_t buf [] ) -{ - check_end(); - int result = core.play_frame( blip_time, sample_count, buf ); - check_warning(); - return result; -} - -int Vgm_Emu::play_frame_( void* p, blip_time_t a, int b, sample_t c [] ) -{ - return STATIC_CAST(Vgm_Emu*,p)->play_frame( a, b, c ); -} - -blargg_err_t Vgm_Emu::play_( int count, sample_t out [] ) -{ - if ( !core.uses_fm() ) - return Classic_Emu::play_( count, out ); - - Stereo_Buffer * secondaries[] = { &core.stereo_buf[1], &core.stereo_buf[2], &core.stereo_buf[3] }; - resampler.dual_play( count, out, core.stereo_buf[0], secondaries, 3 ); - return blargg_ok; -} - -blargg_err_t Vgm_Emu::hash_( Hash_Function& out ) const -{ - byte const* p = file_begin() + header().size(); - byte const* e = file_end(); - int data_offset = get_le32( header().data_offset ); - if ( data_offset ) - p += data_offset + offsetof( header_t, data_offset ) - header().size(); - int gd3_offset = get_le32( header().gd3_offset ); - if ( gd3_offset > 0 && gd3_offset + offsetof( header_t, gd3_offset ) > data_offset + offsetof( header_t, data_offset ) ) - e = file_begin() + gd3_offset + offsetof( header_t, gd3_offset ); - hash_vgm_file( header(), p, e - p, out ); - return blargg_ok; -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Vgm_Emu.h" + +#include "blargg_endian.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// FM emulators are internally quieter to avoid 16-bit overflow +double const fm_gain = 3.0; +double const rolloff = 0.990; +double const oversample_factor = 1.5; + +Vgm_Emu::Vgm_Emu() +{ + resampler.set_callback( play_frame_, this ); + disable_oversampling_ = false; + muted_voices = 0; + set_type( gme_vgm_type ); + set_max_initial_silence( 1 ); + set_silence_lookahead( 1 ); // tracks should already be trimmed + + static equalizer_t const eq = { -14.0, 80 , 0,0,0,0,0,0,0,0 }; + set_equalizer( eq ); +} + +Vgm_Emu::~Vgm_Emu() { } + +void Vgm_Emu::unload() +{ + core.unload(); + Classic_Emu::unload(); +} + +// Track info + +static byte const* skip_gd3_str( byte const in [], byte const* end ) +{ + while ( end - in >= 2 ) + { + in += 2; + if ( !(in [-2] | in [-1]) ) + break; + } + return in; +} + +static byte const* get_gd3_str( byte const* in, byte const* end, char field [] ) +{ + byte const* mid = skip_gd3_str( in, end ); + int len = (mid - in) / 2 - 1; + if ( len > 0 ) + { + len = min( len, (int) Gme_File::max_field_ ); + field [len] = 0; + for ( int i = 0; i < len; i++ ) + field [i] = (in [i * 2 + 1] ? '?' : in [i * 2]); // TODO: convert to utf-8 + } + return mid; +} + +static byte const* get_gd3_pair( byte const* in, byte const* end, char field [] ) +{ + return skip_gd3_str( get_gd3_str( in, end, field ), end ); +} + +static void parse_gd3( byte const in [], byte const* end, track_info_t* out ) +{ + in = get_gd3_pair( in, end, out->song ); + in = get_gd3_pair( in, end, out->game ); + in = get_gd3_pair( in, end, out->system ); + in = get_gd3_pair( in, end, out->author ); + in = get_gd3_str ( in, end, out->copyright ); + in = get_gd3_pair( in, end, out->dumper ); + in = get_gd3_str ( in, end, out->comment ); +} + +int const gd3_header_size = 12; + +static int check_gd3_header( byte const h [], int remain ) +{ + if ( remain < gd3_header_size ) return 0; + if ( memcmp( h, "Gd3 ", 4 ) ) return 0; + if ( get_le32( h + 4 ) >= 0x200 ) return 0; + + int gd3_size = get_le32( h + 8 ); + if ( gd3_size > remain - gd3_header_size ) return 0; + + return gd3_size; +} + +static void get_vgm_length( Vgm_Emu::header_t const& h, track_info_t* out ) +{ + int length = get_le32( h.track_duration ) * 10 / 441; // 1000 / 44100 + if ( length > 0 ) + { + int loop = get_le32( h.loop_duration ); + if ( loop > 0 && get_le32( h.loop_offset ) ) + { + out->loop_length = loop * 10 / 441; + out->intro_length = length - out->loop_length; + check( out->loop_length <= length ); + // TODO: Also set out->length? We now have play_length for suggested play time. + } + else + { + out->length = length; + out->intro_length = length; + out->loop_length = 0; + } + } +} + +blargg_err_t Vgm_Emu::track_info_( track_info_t* out, int ) const +{ + get_vgm_length( header(), out ); + + int gd3_offset = get_le32( header().gd3_offset ); + if ( gd3_offset <= 0 ) + return blargg_ok; + + byte const* gd3 = core.file_begin() + gd3_offset + offsetof( header_t, gd3_offset ); + int gd3_size = check_gd3_header( gd3, core.file_end() - gd3 ); + if ( gd3_size ) + { + byte const* gd3_data = gd3 + gd3_header_size; + parse_gd3( gd3_data, gd3_data + gd3_size, out ); + } + + return blargg_ok; +} + +blargg_err_t Vgm_Emu::gd3_data( const unsigned char ** data, int * size ) +{ + *data = 0; + *size = 0; + + int gd3_offset = get_le32( header().gd3_offset ); + if ( gd3_offset <= 0 ) + return blargg_ok; + + byte const* gd3 = core.file_begin() + gd3_offset + offsetof( header_t, gd3_offset ); + int gd3_size = check_gd3_header( gd3, core.file_end() - gd3 ); + if ( gd3_size ) + { + *data = gd3; + *size = gd3_size + gd3_header_size; + } + + return blargg_ok; +} + +static void hash_vgm_file( Vgm_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( &h.data_size[0], sizeof(h.data_size) ); + out.hash_( &h.version[0], sizeof(h.version) ); + out.hash_( &h.psg_rate[0], sizeof(h.psg_rate) ); + out.hash_( &h.ym2413_rate[0], sizeof(h.ym2413_rate) ); + out.hash_( &h.track_duration[0], sizeof(h.track_duration) ); + out.hash_( &h.loop_offset[0], sizeof(h.loop_offset) ); + out.hash_( &h.loop_duration[0], sizeof(h.loop_duration) ); + out.hash_( &h.frame_rate[0], sizeof(h.frame_rate) ); + out.hash_( &h.noise_feedback[0], sizeof(h.noise_feedback) ); + out.hash_( &h.noise_width, sizeof(h.noise_width) ); + out.hash_( &h.sn76489_flags, sizeof(h.sn76489_flags) ); + out.hash_( &h.ym2612_rate[0], sizeof(h.ym2612_rate) ); + out.hash_( &h.ym2151_rate[0], sizeof(h.ym2151_rate) ); + out.hash_( &h.data_offset[0], sizeof(h.data_offset) ); + out.hash_( &h.segapcm_rate[0], sizeof(h.segapcm_rate) ); + out.hash_( &h.segapcm_reg[0], sizeof(h.segapcm_reg) ); + out.hash_( &h.rf5c68_rate[0], sizeof(h.rf5c68_rate) ); + out.hash_( &h.ym2203_rate[0], sizeof(h.ym2203_rate) ); + out.hash_( &h.ym2608_rate[0], sizeof(h.ym2608_rate) ); + out.hash_( &h.ym2610_rate[0], sizeof(h.ym2610_rate) ); + out.hash_( &h.ym3812_rate[0], sizeof(h.ym3812_rate) ); + out.hash_( &h.ym3526_rate[0], sizeof(h.ym3526_rate) ); + out.hash_( &h.y8950_rate[0], sizeof(h.y8950_rate) ); + out.hash_( &h.ymf262_rate[0], sizeof(h.ymf262_rate) ); + out.hash_( &h.ymf278b_rate[0], sizeof(h.ymf278b_rate) ); + out.hash_( &h.ymf271_rate[0], sizeof(h.ymf271_rate) ); + out.hash_( &h.ymz280b_rate[0], sizeof(h.ymz280b_rate) ); + out.hash_( &h.rf5c164_rate[0], sizeof(h.rf5c164_rate) ); + out.hash_( &h.pwm_rate[0], sizeof(h.pwm_rate) ); + out.hash_( &h.ay8910_rate[0], sizeof(h.ay8910_rate) ); + out.hash_( &h.ay8910_type, sizeof(h.ay8910_type) ); + out.hash_( &h.ay8910_flags, sizeof(h.ay8910_flags) ); + out.hash_( &h.ym2203_ay8910_flags, sizeof(h.ym2203_ay8910_flags) ); + out.hash_( &h.ym2608_ay8910_flags, sizeof(h.ym2608_ay8910_flags) ); + out.hash_( &h.reserved, sizeof(h.reserved) ); + out.hash_( &h.gbdmg_rate[0], sizeof(h.gbdmg_rate) ); + out.hash_( &h.nesapu_rate[0], sizeof(h.nesapu_rate) ); + out.hash_( &h.multipcm_rate[0], sizeof(h.multipcm_rate) ); + out.hash_( &h.upd7759_rate[0], sizeof(h.upd7759_rate) ); + out.hash_( &h.okim6258_rate[0], sizeof(h.okim6258_rate) ); + out.hash_( &h.okim6258_flags, sizeof(h.okim6258_flags) ); + out.hash_( &h.k054539_flags, sizeof(h.k054539_flags) ); + out.hash_( &h.c140_type, sizeof(h.c140_type) ); + out.hash_( &h.reserved_flags, sizeof(h.reserved_flags) ); + out.hash_( &h.okim6295_rate[0], sizeof(h.okim6295_rate) ); + out.hash_( &h.k051649_rate[0], sizeof(h.k051649_rate) ); + out.hash_( &h.k054539_rate[0], sizeof(h.k054539_rate) ); + out.hash_( &h.huc6280_rate[0], sizeof(h.huc6280_rate) ); + out.hash_( &h.c140_rate[0], sizeof(h.c140_rate) ); + out.hash_( &h.k053260_rate[0], sizeof(h.k053260_rate) ); + out.hash_( &h.pokey_rate[0], sizeof(h.pokey_rate) ); + out.hash_( &h.qsound_rate[0], sizeof(h.qsound_rate) ); + out.hash_( &h.reserved2[0], sizeof(h.reserved2) ); + out.hash_( &h.extra_offset[0], sizeof(h.extra_offset) ); + out.hash_( data, data_size ); +} + +struct Vgm_File : Gme_Info_ +{ + Vgm_Emu::header_t h; + blargg_vector data; + blargg_vector gd3; + + Vgm_File() { set_type( gme_vgm_type ); } + + blargg_err_t load_( Data_Reader& in ) + { + int file_size = in.remain(); + if ( file_size <= h.size_min ) + return blargg_err_file_type; + + RETURN_ERR( in.read( &h, h.size_min ) ); + if ( !h.valid_tag() ) + return blargg_err_file_type; + + if ( h.size() > h.size_min ) + RETURN_ERR( in.read( &h.rf5c68_rate, h.size() - h.size_min ) ); + + h.cleanup(); + + int data_offset = get_le32( h.data_offset ) + offsetof( Vgm_Core::header_t, data_offset ); + int data_size = file_size - offsetof( Vgm_Core::header_t, data_offset ) - data_offset; + int gd3_offset = get_le32( h.gd3_offset ); + if ( gd3_offset > 0 ) + gd3_offset += offsetof( Vgm_Core::header_t, gd3_offset ); + + int amount_to_skip = gd3_offset - h.size(); + + if ( gd3_offset > 0 && gd3_offset > data_offset ) + { + data_size = gd3_offset - data_offset; + amount_to_skip = 0; + + RETURN_ERR( data.resize( data_size ) ); + RETURN_ERR( in.skip( data_offset - h.size() ) ); + RETURN_ERR( in.read( data.begin(), data_size ) ); + } + + int remain = file_size - gd3_offset; + byte gd3_h [gd3_header_size]; + if ( gd3_offset > 0 && remain >= gd3_header_size ) + { + RETURN_ERR( in.skip( amount_to_skip ) ); + RETURN_ERR( in.read( gd3_h, sizeof gd3_h ) ); + int gd3_size = check_gd3_header( gd3_h, remain ); + if ( gd3_size ) + { + RETURN_ERR( gd3.resize( gd3_size ) ); + RETURN_ERR( in.read( gd3.begin(), gd3.size() ) ); + } + + if ( data_offset > gd3_offset ) + { + RETURN_ERR( data.resize( data_size ) ); + RETURN_ERR( in.skip( data_offset - gd3_offset - sizeof gd3_h - gd3.size() ) ); + RETURN_ERR( in.read( data.begin(), data.end() - data.begin() ) ); + } + } + + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + get_vgm_length( h, out ); + if ( gd3.size() ) + parse_gd3( gd3.begin(), gd3.end(), out ); + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_vgm_file( h, data.begin(), data.end() - data.begin(), out ); + return blargg_ok; + } +}; + +static Music_Emu* new_vgm_emu () { return BLARGG_NEW Vgm_Emu ; } +static Music_Emu* new_vgm_file() { return BLARGG_NEW Vgm_File; } + +gme_type_t_ const gme_vgm_type [1] = {{ "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGM", 1 }}; + +gme_type_t_ const gme_vgz_type [1] = {{ "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGZ", 1 }}; + +// Setup + +void Vgm_Emu::set_tempo_( double t ) +{ + core.set_tempo( t ); +} + +blargg_err_t Vgm_Emu::set_sample_rate_( int sample_rate ) +{ + RETURN_ERR( core.stereo_buf[0].set_sample_rate( sample_rate, 1000 / 30 ) ); + RETURN_ERR( core.stereo_buf[1].set_sample_rate( sample_rate, 1000 / 30 ) ); + RETURN_ERR( core.stereo_buf[2].set_sample_rate( sample_rate, 1000 / 30 ) ); + RETURN_ERR( core.stereo_buf[3].set_sample_rate( sample_rate, 1000 / 30 ) ); + core.set_sample_rate(sample_rate); + return Classic_Emu::set_sample_rate_( sample_rate ); +} + +void Vgm_Emu::update_eq( blip_eq_t const& eq ) +{ + core.psg[0].treble_eq( eq ); + core.psg[1].treble_eq( eq ); + core.ay[0].treble_eq( eq ); + core.ay[1].treble_eq( eq ); + core.huc6280[0].treble_eq( eq ); + core.huc6280[1].treble_eq( eq ); + core.gbdmg[0].treble_eq( eq ); + core.gbdmg[1].treble_eq( eq ); + core.pcm.treble_eq( eq ); +} + +void Vgm_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) +{ + if ( i < core.psg[0].osc_count ) + { + core.psg[0].set_output( i, c, l, r ); + core.psg[1].set_output( i, c, l, r ); + } +} + +void Vgm_Emu::mute_voices_( int mask ) +{ + muted_voices = mask; + + Classic_Emu::mute_voices_( mask ); + + // TODO: what was this for? + //core.pcm.output( &core.blip_buf ); + + // TODO: silence PCM if FM isn't used? + if ( core.uses_fm() ) + { + core.psg[0].set_output( ( mask & 0x80 ) ? 0 : core.stereo_buf[0].center() ); + core.psg[1].set_output( ( mask & 0x80 ) ? 0 : core.stereo_buf[0].center() ); + core.ay[0].set_output( ( mask & 0x80 ) ? 0 : core.stereo_buf[1].center() ); + core.ay[1].set_output( ( mask & 0x80 ) ? 0 : core.stereo_buf[1].center() ); + for ( unsigned i = 0, j = 1; i < core.huc6280[0].osc_count; i++, j <<= 1) + { + Blip_Buffer * center = ( mask & j ) ? 0 : core.stereo_buf[2].center(); + Blip_Buffer * left = ( mask & j ) ? 0 : core.stereo_buf[2].left(); + Blip_Buffer * right = ( mask & j ) ? 0 : core.stereo_buf[2].right(); + core.huc6280[0].set_output( i, center, left, right ); + core.huc6280[1].set_output( i, center, left, right ); + } + for (unsigned i = 0, j = 1; i < core.gbdmg[0].osc_count; i++, j <<= 1) + { + Blip_Buffer * center = (mask & j) ? 0 : core.stereo_buf[3].center(); + Blip_Buffer * left = (mask & j) ? 0 : core.stereo_buf[3].left(); + Blip_Buffer * right = (mask & j) ? 0 : core.stereo_buf[3].right(); + core.gbdmg[0].set_output(i, center, left, right); + core.gbdmg[1].set_output(i, center, left, right); + } + if (core.ym2612[0].enabled()) + { + core.pcm.volume( (mask & 0x40) ? 0.0 : 0.1115 / 256 * fm_gain * gain() ); + core.ym2612[0].mute_voices( mask ); + if ( core.ym2612[1].enabled() ) + core.ym2612[1].mute_voices( mask ); + } + + if ( core.ym2413[0].enabled() ) + { + int m = mask & 0x3F; + if ( mask & 0x20 ) + m |= 0x01E0; // channels 5-8 + if ( mask & 0x40 ) + m |= 0x3E00; + core.ym2413[0].mute_voices( m ); + if ( core.ym2413[1].enabled() ) + core.ym2413[1].mute_voices( m ); + } + + if ( core.ym2151[0].enabled() ) + { + core.ym2151[0].mute_voices( mask ); + if ( core.ym2151[1].enabled() ) + core.ym2151[1].mute_voices( mask ); + } + + if ( core.c140.enabled() ) + { + int m = 0; + int m_add = 7; + for ( unsigned i = 0; i < 8; i++, m_add <<= 3 ) + { + if ( mask & ( 1 << i ) ) m += m_add; + } + core.c140.mute_voices( m ); + } + + if ( core.rf5c68.enabled() ) + { + core.rf5c68.mute_voices( mask ); + } + + if ( core.rf5c164.enabled() ) + { + core.rf5c164.mute_voices( mask ); + } + } +} + +blargg_err_t Vgm_Emu::load_mem_( byte const data [], int size ) +{ + RETURN_ERR( core.load_mem( data, size ) ); + + set_voice_count( core.psg[0].osc_count ); + + double fm_rate = 0.0; + if ( !disable_oversampling_ ) + fm_rate = sample_rate() * oversample_factor; + RETURN_ERR( core.init_chips( &fm_rate ) ); + + double psg_gain = ( ( core.header().psg_rate[3] & 0xC0 ) == 0x40 ) ? 0.5 : 1.0; + + if ( core.uses_fm() ) + { + set_voice_count( 8 ); + RETURN_ERR( resampler.setup( fm_rate / sample_rate(), rolloff, gain() ) ); + RETURN_ERR( resampler.reset( core.stereo_buf[0].length() * sample_rate() / 1000 ) ); + core.psg[0].volume( 0.135 * fm_gain * psg_gain * gain() ); + core.psg[1].volume( 0.135 * fm_gain * psg_gain * gain() ); + core.ay[0].volume( 0.135 * fm_gain * gain() ); + core.ay[1].volume( 0.135 * fm_gain * gain() ); + core.huc6280[0].volume( 0.135 * fm_gain * gain() ); + core.huc6280[1].volume( 0.135 * fm_gain * gain() ); + core.gbdmg[0].volume( 0.135 * fm_gain * gain() ); + core.gbdmg[1].volume( 0.135 * fm_gain * gain() ); + } + else + { + core.psg[0].volume( psg_gain * gain() ); + core.psg[1].volume( psg_gain * gain() ); + } + + static const char* const fm_names [] = { + "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG" + }; + static const char* const psg_names [] = { "Square 1", "Square 2", "Square 3", "Noise" }; + set_voice_names( core.uses_fm() ? fm_names : psg_names ); + + static int const types [8] = { + wave_type+1, wave_type+2, wave_type+3, noise_type+1, + 0, 0, 0, 0 + }; + set_voice_types( types ); + + return Classic_Emu::setup_buffer( core.stereo_buf[0].center()->clock_rate() ); +} + +// Emulation + +blargg_err_t Vgm_Emu::start_track_( int track ) +{ + RETURN_ERR( Classic_Emu::start_track_( track ) ); + + core.start_track(); + + mute_voices_(muted_voices); + + if ( core.uses_fm() ) + resampler.clear(); + + return blargg_ok; +} + +inline void Vgm_Emu::check_end() +{ + if ( core.track_ended() ) + set_track_ended(); +} + +inline void Vgm_Emu::check_warning() +{ + const char* w = core.warning(); + if ( w ) + set_warning( w ); +} + +blargg_err_t Vgm_Emu::run_clocks( blip_time_t& time_io, int msec ) +{ + check_end(); + time_io = core.run_psg( msec ); + check_warning(); + return blargg_ok; +} + +inline int Vgm_Emu::play_frame( blip_time_t blip_time, int sample_count, sample_t buf [] ) +{ + check_end(); + int result = core.play_frame( blip_time, sample_count, buf ); + check_warning(); + return result; +} + +int Vgm_Emu::play_frame_( void* p, blip_time_t a, int b, sample_t c [] ) +{ + return STATIC_CAST(Vgm_Emu*,p)->play_frame( a, b, c ); +} + +blargg_err_t Vgm_Emu::play_( int count, sample_t out [] ) +{ + if ( !core.uses_fm() ) + return Classic_Emu::play_( count, out ); + + Stereo_Buffer * secondaries[] = { &core.stereo_buf[1], &core.stereo_buf[2], &core.stereo_buf[3] }; + resampler.dual_play( count, out, core.stereo_buf[0], secondaries, 3 ); + return blargg_ok; +} + +blargg_err_t Vgm_Emu::hash_( Hash_Function& out ) const +{ + byte const* p = file_begin() + header().size(); + byte const* e = file_end(); + int data_offset = get_le32( header().data_offset ); + if ( data_offset ) + p += data_offset + offsetof( header_t, data_offset ) - header().size(); + int gd3_offset = get_le32( header().gd3_offset ); + if ( gd3_offset > 0 && gd3_offset + offsetof( header_t, gd3_offset ) > data_offset + offsetof( header_t, data_offset ) ) + e = file_begin() + gd3_offset + offsetof( header_t, gd3_offset ); + hash_vgm_file( header(), p, e - p, out ); + return blargg_ok; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ym2151.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ym2151.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ym2151.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ym2151.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,2017 +1,2017 @@ -/***************************************************************************** -* -* Yamaha YM2151 driver (version 2.150 final beta) -* -******************************************************************************/ - -#include "mathdefs.h" -#include -#include -#include -#include "mamedef.h" -#include "ym2151.h" - -#ifndef logerror -#define logerror (void) -#endif - - -/* struct describing a single operator */ -typedef struct -{ - UINT32 phase; /* accumulated operator phase */ - UINT32 freq; /* operator frequency count */ - INT32 dt1; /* current DT1 (detune 1 phase inc/decrement) value */ - UINT32 mul; /* frequency count multiply */ - UINT32 dt1_i; /* DT1 index * 32 */ - UINT32 dt2; /* current DT2 (detune 2) value */ - - signed int *connect; /* operator output 'direction' */ - - /* only M1 (operator 0) is filled with this data: */ - signed int *mem_connect; /* where to put the delayed sample (MEM) */ - INT32 mem_value; /* delayed sample (MEM) value */ - - /* channel specific data; note: each operator number 0 contains channel specific data */ - UINT32 fb_shift; /* feedback shift value for operators 0 in each channel */ - INT32 fb_out_curr; /* operator feedback value (used only by operators 0) */ - INT32 fb_out_prev; /* previous feedback value (used only by operators 0) */ - UINT32 kc; /* channel KC (copied to all operators) */ - UINT32 kc_i; /* just for speedup */ - UINT32 pms; /* channel PMS */ - UINT32 ams; /* channel AMS */ - /* end of channel specific data */ - - UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ - UINT32 state; /* Envelope state: 4-attack(AR) 3-decay(D1R) 2-sustain(D2R) 1-release(RR) 0-off */ - UINT8 eg_sh_ar; /* (attack state) */ - UINT8 eg_sel_ar; /* (attack state) */ - UINT32 tl; /* Total attenuation Level */ - INT32 volume; /* current envelope attenuation level */ - UINT8 eg_sh_d1r; /* (decay state) */ - UINT8 eg_sel_d1r; /* (decay state) */ - UINT32 d1l; /* envelope switches to sustain state after reaching this level */ - UINT8 eg_sh_d2r; /* (sustain state) */ - UINT8 eg_sel_d2r; /* (sustain state) */ - UINT8 eg_sh_rr; /* (release state) */ - UINT8 eg_sel_rr; /* (release state) */ - - UINT32 key; /* 0=last key was KEY OFF, 1=last key was KEY ON */ - - UINT32 ks; /* key scale */ - UINT32 ar; /* attack rate */ - UINT32 d1r; /* decay rate */ - UINT32 d2r; /* sustain rate */ - UINT32 rr; /* release rate */ - - UINT32 reserved0; /**/ - UINT32 reserved1; /**/ - -} YM2151Operator; - - -typedef struct -{ - signed int chanout[8]; - signed int m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */ - signed int mem; /* one sample delay memory */ - - YM2151Operator oper[32]; /* the 32 operators */ - - UINT32 pan[16]; /* channels output masks (0xffffffff = enable) */ - - UINT32 eg_cnt; /* global envelope generator counter */ - UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 */ - UINT32 eg_timer_add; /* step of eg_timer */ - UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 3 samples (on real chip) */ - - UINT32 lfo_phase; /* accumulated LFO phase (0 to 255) */ - UINT32 lfo_timer; /* LFO timer */ - UINT32 lfo_timer_add; /* step of lfo_timer */ - UINT32 lfo_overflow; /* LFO generates new output when lfo_timer reaches this value */ - UINT32 lfo_counter; /* LFO phase increment counter */ - UINT32 lfo_counter_add; /* step of lfo_counter */ - UINT8 lfo_wsel; /* LFO waveform (0-saw, 1-square, 2-triangle, 3-random noise) */ - UINT8 amd; /* LFO Amplitude Modulation Depth */ - INT8 pmd; /* LFO Phase Modulation Depth */ - UINT32 lfa; /* LFO current AM output */ - INT32 lfp; /* LFO current PM output */ - - UINT8 test; /* TEST register */ - UINT8 ct; /* output control pins (bit1-CT2, bit0-CT1) */ - - UINT32 noise; /* noise enable/period register (bit 7 - noise enable, bits 4-0 - noise period */ - UINT32 noise_rng; /* 17 bit noise shift register */ - UINT32 noise_p; /* current noise 'phase'*/ - UINT32 noise_f; /* current noise period */ - - UINT32 csm_req; /* CSM KEY ON / KEY OFF sequence request */ - - UINT32 irq_enable; /* IRQ enable for timer B (bit 3) and timer A (bit 2); bit 7 - CSM mode (keyon to all slots, everytime timer A overflows) */ - UINT32 status; /* chip status (BUSY, IRQ Flags) */ - UINT8 connect[8]; /* channels connections */ - - /* Frequency-deltas to get the closest frequency possible. - * There are 11 octaves because of DT2 (max 950 cents over base frequency) - * and LFO phase modulation (max 800 cents below AND over base frequency) - * Summary: octave explanation - * 0 note code - LFO PM - * 1 note code - * 2 note code - * 3 note code - * 4 note code - * 5 note code - * 6 note code - * 7 note code - * 8 note code - * 9 note code + DT2 + LFO PM - * 10 note code + DT2 + LFO PM - */ - UINT32 freq[11*768]; /* 11 octaves, 768 'cents' per octave */ - - /* Frequency deltas for DT1. These deltas alter operator frequency - * after it has been taken from frequency-deltas table. - */ - INT32 dt1_freq[8*32]; /* 8 DT1 levels, 32 KC values */ - - UINT32 noise_tab[32]; /* 17bit Noise Generator periods */ - - unsigned int clock; /* chip clock in Hz (passed from 2151intf.c) */ - unsigned int sampfreq; /* sampling frequency in Hz (passed from 2151intf.c) */ - - UINT32 mask; -} YM2151; - - -#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ -#define LFO_SH 10 /* 22.10 fixed point (LFO calculations) */ -#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ - -#define FREQ_MASK ((1<>3) - -/* sin waveform table in 'decibel' scale */ -static unsigned int sin_tab[SIN_LEN]; - - -/* translate from D1L to volume index (16 D1L levels) */ -static UINT32 d1l_tab[16]; - - -#define RATE_STEPS (8) -static const UINT8 eg_inc[19*RATE_STEPS]={ - -/*cycle:0 1 2 3 4 5 6 7*/ - -/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */ -/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */ -/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */ -/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */ - -/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */ -/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */ -/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */ -/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */ - -/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */ -/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */ -/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */ -/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */ - -/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */ -/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */ -/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */ -/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */ - -/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */ -/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */ -/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ -}; - - -#define O(a) (a*RATE_STEPS) - -/*note that there is no O(17) in this table - it's directly in the code */ -static const UINT8 eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */ -/* 32 dummy (infinite time) rates */ -O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), -O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), -O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), -O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), - -/* rates 00-11 */ -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), - -/* rate 12 */ -O( 4),O( 5),O( 6),O( 7), - -/* rate 13 */ -O( 8),O( 9),O(10),O(11), - -/* rate 14 */ -O(12),O(13),O(14),O(15), - -/* rate 15 */ -O(16),O(16),O(16),O(16), - -/* 32 dummy rates (same as 15 3) */ -O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), -O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), -O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), -O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16) - -}; -#undef O - -/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/ -/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */ -/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */ - -#define O(a) (a*1) -static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */ -/* 32 infinite time rates */ -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), - - -/* rates 00-11 */ -O(11),O(11),O(11),O(11), -O(10),O(10),O(10),O(10), -O( 9),O( 9),O( 9),O( 9), -O( 8),O( 8),O( 8),O( 8), -O( 7),O( 7),O( 7),O( 7), -O( 6),O( 6),O( 6),O( 6), -O( 5),O( 5),O( 5),O( 5), -O( 4),O( 4),O( 4),O( 4), -O( 3),O( 3),O( 3),O( 3), -O( 2),O( 2),O( 2),O( 2), -O( 1),O( 1),O( 1),O( 1), -O( 0),O( 0),O( 0),O( 0), - -/* rate 12 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 13 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 14 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 15 */ -O( 0),O( 0),O( 0),O( 0), - -/* 32 dummy rates (same as 15 3) */ -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0) - -}; -#undef O - -/* DT2 defines offset in cents from base note -* -* This table defines offset in frequency-deltas table. -* User's Manual page 22 -* -* Values below were calculated using formula: value = orig.val / 1.5625 -* -* DT2=0 DT2=1 DT2=2 DT2=3 -* 0 600 781 950 -*/ -static const UINT32 dt2_tab[4] = { 0, 384, 500, 608 }; - -/* DT1 defines offset in Hertz from base note -* This table is converted while initialization... -* Detune table shown in YM2151 User's Manual is wrong (verified on the real chip) -*/ - -static const UINT8 dt1_tab[4*32] = { /* 4*32 DT1 values */ -/* DT1=0 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -/* DT1=1 */ - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, - -/* DT1=2 */ - 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, - 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, - -/* DT1=3 */ - 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, - 8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 -}; - -static const UINT16 phaseinc_rom[768]={ -1299,1300,1301,1302,1303,1304,1305,1306,1308,1309,1310,1311,1313,1314,1315,1316, -1318,1319,1320,1321,1322,1323,1324,1325,1327,1328,1329,1330,1332,1333,1334,1335, -1337,1338,1339,1340,1341,1342,1343,1344,1346,1347,1348,1349,1351,1352,1353,1354, -1356,1357,1358,1359,1361,1362,1363,1364,1366,1367,1368,1369,1371,1372,1373,1374, -1376,1377,1378,1379,1381,1382,1383,1384,1386,1387,1388,1389,1391,1392,1393,1394, -1396,1397,1398,1399,1401,1402,1403,1404,1406,1407,1408,1409,1411,1412,1413,1414, -1416,1417,1418,1419,1421,1422,1423,1424,1426,1427,1429,1430,1431,1432,1434,1435, -1437,1438,1439,1440,1442,1443,1444,1445,1447,1448,1449,1450,1452,1453,1454,1455, -1458,1459,1460,1461,1463,1464,1465,1466,1468,1469,1471,1472,1473,1474,1476,1477, -1479,1480,1481,1482,1484,1485,1486,1487,1489,1490,1492,1493,1494,1495,1497,1498, -1501,1502,1503,1504,1506,1507,1509,1510,1512,1513,1514,1515,1517,1518,1520,1521, -1523,1524,1525,1526,1528,1529,1531,1532,1534,1535,1536,1537,1539,1540,1542,1543, -1545,1546,1547,1548,1550,1551,1553,1554,1556,1557,1558,1559,1561,1562,1564,1565, -1567,1568,1569,1570,1572,1573,1575,1576,1578,1579,1580,1581,1583,1584,1586,1587, -1590,1591,1592,1593,1595,1596,1598,1599,1601,1602,1604,1605,1607,1608,1609,1610, -1613,1614,1615,1616,1618,1619,1621,1622,1624,1625,1627,1628,1630,1631,1632,1633, -1637,1638,1639,1640,1642,1643,1645,1646,1648,1649,1651,1652,1654,1655,1656,1657, -1660,1661,1663,1664,1666,1667,1669,1670,1672,1673,1675,1676,1678,1679,1681,1682, -1685,1686,1688,1689,1691,1692,1694,1695,1697,1698,1700,1701,1703,1704,1706,1707, -1709,1710,1712,1713,1715,1716,1718,1719,1721,1722,1724,1725,1727,1728,1730,1731, -1734,1735,1737,1738,1740,1741,1743,1744,1746,1748,1749,1751,1752,1754,1755,1757, -1759,1760,1762,1763,1765,1766,1768,1769,1771,1773,1774,1776,1777,1779,1780,1782, -1785,1786,1788,1789,1791,1793,1794,1796,1798,1799,1801,1802,1804,1806,1807,1809, -1811,1812,1814,1815,1817,1819,1820,1822,1824,1825,1827,1828,1830,1832,1833,1835, -1837,1838,1840,1841,1843,1845,1846,1848,1850,1851,1853,1854,1856,1858,1859,1861, -1864,1865,1867,1868,1870,1872,1873,1875,1877,1879,1880,1882,1884,1885,1887,1888, -1891,1892,1894,1895,1897,1899,1900,1902,1904,1906,1907,1909,1911,1912,1914,1915, -1918,1919,1921,1923,1925,1926,1928,1930,1932,1933,1935,1937,1939,1940,1942,1944, -1946,1947,1949,1951,1953,1954,1956,1958,1960,1961,1963,1965,1967,1968,1970,1972, -1975,1976,1978,1980,1982,1983,1985,1987,1989,1990,1992,1994,1996,1997,1999,2001, -2003,2004,2006,2008,2010,2011,2013,2015,2017,2019,2021,2022,2024,2026,2028,2029, -2032,2033,2035,2037,2039,2041,2043,2044,2047,2048,2050,2052,2054,2056,2058,2059, -2062,2063,2065,2067,2069,2071,2073,2074,2077,2078,2080,2082,2084,2086,2088,2089, -2092,2093,2095,2097,2099,2101,2103,2104,2107,2108,2110,2112,2114,2116,2118,2119, -2122,2123,2125,2127,2129,2131,2133,2134,2137,2139,2141,2142,2145,2146,2148,2150, -2153,2154,2156,2158,2160,2162,2164,2165,2168,2170,2172,2173,2176,2177,2179,2181, -2185,2186,2188,2190,2192,2194,2196,2197,2200,2202,2204,2205,2208,2209,2211,2213, -2216,2218,2220,2222,2223,2226,2227,2230,2232,2234,2236,2238,2239,2242,2243,2246, -2249,2251,2253,2255,2256,2259,2260,2263,2265,2267,2269,2271,2272,2275,2276,2279, -2281,2283,2285,2287,2288,2291,2292,2295,2297,2299,2301,2303,2304,2307,2308,2311, -2315,2317,2319,2321,2322,2325,2326,2329,2331,2333,2335,2337,2338,2341,2342,2345, -2348,2350,2352,2354,2355,2358,2359,2362,2364,2366,2368,2370,2371,2374,2375,2378, -2382,2384,2386,2388,2389,2392,2393,2396,2398,2400,2402,2404,2407,2410,2411,2414, -2417,2419,2421,2423,2424,2427,2428,2431,2433,2435,2437,2439,2442,2445,2446,2449, -2452,2454,2456,2458,2459,2462,2463,2466,2468,2470,2472,2474,2477,2480,2481,2484, -2488,2490,2492,2494,2495,2498,2499,2502,2504,2506,2508,2510,2513,2516,2517,2520, -2524,2526,2528,2530,2531,2534,2535,2538,2540,2542,2544,2546,2549,2552,2553,2556, -2561,2563,2565,2567,2568,2571,2572,2575,2577,2579,2581,2583,2586,2589,2590,2593 -}; - - -/* - Noise LFO waveform. - - Here are just 256 samples out of much longer data. - - It does NOT repeat every 256 samples on real chip and I wasnt able to find - the point where it repeats (even in strings as long as 131072 samples). - - I only put it here because its better than nothing and perhaps - someone might be able to figure out the real algorithm. - - - Note that (due to the way the LFO output is calculated) it is quite - possible that two values: 0x80 and 0x00 might be wrong in this table. - To be exact: - some 0x80 could be 0x81 as well as some 0x00 could be 0x01. -*/ - -static const UINT8 lfo_noise_waveform[256] = { -0xFF,0xEE,0xD3,0x80,0x58,0xDA,0x7F,0x94,0x9E,0xE3,0xFA,0x00,0x4D,0xFA,0xFF,0x6A, -0x7A,0xDE,0x49,0xF6,0x00,0x33,0xBB,0x63,0x91,0x60,0x51,0xFF,0x00,0xD8,0x7F,0xDE, -0xDC,0x73,0x21,0x85,0xB2,0x9C,0x5D,0x24,0xCD,0x91,0x9E,0x76,0x7F,0x20,0xFB,0xF3, -0x00,0xA6,0x3E,0x42,0x27,0x69,0xAE,0x33,0x45,0x44,0x11,0x41,0x72,0x73,0xDF,0xA2, - -0x32,0xBD,0x7E,0xA8,0x13,0xEB,0xD3,0x15,0xDD,0xFB,0xC9,0x9D,0x61,0x2F,0xBE,0x9D, -0x23,0x65,0x51,0x6A,0x84,0xF9,0xC9,0xD7,0x23,0xBF,0x65,0x19,0xDC,0x03,0xF3,0x24, -0x33,0xB6,0x1E,0x57,0x5C,0xAC,0x25,0x89,0x4D,0xC5,0x9C,0x99,0x15,0x07,0xCF,0xBA, -0xC5,0x9B,0x15,0x4D,0x8D,0x2A,0x1E,0x1F,0xEA,0x2B,0x2F,0x64,0xA9,0x50,0x3D,0xAB, - -0x50,0x77,0xE9,0xC0,0xAC,0x6D,0x3F,0xCA,0xCF,0x71,0x7D,0x80,0xA6,0xFD,0xFF,0xB5, -0xBD,0x6F,0x24,0x7B,0x00,0x99,0x5D,0xB1,0x48,0xB0,0x28,0x7F,0x80,0xEC,0xBF,0x6F, -0x6E,0x39,0x90,0x42,0xD9,0x4E,0x2E,0x12,0x66,0xC8,0xCF,0x3B,0x3F,0x10,0x7D,0x79, -0x00,0xD3,0x1F,0x21,0x93,0x34,0xD7,0x19,0x22,0xA2,0x08,0x20,0xB9,0xB9,0xEF,0x51, - -0x99,0xDE,0xBF,0xD4,0x09,0x75,0xE9,0x8A,0xEE,0xFD,0xE4,0x4E,0x30,0x17,0xDF,0xCE, -0x11,0xB2,0x28,0x35,0xC2,0x7C,0x64,0xEB,0x91,0x5F,0x32,0x0C,0x6E,0x00,0xF9,0x92, -0x19,0xDB,0x8F,0xAB,0xAE,0xD6,0x12,0xC4,0x26,0x62,0xCE,0xCC,0x0A,0x03,0xE7,0xDD, -0xE2,0x4D,0x8A,0xA6,0x46,0x95,0x0F,0x8F,0xF5,0x15,0x97,0x32,0xD4,0x28,0x1E,0x55 -}; - - - - -/* save output as raw 16-bit sample */ -/* #define SAVE_SAMPLE */ -/* #define SAVE_SEPARATE_CHANNELS */ -#if defined SAVE_SAMPLE || defined SAVE_SEPARATE_CHANNELS -static FILE *sample[9]; -#endif - - - - -static void init_tables(void) -{ - signed int i,x,n; - double o,m; - - for (x=0; x>= 4; /* 12 bits here */ - if (n&1) /* round to closest */ - n = (n>>1)+1; - else - n = n>>1; - /* 11 bits here (rounded) */ - n <<= 2; /* 13 bits here (as in real chip) */ - tl_tab[ x*2 + 0 ] = n; - tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; - - for (i=1; i<13; i++) - { - tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; - tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; - } - #if 0 - logerror("tl %04i", x*2); - for (i=0; i<13; i++) - logerror(", [%02i] %4i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]); - logerror("\n"); - #endif - } - /*logerror("TL_TAB_LEN = %i (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ - /*logerror("ENV_QUIET= %i\n",ENV_QUIET );*/ - - - for (i=0; i0.0) - o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ - else - o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ - - o = o / (ENV_STEP/4); - - n = (int)(2.0*o); - if (n&1) /* round to closest */ - n = (n>>1)+1; - else - n = n>>1; - - sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); - /*logerror("sin [0x%4x]= %4i (tl_tab value=%8x)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/ - } - - - /* calculate d1l_tab table */ - for (i=0; i<16; i++) - { - m = (i!=15 ? i : i+16) * (4.0/ENV_STEP); /* every 3 'dB' except for all bits = 1 = 45+48 'dB' */ - d1l_tab[i] = m; - /*logerror("d1l_tab[%02x]=%08x\n",i,d1l_tab[i] );*/ - } - -#ifdef SAVE_SAMPLE - sample[8]=fopen("sampsum.pcm","wb"); -#endif -#ifdef SAVE_SEPARATE_CHANNELS - sample[0]=fopen("samp0.pcm","wb"); - sample[1]=fopen("samp1.pcm","wb"); - sample[2]=fopen("samp2.pcm","wb"); - sample[3]=fopen("samp3.pcm","wb"); - sample[4]=fopen("samp4.pcm","wb"); - sample[5]=fopen("samp5.pcm","wb"); - sample[6]=fopen("samp6.pcm","wb"); - sample[7]=fopen("samp7.pcm","wb"); -#endif -} - - -static void init_chip_tables(YM2151 *chip) -{ - int i,j; - double mult,phaseinc,Hz; - double scaler; - - scaler = ( (double)chip->clock / 64.0 ) / ( (double)chip->sampfreq ); - if ( fabs( scaler - 1.0 ) < 0.0000001 ) scaler = 1.0; - /*logerror("scaler = %20.15f\n", scaler);*/ - - - /* this loop calculates Hertz values for notes from c-0 to b-7 */ - /* including 64 'cents' (100/64 that is 1.5625 of real cent) per note */ - /* i*100/64/1200 is equal to i/768 */ - - /* real chip works with 10 bits fixed point values (10.10) */ - mult = (1<<(FREQ_SH-10)); /* -10 because phaseinc_rom table values are already in 10.10 format */ - - for (i=0; i<768; i++) - { - /* 3.4375 Hz is note A; C# is 4 semitones higher */ - Hz = 1000; -#if 0 -/* Hz is close, but not perfect */ - //Hz = scaler * 3.4375 * pow (2, (i + 4 * 64 ) / 768.0 ); - /* calculate phase increment */ - phaseinc = (Hz*SIN_LEN) / (double)chip->sampfreq; -#endif - - phaseinc = phaseinc_rom[i]; /* real chip phase increment */ - phaseinc *= scaler; /* adjust */ - - - /* octave 2 - reference octave */ - chip->freq[ 768+2*768+i ] = ((int)(phaseinc*mult)) & 0xffffffc0; /* adjust to X.10 fixed point */ - /* octave 0 and octave 1 */ - for (j=0; j<2; j++) - { - chip->freq[768 + j*768 + i] = (chip->freq[ 768+2*768+i ] >> (2-j) ) & 0xffffffc0; /* adjust to X.10 fixed point */ - } - /* octave 3 to 7 */ - for (j=3; j<8; j++) - { - chip->freq[768 + j*768 + i] = chip->freq[ 768+2*768+i ] << (j-2); - } - } - - /* octave -1 (all equal to: oct 0, _KC_00_, _KF_00_) */ - for (i=0; i<768; i++) - { - chip->freq[ 0*768 + i ] = chip->freq[1*768+0]; - } - - /* octave 8 and 9 (all equal to: oct 7, _KC_14_, _KF_63_) */ - for (j=8; j<10; j++) - { - for (i=0; i<768; i++) - { - chip->freq[768+ j*768 + i ] = chip->freq[768 + 8*768 -1]; - } - } - - mult = (1<clock/64.0) ) / (double)(1<<20); - - /*calculate phase increment*/ - phaseinc = (Hz*SIN_LEN) / (double)chip->sampfreq; - - /*positive and negative values*/ - chip->dt1_freq[ (j+0)*32 + i ] = phaseinc * mult; - chip->dt1_freq[ (j+4)*32 + i ] = -chip->dt1_freq[ (j+0)*32 + i ]; - -#if 0 - { - int x = j*32 + i; - pom = (double)chip->dt1_freq[x] / mult; - pom = pom * (double)chip->sampfreq / (double)SIN_LEN; - logerror("DT1(%03i)[%02i %02i][%08x]= real %19.15f Hz emul %19.15f Hz\n", - x, j, i, chip->dt1_freq[x], Hz, pom); - } -#endif - } - } - - - /* calculate noise periods table */ - scaler = ( (double)chip->clock / 64.0 ) / ( (double)chip->sampfreq ); - if ( fabs( scaler - 1.0 ) < 0.0000001 ) scaler = 1.0; - for (i=0; i<32; i++) - { - j = (i!=31 ? i : 30); /* rate 30 and 31 are the same */ - j = 32-j; - j = (65536.0 / (double)(j*32.0)); /* number of samples per one shift of the shift register */ - /*chip->noise_tab[i] = j * 64;*/ /* number of chip clock cycles per one shift */ - chip->noise_tab[i] = j * 64 * scaler; - /*logerror("noise_tab[%02x]=%08x\n", i, chip->noise_tab[i]);*/ - } -} - -#define KEY_ON(op, key_set){ \ - if (!(op)->key) \ - { \ - (op)->phase = 0; /* clear phase */ \ - (op)->state = EG_ATT; /* KEY ON = attack */ \ - (op)->volume += (~(op)->volume * \ - (eg_inc[(op)->eg_sel_ar + ((PSG->eg_cnt>>(op)->eg_sh_ar)&7)]) \ - ) >>4; \ - if ((op)->volume <= MIN_ATT_INDEX) \ - { \ - (op)->volume = MIN_ATT_INDEX; \ - (op)->state = EG_DEC; \ - } \ - } \ - (op)->key |= key_set; \ -} - -#define KEY_OFF(op, key_clr){ \ - if ((op)->key) \ - { \ - (op)->key &= key_clr; \ - if (!(op)->key) \ - { \ - if ((op)->state>EG_REL) \ - (op)->state = EG_REL;/* KEY OFF = release */\ - } \ - } \ -} - -INLINE void envelope_KONKOFF(YM2151 *PSG, YM2151Operator * op, int v) -{ - if (v&0x08) /* M1 */ - KEY_ON (op+0, 1) - else - KEY_OFF(op+0,~1) - - if (v&0x20) /* M2 */ - KEY_ON (op+1, 1) - else - KEY_OFF(op+1,~1) - - if (v&0x10) /* C1 */ - KEY_ON (op+2, 1) - else - KEY_OFF(op+2,~1) - - if (v&0x40) /* C2 */ - KEY_ON (op+3, 1) - else - KEY_OFF(op+3,~1) -} - - -INLINE void set_connect(YM2151 *PSG, YM2151Operator *om1, int cha, int v) -{ - YM2151Operator *om2 = om1+1; - YM2151Operator *oc1 = om1+2; - - /* set connect algorithm */ - - /* MEM is simply one sample delay */ - - switch( v&7 ) - { - case 0: - /* M1---C1---MEM---M2---C2---OUT */ - om1->connect = &PSG->c1; - oc1->connect = &PSG->mem; - om2->connect = &PSG->c2; - om1->mem_connect = &PSG->m2; - break; - - case 1: - /* M1------+-MEM---M2---C2---OUT */ - /* C1-+ */ - om1->connect = &PSG->mem; - oc1->connect = &PSG->mem; - om2->connect = &PSG->c2; - om1->mem_connect = &PSG->m2; - break; - - case 2: - /* M1-----------------+-C2---OUT */ - /* C1---MEM---M2-+ */ - om1->connect = &PSG->c2; - oc1->connect = &PSG->mem; - om2->connect = &PSG->c2; - om1->mem_connect = &PSG->m2; - break; - - case 3: - /* M1---C1---MEM------+-C2---OUT */ - /* M2-+ */ - om1->connect = &PSG->c1; - oc1->connect = &PSG->mem; - om2->connect = &PSG->c2; - om1->mem_connect = &PSG->c2; - break; - - case 4: - /* M1---C1-+-OUT */ - /* M2---C2-+ */ - /* MEM: not used */ - om1->connect = &PSG->c1; - oc1->connect = &PSG->chanout[cha]; - om2->connect = &PSG->c2; - om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ - break; - - case 5: - /* +----C1----+ */ - /* M1-+-MEM---M2-+-OUT */ - /* +----C2----+ */ - om1->connect = 0; /* special mark */ - oc1->connect = &PSG->chanout[cha]; - om2->connect = &PSG->chanout[cha]; - om1->mem_connect = &PSG->m2; - break; - - case 6: - /* M1---C1-+ */ - /* M2-+-OUT */ - /* C2-+ */ - /* MEM: not used */ - om1->connect = &PSG->c1; - oc1->connect = &PSG->chanout[cha]; - om2->connect = &PSG->chanout[cha]; - om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ - break; - - case 7: - /* M1-+ */ - /* C1-+-OUT */ - /* M2-+ */ - /* C2-+ */ - /* MEM: not used*/ - om1->connect = &PSG->chanout[cha]; - oc1->connect = &PSG->chanout[cha]; - om2->connect = &PSG->chanout[cha]; - om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ - break; - } -} - - -INLINE void refresh_EG(YM2151Operator * op) -{ - UINT32 kc; - UINT32 v; - - kc = op->kc; - - /* v = 32 + 2*RATE + RKS = max 126 */ - - v = kc >> op->ks; - if ((op->ar+v) < 32+62) - { - op->eg_sh_ar = eg_rate_shift [op->ar + v ]; - op->eg_sel_ar = eg_rate_select[op->ar + v ]; - } - else - { - op->eg_sh_ar = 0; - op->eg_sel_ar = 17*RATE_STEPS; - } - op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; - op->eg_sel_d1r= eg_rate_select[op->d1r + v]; - op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; - op->eg_sel_d2r= eg_rate_select[op->d2r + v]; - op->eg_sh_rr = eg_rate_shift [op->rr + v]; - op->eg_sel_rr = eg_rate_select[op->rr + v]; - - - op+=1; - - v = kc >> op->ks; - if ((op->ar+v) < 32+62) - { - op->eg_sh_ar = eg_rate_shift [op->ar + v ]; - op->eg_sel_ar = eg_rate_select[op->ar + v ]; - } - else - { - op->eg_sh_ar = 0; - op->eg_sel_ar = 17*RATE_STEPS; - } - op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; - op->eg_sel_d1r= eg_rate_select[op->d1r + v]; - op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; - op->eg_sel_d2r= eg_rate_select[op->d2r + v]; - op->eg_sh_rr = eg_rate_shift [op->rr + v]; - op->eg_sel_rr = eg_rate_select[op->rr + v]; - - op+=1; - - v = kc >> op->ks; - if ((op->ar+v) < 32+62) - { - op->eg_sh_ar = eg_rate_shift [op->ar + v ]; - op->eg_sel_ar = eg_rate_select[op->ar + v ]; - } - else - { - op->eg_sh_ar = 0; - op->eg_sel_ar = 17*RATE_STEPS; - } - op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; - op->eg_sel_d1r= eg_rate_select[op->d1r + v]; - op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; - op->eg_sel_d2r= eg_rate_select[op->d2r + v]; - op->eg_sh_rr = eg_rate_shift [op->rr + v]; - op->eg_sel_rr = eg_rate_select[op->rr + v]; - - op+=1; - - v = kc >> op->ks; - if ((op->ar+v) < 32+62) - { - op->eg_sh_ar = eg_rate_shift [op->ar + v ]; - op->eg_sel_ar = eg_rate_select[op->ar + v ]; - } - else - { - op->eg_sh_ar = 0; - op->eg_sel_ar = 17*RATE_STEPS; - } - op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; - op->eg_sel_d1r= eg_rate_select[op->d1r + v]; - op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; - op->eg_sel_d2r= eg_rate_select[op->d2r + v]; - op->eg_sh_rr = eg_rate_shift [op->rr + v]; - op->eg_sel_rr = eg_rate_select[op->rr + v]; -} - - -/* write a register on YM2151 chip number 'n' */ -void ym2151_write_reg(void *_chip, int r, int v) -{ - YM2151 *chip = (YM2151 *)_chip; - YM2151Operator *op = &chip->oper[ (r&0x07)*4+((r&0x18)>>3) ]; - - /* adjust bus to 8 bits */ - r &= 0xff; - v &= 0xff; - -#if 0 - /* There is no info on what YM2151 really does when busy flag is set */ - if ( chip->status & 0x80 ) return; - timer_set ( attotime::from_hz(chip->clock) * 64, chip, 0, timer_callback_chip_busy); - chip->status |= 0x80; /* set busy flag for 64 chip clock cycles */ -#endif - - - switch(r & 0xe0) - { - case 0x00: - switch(r){ - case 0x01: /* LFO reset(bit 1), Test Register (other bits) */ - chip->test = v; - if (v&2) chip->lfo_phase = 0; - break; - - case 0x08: - envelope_KONKOFF(chip, &chip->oper[ (v&7)*4 ], v ); - break; - - case 0x0f: /* noise mode enable, noise period */ - chip->noise = v; - chip->noise_f = chip->noise_tab[ v & 0x1f ]; - break; - - case 0x10: /* timer A hi */ - break; - - case 0x11: /* timer A low */ - break; - - case 0x12: /* timer B */ - break; - - case 0x14: /* CSM, irq flag reset, irq enable, timer start/stop */ - - chip->irq_enable = v; /* bit 3-timer B, bit 2-timer A, bit 7 - CSM */ - - break; - - case 0x18: /* LFO frequency */ - { - chip->lfo_overflow = ( 1 << ((15-(v>>4))+3) ) * (1<lfo_counter_add = 0x10 + (v & 0x0f); - } - break; - - case 0x19: /* PMD (bit 7==1) or AMD (bit 7==0) */ - if (v&0x80) - chip->pmd = v & 0x7f; - else - chip->amd = v & 0x7f; - break; - - case 0x1b: /* CT2, CT1, LFO waveform */ - chip->ct = v >> 6; - chip->lfo_wsel = v & 3; - break; - - default: - /*logerror("YM2151 Write %02x to undocumented register #%02x\n",v,r);*/ - break; - } - break; - - case 0x20: - op = &chip->oper[ (r&7) * 4 ]; - switch(r & 0x18) - { - case 0x00: /* RL enable, Feedback, Connection */ - op->fb_shift = ((v>>3)&7) ? ((v>>3)&7)+6:0; - chip->pan[ (r&7)*2 ] = (v & 0x40) ? ~0 : 0; - chip->pan[ (r&7)*2 +1 ] = (v & 0x80) ? ~0 : 0; - chip->connect[r&7] = v&7; - set_connect(chip, op, r&7, v&7); - break; - - case 0x08: /* Key Code */ - v &= 0x7f; - if (v != (int)(op->kc)) - { - UINT32 kc, kc_channel; - - kc_channel = (v - (v>>2))*64; - kc_channel += 768; - kc_channel |= (op->kc_i & 63); - - (op+0)->kc = v; - (op+0)->kc_i = kc_channel; - (op+1)->kc = v; - (op+1)->kc_i = kc_channel; - (op+2)->kc = v; - (op+2)->kc_i = kc_channel; - (op+3)->kc = v; - (op+3)->kc_i = kc_channel; - - kc = v>>2; - - (op+0)->dt1 = chip->dt1_freq[ (op+0)->dt1_i + kc ]; - (op+0)->freq = ( (chip->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; - - (op+1)->dt1 = chip->dt1_freq[ (op+1)->dt1_i + kc ]; - (op+1)->freq = ( (chip->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; - - (op+2)->dt1 = chip->dt1_freq[ (op+2)->dt1_i + kc ]; - (op+2)->freq = ( (chip->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; - - (op+3)->dt1 = chip->dt1_freq[ (op+3)->dt1_i + kc ]; - (op+3)->freq = ( (chip->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; - - refresh_EG( op ); - } - break; - - case 0x10: /* Key Fraction */ - v >>= 2; - if (v != (int)(op->kc_i & 63)) - { - UINT32 kc_channel; - - kc_channel = v; - kc_channel |= (op->kc_i & ~63); - - (op+0)->kc_i = kc_channel; - (op+1)->kc_i = kc_channel; - (op+2)->kc_i = kc_channel; - (op+3)->kc_i = kc_channel; - - (op+0)->freq = ( (chip->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; - (op+1)->freq = ( (chip->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; - (op+2)->freq = ( (chip->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; - (op+3)->freq = ( (chip->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; - } - break; - - case 0x18: /* PMS, AMS */ - op->pms = (v>>4) & 7; - op->ams = (v & 3); - break; - } - break; - - case 0x40: /* DT1, MUL */ - { - UINT32 olddt1_i = op->dt1_i; - UINT32 oldmul = op->mul; - - op->dt1_i = (v&0x70)<<1; - op->mul = (v&0x0f) ? (v&0x0f)<<1: 1; - - if (olddt1_i != op->dt1_i) - op->dt1 = chip->dt1_freq[ op->dt1_i + (op->kc>>2) ]; - - if ( (olddt1_i != op->dt1_i) || (oldmul != op->mul) ) - op->freq = ( (chip->freq[ op->kc_i + op->dt2 ] + op->dt1) * op->mul ) >> 1; - } - break; - - case 0x60: /* TL */ - op->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */ - break; - - case 0x80: /* KS, AR */ - { - UINT32 oldks = op->ks; - UINT32 oldar = op->ar; - - op->ks = 5-(v>>6); - op->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; - - if ( (op->ar != oldar) || (op->ks != oldks) ) - { - if ((op->ar + (op->kc>>op->ks)) < 32+62) - { - op->eg_sh_ar = eg_rate_shift [op->ar + (op->kc>>op->ks) ]; - op->eg_sel_ar = eg_rate_select[op->ar + (op->kc>>op->ks) ]; - } - else - { - op->eg_sh_ar = 0; - op->eg_sel_ar = 17*RATE_STEPS; - } - } - - if (op->ks != oldks) - { - op->eg_sh_d1r = eg_rate_shift [op->d1r + (op->kc>>op->ks) ]; - op->eg_sel_d1r= eg_rate_select[op->d1r + (op->kc>>op->ks) ]; - op->eg_sh_d2r = eg_rate_shift [op->d2r + (op->kc>>op->ks) ]; - op->eg_sel_d2r= eg_rate_select[op->d2r + (op->kc>>op->ks) ]; - op->eg_sh_rr = eg_rate_shift [op->rr + (op->kc>>op->ks) ]; - op->eg_sel_rr = eg_rate_select[op->rr + (op->kc>>op->ks) ]; - } - } - break; - - case 0xa0: /* LFO AM enable, D1R */ - op->AMmask = (v&0x80) ? ~0 : 0; - op->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; - op->eg_sh_d1r = eg_rate_shift [op->d1r + (op->kc>>op->ks) ]; - op->eg_sel_d1r= eg_rate_select[op->d1r + (op->kc>>op->ks) ]; - break; - - case 0xc0: /* DT2, D2R */ - { - UINT32 olddt2 = op->dt2; - op->dt2 = dt2_tab[ v>>6 ]; - if (op->dt2 != olddt2) - op->freq = ( (chip->freq[ op->kc_i + op->dt2 ] + op->dt1) * op->mul ) >> 1; - } - op->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; - op->eg_sh_d2r = eg_rate_shift [op->d2r + (op->kc>>op->ks) ]; - op->eg_sel_d2r= eg_rate_select[op->d2r + (op->kc>>op->ks) ]; - break; - - case 0xe0: /* D1L, RR */ - op->d1l = d1l_tab[ v>>4 ]; - op->rr = 34 + ((v&0x0f)<<2); - op->eg_sh_rr = eg_rate_shift [op->rr + (op->kc>>op->ks) ]; - op->eg_sel_rr = eg_rate_select[op->rr + (op->kc>>op->ks) ]; - break; - } -} - - -/* -* Initialize YM2151 emulator(s). -* -* 'num' is the number of virtual YM2151's to allocate -* 'clock' is the chip clock in Hz -* 'rate' is sampling rate -*/ -void * ym2151_init(int clock, int rate) -{ - YM2151 *PSG; - - PSG = (YM2151 *) malloc(sizeof(YM2151)); - - memset(PSG, 0, sizeof(YM2151)); - - init_tables(); - - PSG->clock = clock; - /*rate = clock/64;*/ - PSG->sampfreq = rate ? rate : 44100; /* avoid division by 0 in init_chip_tables() */ - init_chip_tables( PSG ); - - PSG->lfo_timer_add = (1<sampfreq; - - PSG->eg_timer_add = (1<sampfreq; - PSG->eg_timer_overflow = ( 3 ) * (1<eg_timer_add, PSG->eg_timer_overflow);*/ - - ym2151_reset_chip(PSG); - /*logerror("YM2151[init] clock=%i sampfreq=%i\n", PSG->clock, PSG->sampfreq);*/ - - return PSG; -} - - - -void ym2151_shutdown(void *_chip) -{ - YM2151 *chip = (YM2151 *)_chip; - - free (chip); - -#ifdef SAVE_SAMPLE - fclose(sample[8]); -#endif -#ifdef SAVE_SEPARATE_CHANNELS - fclose(sample[0]); - fclose(sample[1]); - fclose(sample[2]); - fclose(sample[3]); - fclose(sample[4]); - fclose(sample[5]); - fclose(sample[6]); - fclose(sample[7]); -#endif -} - - - -/* -* Reset chip number 'n'. -*/ -void ym2151_reset_chip(void *_chip) -{ - int i; - YM2151 *chip = (YM2151 *)_chip; - - - /* initialize hardware registers */ - for (i=0; i<32; i++) - { - memset(&chip->oper[i],'\0',sizeof(YM2151Operator)); - chip->oper[i].volume = MAX_ATT_INDEX; - chip->oper[i].kc_i = 768; /* min kc_i value */ - } - - chip->eg_timer = 0; - chip->eg_cnt = 0; - - chip->lfo_timer = 0; - chip->lfo_counter= 0; - chip->lfo_phase = 0; - chip->lfo_wsel = 0; - chip->pmd = 0; - chip->amd = 0; - chip->lfa = 0; - chip->lfp = 0; - - chip->test= 0; - - chip->irq_enable = 0; - - chip->noise = 0; - chip->noise_rng = 0; - chip->noise_p = 0; - chip->noise_f = chip->noise_tab[0]; - - chip->csm_req = 0; - chip->status = 0; - - ym2151_write_reg(chip, 0x1b, 0); /* only because of CT1, CT2 output pins */ - ym2151_write_reg(chip, 0x18, 0); /* set LFO frequency */ - for (i=0x20; i<0x100; i++) /* set the operators */ - { - ym2151_write_reg(chip, i, 0); - } -} - - - -INLINE signed int op_calc(YM2151Operator * OP, unsigned int env, signed int pm) -{ - UINT32 p; - - - p = (env<<3) + sin_tab[ ( ((signed int)((OP->phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ]; - - if (p >= TL_TAB_LEN) - return 0; - - return tl_tab[p]; -} - -INLINE signed int op_calc1(YM2151Operator * OP, unsigned int env, signed int pm) -{ - UINT32 p; - INT32 i; - - - i = (OP->phase & ~FREQ_MASK) + pm; - -/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, OP->phase>>FREQ_SH, pm);*/ - - p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK]; - -/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ - - if (p >= TL_TAB_LEN) - return 0; - - return tl_tab[p]; -} - - - -#define volume_calc(OP) ((OP)->tl + ((UINT32)(OP)->volume) + (AM & (OP)->AMmask)) - -INLINE void chan_calc(YM2151 *PSG, unsigned int chan) -{ - YM2151Operator *op; - unsigned int env; - UINT32 AM = 0; - - PSG->m2 = PSG->c1 = PSG->c2 = PSG->mem = 0; - op = &PSG->oper[chan*4]; /* M1 */ - - *op->mem_connect = op->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ - - if (op->ams) - AM = PSG->lfa << (op->ams-1); - env = volume_calc(op); - { - INT32 out = op->fb_out_prev + op->fb_out_curr; - op->fb_out_prev = op->fb_out_curr; - - if (!op->connect) - /* algorithm 5 */ - PSG->mem = PSG->c1 = PSG->c2 = op->fb_out_prev; - else - /* other algorithms */ - *op->connect = op->fb_out_prev; - - op->fb_out_curr = 0; - if (env < ENV_QUIET) - { - if (!op->fb_shift) - out=0; - op->fb_out_curr = op_calc1(op, env, (out<fb_shift) ); - } - } - - env = volume_calc(op+1); /* M2 */ - if (env < ENV_QUIET) - *(op+1)->connect += op_calc(op+1, env, PSG->m2); - - env = volume_calc(op+2); /* C1 */ - if (env < ENV_QUIET) - *(op+2)->connect += op_calc(op+2, env, PSG->c1); - - env = volume_calc(op+3); /* C2 */ - if (env < ENV_QUIET) - PSG->chanout[chan] += op_calc(op+3, env, PSG->c2); - - /* M1 */ - op->mem_value = PSG->mem; -} - -INLINE void chan7_calc(YM2151 *PSG) -{ - YM2151Operator *op; - unsigned int env; - UINT32 AM = 0; - - PSG->m2 = PSG->c1 = PSG->c2 = PSG->mem = 0; - op = &PSG->oper[7*4]; /* M1 */ - - *op->mem_connect = op->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ - - if (op->ams) - AM = PSG->lfa << (op->ams-1); - env = volume_calc(op); - { - INT32 out = op->fb_out_prev + op->fb_out_curr; - op->fb_out_prev = op->fb_out_curr; - - if (!op->connect) - /* algorithm 5 */ - PSG->mem = PSG->c1 = PSG->c2 = op->fb_out_prev; - else - /* other algorithms */ - *op->connect = op->fb_out_prev; - - op->fb_out_curr = 0; - if (env < ENV_QUIET) - { - if (!op->fb_shift) - out=0; - op->fb_out_curr = op_calc1(op, env, (out<fb_shift) ); - } - } - - env = volume_calc(op+1); /* M2 */ - if (env < ENV_QUIET) - *(op+1)->connect += op_calc(op+1, env, PSG->m2); - - env = volume_calc(op+2); /* C1 */ - if (env < ENV_QUIET) - *(op+2)->connect += op_calc(op+2, env, PSG->c1); - - env = volume_calc(op+3); /* C2 */ - if (PSG->noise & 0x80) - { - UINT32 noiseout; - - noiseout = 0; - if (env < 0x3ff) - noiseout = (env ^ 0x3ff) * 2; /* range of the YM2151 noise output is -2044 to 2040 */ -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4146) -#endif - PSG->chanout[7] += ((PSG->noise_rng&0x10000) ? noiseout: -noiseout); /* bit 16 -> output */ -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - } - else - { - if (env < ENV_QUIET) - PSG->chanout[7] += op_calc(op+3, env, PSG->c2); - } - /* M1 */ - op->mem_value = PSG->mem; -} - - - - - - -/* -The 'rate' is calculated from following formula (example on decay rate): - rks = notecode after key scaling (a value from 0 to 31) - DR = value written to the chip register - rate = 2*DR + rks; (max rate = 2*31+31 = 93) -Four MSBs of the 'rate' above are the 'main' rate (from 00 to 15) -Two LSBs of the 'rate' above are the value 'x' (the shape type). -(eg. '11 2' means that 'rate' is 11*4+2=46) - -NOTE: A 'sample' in the description below is actually 3 output samples, -thats because the Envelope Generator clock is equal to internal_clock/3. - -Single '-' (minus) character in the diagrams below represents one sample -on the output; this is for rates 11 x (11 0, 11 1, 11 2 and 11 3) - -these 'main' rates: -00 x: single '-' = 2048 samples; (ie. level can change every 2048 samples) -01 x: single '-' = 1024 samples; -02 x: single '-' = 512 samples; -03 x: single '-' = 256 samples; -04 x: single '-' = 128 samples; -05 x: single '-' = 64 samples; -06 x: single '-' = 32 samples; -07 x: single '-' = 16 samples; -08 x: single '-' = 8 samples; -09 x: single '-' = 4 samples; -10 x: single '-' = 2 samples; -11 x: single '-' = 1 sample; (ie. level can change every 1 sample) - -Shapes for rates 11 x look like this: -rate: step: -11 0 01234567 - -level: -0 -- -1 -- -2 -- -3 -- - -rate: step: -11 1 01234567 - -level: -0 -- -1 -- -2 - -3 - -4 -- - -rate: step: -11 2 01234567 - -level: -0 -- -1 - -2 - -3 -- -4 - -5 - - -rate: step: -11 3 01234567 - -level: -0 -- -1 - -2 - -3 - -4 - -5 - -6 - - - -For rates 12 x, 13 x, 14 x and 15 x output level changes on every -sample - this means that the waveform looks like this: (but the level -changes by different values on different steps) -12 3 01234567 - -0 - -2 - -4 - -8 - -10 - -12 - -14 - -18 - -20 - - -Notes about the timing: ----------------------- - -1. Synchronism - -Output level of each two (or more) voices running at the same 'main' rate -(eg 11 0 and 11 1 in the diagram below) will always be changing in sync, -even if there're started with some delay. - -Note that, in the diagram below, the decay phase in channel 0 starts at -sample #2, while in channel 1 it starts at sample #6. Anyway, both channels -will always change their levels at exactly the same (following) samples. - -(S - start point of this channel, A-attack phase, D-decay phase): - -step: -01234567012345670123456 - -channel 0: - -- - | -- - | - - | - - | -- - | -- -| -- -| - -| - -| -- -AADDDDDDDDDDDDDDDD -S - -01234567012345670123456 -channel 1: - - - | - - | -- - | -- - | -- - | - - | - - | -- - | -- - | -- - AADDDDDDDDDDDDDDDD - S -01234567012345670123456 - - -2. Shifted (delayed) synchronism - -Output of each two (or more) voices running at different 'main' rate -(9 1, 10 1 and 11 1 in the diagrams below) will always be changing -in 'delayed-sync' (even if there're started with some delay as in "1.") - -Note that the shapes are delayed by exactly one sample per one 'main' rate -increment. (Normally one would expect them to start at the same samples.) - -See diagram below (* - start point of the shape). - -cycle: -0123456701234567012345670123456701234567012345670123456701234567 - -rate 09 1 -*------- - -------- - ---- - ---- - -------- - *------- - | -------- - | ---- - | ---- - | -------- -rate 10 1 | --- | - *--- | - ---- | - -- | - -- | - ---- | - *--- | - | ---- | - | -- | | <- one step (two samples) delay between 9 1 and 10 1 - | -- | | - | ----| - | *--- - | ---- - | -- - | -- - | ---- -rate 11 1 | -- | - -- | - *- | - -- | - - | - - | - -- | - *- | - -- | - - || <- one step (one sample) delay between 10 1 and 11 1 - - || - --| - *- - -- - - - - - -- - *- - -- - - - - - -- -*/ - -INLINE void advance_eg(YM2151 *PSG) -{ - YM2151Operator *op; - unsigned int i; - - - - PSG->eg_timer += PSG->eg_timer_add; - - while (PSG->eg_timer >= PSG->eg_timer_overflow) - { - PSG->eg_timer -= PSG->eg_timer_overflow; - - PSG->eg_cnt++; - - /* envelope generator */ - op = &PSG->oper[0]; /* CH 0 M1 */ - i = 32; - do - { - switch(op->state) - { - case EG_ATT: /* attack phase */ - if ( !(PSG->eg_cnt & ((1<eg_sh_ar)-1) ) ) - { - op->volume += (~op->volume * - (eg_inc[op->eg_sel_ar + ((PSG->eg_cnt>>op->eg_sh_ar)&7)]) - ) >>4; - - if (op->volume <= MIN_ATT_INDEX) - { - op->volume = MIN_ATT_INDEX; - op->state = EG_DEC; - } - - } - break; - - case EG_DEC: /* decay phase */ - if ( !(PSG->eg_cnt & ((1<eg_sh_d1r)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_d1r + ((PSG->eg_cnt>>op->eg_sh_d1r)&7)]; - - if ( op->volume >= (INT32)(op->d1l) ) - op->state = EG_SUS; - - } - break; - - case EG_SUS: /* sustain phase */ - if ( !(PSG->eg_cnt & ((1<eg_sh_d2r)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_d2r + ((PSG->eg_cnt>>op->eg_sh_d2r)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_OFF; - } - - } - break; - - case EG_REL: /* release phase */ - if ( !(PSG->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((PSG->eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_OFF; - } - - } - break; - } - op++; - i--; - }while (i); - } -} - - -INLINE void advance(YM2151 *PSG) -{ - YM2151Operator *op; - unsigned int i; - int a,p; - - /* LFO */ - if (PSG->test&2) - PSG->lfo_phase = 0; - else - { - PSG->lfo_timer += PSG->lfo_timer_add; - if (PSG->lfo_timer >= PSG->lfo_overflow) - { - PSG->lfo_timer -= PSG->lfo_overflow; - PSG->lfo_counter += PSG->lfo_counter_add; - PSG->lfo_phase += (PSG->lfo_counter>>4); - PSG->lfo_phase &= 255; - PSG->lfo_counter &= 15; - } - } - - i = PSG->lfo_phase; - /* calculate LFO AM and PM waveform value (all verified on real chip, except for noise algorithm which is impossible to analyse)*/ - switch (PSG->lfo_wsel) - { - case 0: - /* saw */ - /* AM: 255 down to 0 */ - /* PM: 0 to 127, -127 to 0 (at PMD=127: LFP = 0 to 126, -126 to 0) */ - a = 255 - i; - if (i<128) - p = i; - else - p = i - 255; - break; - case 1: - /* square */ - /* AM: 255, 0 */ - /* PM: 128,-128 (LFP = exactly +PMD, -PMD) */ - if (i<128) - { - a = 255; - p = 128; - } - else - { - a = 0; - p = -128; - } - break; - case 2: - /* triangle */ - /* AM: 255 down to 1 step -2; 0 up to 254 step +2 */ - /* PM: 0 to 126 step +2, 127 to 1 step -2, 0 to -126 step -2, -127 to -1 step +2*/ - if (i<128) - a = 255 - (i*2); - else - a = (i*2) - 256; - - if (i<64) /* i = 0..63 */ - p = i*2; /* 0 to 126 step +2 */ - else if (i<128) /* i = 64..127 */ - p = 255 - i*2; /* 127 to 1 step -2 */ - else if (i<192) /* i = 128..191 */ - p = 256 - i*2; /* 0 to -126 step -2*/ - else /* i = 192..255 */ - p = i*2 - 511; /*-127 to -1 step +2*/ - break; - case 3: - default: /*keep the compiler happy*/ - /* random */ - /* the real algorithm is unknown !!! - We just use a snapshot of data from real chip */ - - /* AM: range 0 to 255 */ - /* PM: range -128 to 127 */ - - a = lfo_noise_waveform[i]; - p = a-128; - break; - } - PSG->lfa = a * PSG->amd / 128; - PSG->lfp = p * PSG->pmd / 128; - - - /* The Noise Generator of the YM2151 is 17-bit shift register. - * Input to the bit16 is negated (bit0 XOR bit3) (EXNOR). - * Output of the register is negated (bit0 XOR bit3). - * Simply use bit16 as the noise output. - */ - PSG->noise_p += PSG->noise_f; - i = (PSG->noise_p>>16); /* number of events (shifts of the shift register) */ - PSG->noise_p &= 0xffff; - while (i) - { - UINT32 j; - j = ( (PSG->noise_rng ^ (PSG->noise_rng>>3) ) & 1) ^ 1; - PSG->noise_rng = (j<<16) | (PSG->noise_rng>>1); - i--; - } - - - /* phase generator */ - op = &PSG->oper[0]; /* CH 0 M1 */ - i = 8; - do - { - if (op->pms) /* only when phase modulation from LFO is enabled for this channel */ - { - INT32 mod_ind = PSG->lfp; /* -128..+127 (8bits signed) */ - if (op->pms < 6) - mod_ind >>= (6 - op->pms); - else - mod_ind <<= (op->pms - 5); - - if (mod_ind) - { - UINT32 kc_channel = op->kc_i + mod_ind; - (op+0)->phase += ( (PSG->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; - (op+1)->phase += ( (PSG->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; - (op+2)->phase += ( (PSG->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; - (op+3)->phase += ( (PSG->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; - } - else /* phase modulation from LFO is equal to zero */ - { - (op+0)->phase += (op+0)->freq; - (op+1)->phase += (op+1)->freq; - (op+2)->phase += (op+2)->freq; - (op+3)->phase += (op+3)->freq; - } - } - else /* phase modulation from LFO is disabled */ - { - (op+0)->phase += (op+0)->freq; - (op+1)->phase += (op+1)->freq; - (op+2)->phase += (op+2)->freq; - (op+3)->phase += (op+3)->freq; - } - - op+=4; - i--; - }while (i); - - - /* CSM is calculated *after* the phase generator calculations (verified on real chip) - * CSM keyon line seems to be ORed with the KO line inside of the chip. - * The result is that it only works when KO (register 0x08) is off, ie. 0 - * - * Interesting effect is that when timer A is set to 1023, the KEY ON happens - * on every sample, so there is no KEY OFF at all - the result is that - * the sound played is the same as after normal KEY ON. - */ - - if (PSG->csm_req) /* CSM KEYON/KEYOFF seqeunce request */ - { - if (PSG->csm_req==2) /* KEY ON */ - { - op = &PSG->oper[0]; /* CH 0 M1 */ - i = 32; - do - { - KEY_ON(op, 2); - op++; - i--; - }while (i); - PSG->csm_req = 1; - } - else /* KEY OFF */ - { - op = &PSG->oper[0]; /* CH 0 M1 */ - i = 32; - do - { - KEY_OFF(op,~2); - op++; - i--; - }while (i); - PSG->csm_req = 0; - } - } -} - -/* first macro saves left and right channels to mono file */ -/* second macro saves left and right channels to stereo file */ -#if 0 /*MONO*/ - #ifdef SAVE_SEPARATE_CHANNELS - #define SAVE_SINGLE_CHANNEL(j) \ - { signed int pom= -(chanout[j] & PSG->pan[j*2]); \ - if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ - fputc((unsigned short)pom&0xff,sample[j]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ - } - #else - #define SAVE_SINGLE_CHANNEL(j) - #endif -#else /*STEREO*/ - #ifdef SAVE_SEPARATE_CHANNELS - #define SAVE_SINGLE_CHANNEL(j) \ - { signed int pom = -(chanout[j] & PSG->pan[j*2]); \ - if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ - fputc((unsigned short)pom&0xff,sample[j]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ - pom = -(chanout[j] & PSG->pan[j*2+1]); \ - if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ - fputc((unsigned short)pom&0xff,sample[j]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ - } - #else - #define SAVE_SINGLE_CHANNEL(j) - #endif -#endif - -/* first macro saves left and right channels to mono file */ -/* second macro saves left and right channels to stereo file */ -#if 1 /*MONO*/ - #ifdef SAVE_SAMPLE - #define SAVE_ALL_CHANNELS \ - { signed int pom = outl; \ - /*pom = acc_calc(pom);*/ \ - /*fprintf(sample[8]," %i\n",pom);*/ \ - fputc((unsigned short)pom&0xff,sample[8]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ - } - #else - #define SAVE_ALL_CHANNELS - #endif -#else /*STEREO*/ - #ifdef SAVE_SAMPLE - #define SAVE_ALL_CHANNELS \ - { signed int pom = outl; \ - fputc((unsigned short)pom&0xff,sample[8]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ - pom = outr; \ - fputc((unsigned short)pom&0xff,sample[8]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ - } - #else - #define SAVE_ALL_CHANNELS - #endif -#endif - - -/* Generate samples for one of the YM2151's -* -* 'num' is the number of virtual YM2151 -* '**buffers' is table of pointers to the buffers: left and right -* 'length' is the number of samples that should be generated -*/ -void ym2151_update_one(void *chip, SAMP **buffers, int length) -{ - YM2151 *PSG = (YM2151 *)chip; - signed int *chanout = PSG->chanout; - int i; - UINT32 mask = ~PSG->mask; - signed int outl,outr; - SAMP *bufL, *bufR; - - bufL = buffers[0]; - bufR = buffers[1]; - - for (i=0; ipan[0]; - if (mask & 1) outr += chanout[0] & PSG->pan[1]; - if (mask & 2) outl += (chanout[1] & PSG->pan[2]); - if (mask & 2) outr += (chanout[1] & PSG->pan[3]); - if (mask & 4) outl += (chanout[2] & PSG->pan[4]); - if (mask & 4) outr += (chanout[2] & PSG->pan[5]); - if (mask & 8) outl += (chanout[3] & PSG->pan[6]); - if (mask & 8) outr += (chanout[3] & PSG->pan[7]); - if (mask & 16) outl += (chanout[4] & PSG->pan[8]); - if (mask & 16) outr += (chanout[4] & PSG->pan[9]); - if (mask & 32) outl += (chanout[5] & PSG->pan[10]); - if (mask & 32) outr += (chanout[5] & PSG->pan[11]); - if (mask & 64) outl += (chanout[6] & PSG->pan[12]); - if (mask & 64) outr += (chanout[6] & PSG->pan[13]); - if (mask & 128) outl += (chanout[7] & PSG->pan[14]); - if (mask & 128) outr += (chanout[7] & PSG->pan[15]); - - outl >>= FINAL_SH; - outr >>= FINAL_SH; - if (outl > MAXOUT) outl = MAXOUT; - else if (outl < MINOUT) outl = MINOUT; - if (outr > MAXOUT) outr = MAXOUT; - else if (outr < MINOUT) outr = MINOUT; - ((SAMP*)bufL)[i] = (SAMP)outl; - ((SAMP*)bufR)[i] = (SAMP)outr; - - SAVE_ALL_CHANNELS - - advance(PSG); - } -} - -void ym2151_set_mask(void *_chip, UINT32 mask) -{ - YM2151 *PSG = (YM2151 *)_chip; - - PSG->mask = mask; -} +/***************************************************************************** +* +* Yamaha YM2151 driver (version 2.150 final beta) +* +******************************************************************************/ + +#include "mathdefs.h" +#include +#include +#include +#include "mamedef.h" +#include "ym2151.h" + +#ifndef logerror +#define logerror (void) +#endif + + +/* struct describing a single operator */ +typedef struct +{ + UINT32 phase; /* accumulated operator phase */ + UINT32 freq; /* operator frequency count */ + INT32 dt1; /* current DT1 (detune 1 phase inc/decrement) value */ + UINT32 mul; /* frequency count multiply */ + UINT32 dt1_i; /* DT1 index * 32 */ + UINT32 dt2; /* current DT2 (detune 2) value */ + + signed int *connect; /* operator output 'direction' */ + + /* only M1 (operator 0) is filled with this data: */ + signed int *mem_connect; /* where to put the delayed sample (MEM) */ + INT32 mem_value; /* delayed sample (MEM) value */ + + /* channel specific data; note: each operator number 0 contains channel specific data */ + UINT32 fb_shift; /* feedback shift value for operators 0 in each channel */ + INT32 fb_out_curr; /* operator feedback value (used only by operators 0) */ + INT32 fb_out_prev; /* previous feedback value (used only by operators 0) */ + UINT32 kc; /* channel KC (copied to all operators) */ + UINT32 kc_i; /* just for speedup */ + UINT32 pms; /* channel PMS */ + UINT32 ams; /* channel AMS */ + /* end of channel specific data */ + + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT32 state; /* Envelope state: 4-attack(AR) 3-decay(D1R) 2-sustain(D2R) 1-release(RR) 0-off */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT32 tl; /* Total attenuation Level */ + INT32 volume; /* current envelope attenuation level */ + UINT8 eg_sh_d1r; /* (decay state) */ + UINT8 eg_sel_d1r; /* (decay state) */ + UINT32 d1l; /* envelope switches to sustain state after reaching this level */ + UINT8 eg_sh_d2r; /* (sustain state) */ + UINT8 eg_sel_d2r; /* (sustain state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + + UINT32 key; /* 0=last key was KEY OFF, 1=last key was KEY ON */ + + UINT32 ks; /* key scale */ + UINT32 ar; /* attack rate */ + UINT32 d1r; /* decay rate */ + UINT32 d2r; /* sustain rate */ + UINT32 rr; /* release rate */ + + UINT32 reserved0; /**/ + UINT32 reserved1; /**/ + +} YM2151Operator; + + +typedef struct +{ + signed int chanout[8]; + signed int m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */ + signed int mem; /* one sample delay memory */ + + YM2151Operator oper[32]; /* the 32 operators */ + + UINT32 pan[16]; /* channels output masks (0xffffffff = enable) */ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 3 samples (on real chip) */ + + UINT32 lfo_phase; /* accumulated LFO phase (0 to 255) */ + UINT32 lfo_timer; /* LFO timer */ + UINT32 lfo_timer_add; /* step of lfo_timer */ + UINT32 lfo_overflow; /* LFO generates new output when lfo_timer reaches this value */ + UINT32 lfo_counter; /* LFO phase increment counter */ + UINT32 lfo_counter_add; /* step of lfo_counter */ + UINT8 lfo_wsel; /* LFO waveform (0-saw, 1-square, 2-triangle, 3-random noise) */ + UINT8 amd; /* LFO Amplitude Modulation Depth */ + INT8 pmd; /* LFO Phase Modulation Depth */ + UINT32 lfa; /* LFO current AM output */ + INT32 lfp; /* LFO current PM output */ + + UINT8 test; /* TEST register */ + UINT8 ct; /* output control pins (bit1-CT2, bit0-CT1) */ + + UINT32 noise; /* noise enable/period register (bit 7 - noise enable, bits 4-0 - noise period */ + UINT32 noise_rng; /* 17 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase'*/ + UINT32 noise_f; /* current noise period */ + + UINT32 csm_req; /* CSM KEY ON / KEY OFF sequence request */ + + UINT32 irq_enable; /* IRQ enable for timer B (bit 3) and timer A (bit 2); bit 7 - CSM mode (keyon to all slots, everytime timer A overflows) */ + UINT32 status; /* chip status (BUSY, IRQ Flags) */ + UINT8 connect[8]; /* channels connections */ + + /* Frequency-deltas to get the closest frequency possible. + * There are 11 octaves because of DT2 (max 950 cents over base frequency) + * and LFO phase modulation (max 800 cents below AND over base frequency) + * Summary: octave explanation + * 0 note code - LFO PM + * 1 note code + * 2 note code + * 3 note code + * 4 note code + * 5 note code + * 6 note code + * 7 note code + * 8 note code + * 9 note code + DT2 + LFO PM + * 10 note code + DT2 + LFO PM + */ + UINT32 freq[11*768]; /* 11 octaves, 768 'cents' per octave */ + + /* Frequency deltas for DT1. These deltas alter operator frequency + * after it has been taken from frequency-deltas table. + */ + INT32 dt1_freq[8*32]; /* 8 DT1 levels, 32 KC values */ + + UINT32 noise_tab[32]; /* 17bit Noise Generator periods */ + + unsigned int clock; /* chip clock in Hz (passed from 2151intf.c) */ + unsigned int sampfreq; /* sampling frequency in Hz (passed from 2151intf.c) */ + + UINT32 mask; +} YM2151; + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ +#define LFO_SH 10 /* 22.10 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<>3) + +/* sin waveform table in 'decibel' scale */ +static unsigned int sin_tab[SIN_LEN]; + + +/* translate from D1L to volume index (16 D1L levels) */ +static UINT32 d1l_tab[16]; + + +#define RATE_STEPS (8) +static const UINT8 eg_inc[19*RATE_STEPS]={ + +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */ +/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */ +/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */ +/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */ + +/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */ +/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */ +/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(17) in this table - it's directly in the code */ +static const UINT8 eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */ +/* 32 dummy (infinite time) rates */ +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), + +/* rates 00-11 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 12 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 13 */ +O( 8),O( 9),O(10),O(11), + +/* rate 14 */ +O(12),O(13),O(14),O(15), + +/* rate 15 */ +O(16),O(16),O(16),O(16), + +/* 32 dummy rates (same as 15 3) */ +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16) + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/ +/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */ +/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */ +/* 32 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + + +/* rates 00-11 */ +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 12 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 32 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0) + +}; +#undef O + +/* DT2 defines offset in cents from base note +* +* This table defines offset in frequency-deltas table. +* User's Manual page 22 +* +* Values below were calculated using formula: value = orig.val / 1.5625 +* +* DT2=0 DT2=1 DT2=2 DT2=3 +* 0 600 781 950 +*/ +static const UINT32 dt2_tab[4] = { 0, 384, 500, 608 }; + +/* DT1 defines offset in Hertz from base note +* This table is converted while initialization... +* Detune table shown in YM2151 User's Manual is wrong (verified on the real chip) +*/ + +static const UINT8 dt1_tab[4*32] = { /* 4*32 DT1 values */ +/* DT1=0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/* DT1=1 */ + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, + +/* DT1=2 */ + 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, + 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, + +/* DT1=3 */ + 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, + 8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 +}; + +static const UINT16 phaseinc_rom[768]={ +1299,1300,1301,1302,1303,1304,1305,1306,1308,1309,1310,1311,1313,1314,1315,1316, +1318,1319,1320,1321,1322,1323,1324,1325,1327,1328,1329,1330,1332,1333,1334,1335, +1337,1338,1339,1340,1341,1342,1343,1344,1346,1347,1348,1349,1351,1352,1353,1354, +1356,1357,1358,1359,1361,1362,1363,1364,1366,1367,1368,1369,1371,1372,1373,1374, +1376,1377,1378,1379,1381,1382,1383,1384,1386,1387,1388,1389,1391,1392,1393,1394, +1396,1397,1398,1399,1401,1402,1403,1404,1406,1407,1408,1409,1411,1412,1413,1414, +1416,1417,1418,1419,1421,1422,1423,1424,1426,1427,1429,1430,1431,1432,1434,1435, +1437,1438,1439,1440,1442,1443,1444,1445,1447,1448,1449,1450,1452,1453,1454,1455, +1458,1459,1460,1461,1463,1464,1465,1466,1468,1469,1471,1472,1473,1474,1476,1477, +1479,1480,1481,1482,1484,1485,1486,1487,1489,1490,1492,1493,1494,1495,1497,1498, +1501,1502,1503,1504,1506,1507,1509,1510,1512,1513,1514,1515,1517,1518,1520,1521, +1523,1524,1525,1526,1528,1529,1531,1532,1534,1535,1536,1537,1539,1540,1542,1543, +1545,1546,1547,1548,1550,1551,1553,1554,1556,1557,1558,1559,1561,1562,1564,1565, +1567,1568,1569,1570,1572,1573,1575,1576,1578,1579,1580,1581,1583,1584,1586,1587, +1590,1591,1592,1593,1595,1596,1598,1599,1601,1602,1604,1605,1607,1608,1609,1610, +1613,1614,1615,1616,1618,1619,1621,1622,1624,1625,1627,1628,1630,1631,1632,1633, +1637,1638,1639,1640,1642,1643,1645,1646,1648,1649,1651,1652,1654,1655,1656,1657, +1660,1661,1663,1664,1666,1667,1669,1670,1672,1673,1675,1676,1678,1679,1681,1682, +1685,1686,1688,1689,1691,1692,1694,1695,1697,1698,1700,1701,1703,1704,1706,1707, +1709,1710,1712,1713,1715,1716,1718,1719,1721,1722,1724,1725,1727,1728,1730,1731, +1734,1735,1737,1738,1740,1741,1743,1744,1746,1748,1749,1751,1752,1754,1755,1757, +1759,1760,1762,1763,1765,1766,1768,1769,1771,1773,1774,1776,1777,1779,1780,1782, +1785,1786,1788,1789,1791,1793,1794,1796,1798,1799,1801,1802,1804,1806,1807,1809, +1811,1812,1814,1815,1817,1819,1820,1822,1824,1825,1827,1828,1830,1832,1833,1835, +1837,1838,1840,1841,1843,1845,1846,1848,1850,1851,1853,1854,1856,1858,1859,1861, +1864,1865,1867,1868,1870,1872,1873,1875,1877,1879,1880,1882,1884,1885,1887,1888, +1891,1892,1894,1895,1897,1899,1900,1902,1904,1906,1907,1909,1911,1912,1914,1915, +1918,1919,1921,1923,1925,1926,1928,1930,1932,1933,1935,1937,1939,1940,1942,1944, +1946,1947,1949,1951,1953,1954,1956,1958,1960,1961,1963,1965,1967,1968,1970,1972, +1975,1976,1978,1980,1982,1983,1985,1987,1989,1990,1992,1994,1996,1997,1999,2001, +2003,2004,2006,2008,2010,2011,2013,2015,2017,2019,2021,2022,2024,2026,2028,2029, +2032,2033,2035,2037,2039,2041,2043,2044,2047,2048,2050,2052,2054,2056,2058,2059, +2062,2063,2065,2067,2069,2071,2073,2074,2077,2078,2080,2082,2084,2086,2088,2089, +2092,2093,2095,2097,2099,2101,2103,2104,2107,2108,2110,2112,2114,2116,2118,2119, +2122,2123,2125,2127,2129,2131,2133,2134,2137,2139,2141,2142,2145,2146,2148,2150, +2153,2154,2156,2158,2160,2162,2164,2165,2168,2170,2172,2173,2176,2177,2179,2181, +2185,2186,2188,2190,2192,2194,2196,2197,2200,2202,2204,2205,2208,2209,2211,2213, +2216,2218,2220,2222,2223,2226,2227,2230,2232,2234,2236,2238,2239,2242,2243,2246, +2249,2251,2253,2255,2256,2259,2260,2263,2265,2267,2269,2271,2272,2275,2276,2279, +2281,2283,2285,2287,2288,2291,2292,2295,2297,2299,2301,2303,2304,2307,2308,2311, +2315,2317,2319,2321,2322,2325,2326,2329,2331,2333,2335,2337,2338,2341,2342,2345, +2348,2350,2352,2354,2355,2358,2359,2362,2364,2366,2368,2370,2371,2374,2375,2378, +2382,2384,2386,2388,2389,2392,2393,2396,2398,2400,2402,2404,2407,2410,2411,2414, +2417,2419,2421,2423,2424,2427,2428,2431,2433,2435,2437,2439,2442,2445,2446,2449, +2452,2454,2456,2458,2459,2462,2463,2466,2468,2470,2472,2474,2477,2480,2481,2484, +2488,2490,2492,2494,2495,2498,2499,2502,2504,2506,2508,2510,2513,2516,2517,2520, +2524,2526,2528,2530,2531,2534,2535,2538,2540,2542,2544,2546,2549,2552,2553,2556, +2561,2563,2565,2567,2568,2571,2572,2575,2577,2579,2581,2583,2586,2589,2590,2593 +}; + + +/* + Noise LFO waveform. + + Here are just 256 samples out of much longer data. + + It does NOT repeat every 256 samples on real chip and I wasnt able to find + the point where it repeats (even in strings as long as 131072 samples). + + I only put it here because its better than nothing and perhaps + someone might be able to figure out the real algorithm. + + + Note that (due to the way the LFO output is calculated) it is quite + possible that two values: 0x80 and 0x00 might be wrong in this table. + To be exact: + some 0x80 could be 0x81 as well as some 0x00 could be 0x01. +*/ + +static const UINT8 lfo_noise_waveform[256] = { +0xFF,0xEE,0xD3,0x80,0x58,0xDA,0x7F,0x94,0x9E,0xE3,0xFA,0x00,0x4D,0xFA,0xFF,0x6A, +0x7A,0xDE,0x49,0xF6,0x00,0x33,0xBB,0x63,0x91,0x60,0x51,0xFF,0x00,0xD8,0x7F,0xDE, +0xDC,0x73,0x21,0x85,0xB2,0x9C,0x5D,0x24,0xCD,0x91,0x9E,0x76,0x7F,0x20,0xFB,0xF3, +0x00,0xA6,0x3E,0x42,0x27,0x69,0xAE,0x33,0x45,0x44,0x11,0x41,0x72,0x73,0xDF,0xA2, + +0x32,0xBD,0x7E,0xA8,0x13,0xEB,0xD3,0x15,0xDD,0xFB,0xC9,0x9D,0x61,0x2F,0xBE,0x9D, +0x23,0x65,0x51,0x6A,0x84,0xF9,0xC9,0xD7,0x23,0xBF,0x65,0x19,0xDC,0x03,0xF3,0x24, +0x33,0xB6,0x1E,0x57,0x5C,0xAC,0x25,0x89,0x4D,0xC5,0x9C,0x99,0x15,0x07,0xCF,0xBA, +0xC5,0x9B,0x15,0x4D,0x8D,0x2A,0x1E,0x1F,0xEA,0x2B,0x2F,0x64,0xA9,0x50,0x3D,0xAB, + +0x50,0x77,0xE9,0xC0,0xAC,0x6D,0x3F,0xCA,0xCF,0x71,0x7D,0x80,0xA6,0xFD,0xFF,0xB5, +0xBD,0x6F,0x24,0x7B,0x00,0x99,0x5D,0xB1,0x48,0xB0,0x28,0x7F,0x80,0xEC,0xBF,0x6F, +0x6E,0x39,0x90,0x42,0xD9,0x4E,0x2E,0x12,0x66,0xC8,0xCF,0x3B,0x3F,0x10,0x7D,0x79, +0x00,0xD3,0x1F,0x21,0x93,0x34,0xD7,0x19,0x22,0xA2,0x08,0x20,0xB9,0xB9,0xEF,0x51, + +0x99,0xDE,0xBF,0xD4,0x09,0x75,0xE9,0x8A,0xEE,0xFD,0xE4,0x4E,0x30,0x17,0xDF,0xCE, +0x11,0xB2,0x28,0x35,0xC2,0x7C,0x64,0xEB,0x91,0x5F,0x32,0x0C,0x6E,0x00,0xF9,0x92, +0x19,0xDB,0x8F,0xAB,0xAE,0xD6,0x12,0xC4,0x26,0x62,0xCE,0xCC,0x0A,0x03,0xE7,0xDD, +0xE2,0x4D,0x8A,0xA6,0x46,0x95,0x0F,0x8F,0xF5,0x15,0x97,0x32,0xD4,0x28,0x1E,0x55 +}; + + + + +/* save output as raw 16-bit sample */ +/* #define SAVE_SAMPLE */ +/* #define SAVE_SEPARATE_CHANNELS */ +#if defined SAVE_SAMPLE || defined SAVE_SEPARATE_CHANNELS +static FILE *sample[9]; +#endif + + + + +static void init_tables(void) +{ + signed int i,x,n; + double o,m; + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to closest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 2; /* 13 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<13; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<13; i++) + logerror(", [%02i] %4i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]); + logerror("\n"); + #endif + } + /*logerror("TL_TAB_LEN = %i (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + /*logerror("ENV_QUIET= %i\n",ENV_QUIET );*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to closest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + /*logerror("sin [0x%4x]= %4i (tl_tab value=%8x)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/ + } + + + /* calculate d1l_tab table */ + for (i=0; i<16; i++) + { + m = (i!=15 ? i : i+16) * (4.0/ENV_STEP); /* every 3 'dB' except for all bits = 1 = 45+48 'dB' */ + d1l_tab[i] = m; + /*logerror("d1l_tab[%02x]=%08x\n",i,d1l_tab[i] );*/ + } + +#ifdef SAVE_SAMPLE + sample[8]=fopen("sampsum.pcm","wb"); +#endif +#ifdef SAVE_SEPARATE_CHANNELS + sample[0]=fopen("samp0.pcm","wb"); + sample[1]=fopen("samp1.pcm","wb"); + sample[2]=fopen("samp2.pcm","wb"); + sample[3]=fopen("samp3.pcm","wb"); + sample[4]=fopen("samp4.pcm","wb"); + sample[5]=fopen("samp5.pcm","wb"); + sample[6]=fopen("samp6.pcm","wb"); + sample[7]=fopen("samp7.pcm","wb"); +#endif +} + + +static void init_chip_tables(YM2151 *chip) +{ + int i,j; + double mult,phaseinc,Hz; + double scaler; + + scaler = ( (double)chip->clock / 64.0 ) / ( (double)chip->sampfreq ); + if ( fabs( scaler - 1.0 ) < 0.0000001 ) scaler = 1.0; + /*logerror("scaler = %20.15f\n", scaler);*/ + + + /* this loop calculates Hertz values for notes from c-0 to b-7 */ + /* including 64 'cents' (100/64 that is 1.5625 of real cent) per note */ + /* i*100/64/1200 is equal to i/768 */ + + /* real chip works with 10 bits fixed point values (10.10) */ + mult = (1<<(FREQ_SH-10)); /* -10 because phaseinc_rom table values are already in 10.10 format */ + + for (i=0; i<768; i++) + { + /* 3.4375 Hz is note A; C# is 4 semitones higher */ + Hz = 1000; +#if 0 +/* Hz is close, but not perfect */ + //Hz = scaler * 3.4375 * pow (2, (i + 4 * 64 ) / 768.0 ); + /* calculate phase increment */ + phaseinc = (Hz*SIN_LEN) / (double)chip->sampfreq; +#endif + + phaseinc = phaseinc_rom[i]; /* real chip phase increment */ + phaseinc *= scaler; /* adjust */ + + + /* octave 2 - reference octave */ + chip->freq[ 768+2*768+i ] = ((int)(phaseinc*mult)) & 0xffffffc0; /* adjust to X.10 fixed point */ + /* octave 0 and octave 1 */ + for (j=0; j<2; j++) + { + chip->freq[768 + j*768 + i] = (chip->freq[ 768+2*768+i ] >> (2-j) ) & 0xffffffc0; /* adjust to X.10 fixed point */ + } + /* octave 3 to 7 */ + for (j=3; j<8; j++) + { + chip->freq[768 + j*768 + i] = chip->freq[ 768+2*768+i ] << (j-2); + } + } + + /* octave -1 (all equal to: oct 0, _KC_00_, _KF_00_) */ + for (i=0; i<768; i++) + { + chip->freq[ 0*768 + i ] = chip->freq[1*768+0]; + } + + /* octave 8 and 9 (all equal to: oct 7, _KC_14_, _KF_63_) */ + for (j=8; j<10; j++) + { + for (i=0; i<768; i++) + { + chip->freq[768+ j*768 + i ] = chip->freq[768 + 8*768 -1]; + } + } + + mult = (1<clock/64.0) ) / (double)(1<<20); + + /*calculate phase increment*/ + phaseinc = (Hz*SIN_LEN) / (double)chip->sampfreq; + + /*positive and negative values*/ + chip->dt1_freq[ (j+0)*32 + i ] = phaseinc * mult; + chip->dt1_freq[ (j+4)*32 + i ] = -chip->dt1_freq[ (j+0)*32 + i ]; + +#if 0 + { + int x = j*32 + i; + pom = (double)chip->dt1_freq[x] / mult; + pom = pom * (double)chip->sampfreq / (double)SIN_LEN; + logerror("DT1(%03i)[%02i %02i][%08x]= real %19.15f Hz emul %19.15f Hz\n", + x, j, i, chip->dt1_freq[x], Hz, pom); + } +#endif + } + } + + + /* calculate noise periods table */ + scaler = ( (double)chip->clock / 64.0 ) / ( (double)chip->sampfreq ); + if ( fabs( scaler - 1.0 ) < 0.0000001 ) scaler = 1.0; + for (i=0; i<32; i++) + { + j = (i!=31 ? i : 30); /* rate 30 and 31 are the same */ + j = 32-j; + j = (65536.0 / (double)(j*32.0)); /* number of samples per one shift of the shift register */ + /*chip->noise_tab[i] = j * 64;*/ /* number of chip clock cycles per one shift */ + chip->noise_tab[i] = j * 64 * scaler; + /*logerror("noise_tab[%02x]=%08x\n", i, chip->noise_tab[i]);*/ + } +} + +#define KEY_ON(op, key_set){ \ + if (!(op)->key) \ + { \ + (op)->phase = 0; /* clear phase */ \ + (op)->state = EG_ATT; /* KEY ON = attack */ \ + (op)->volume += (~(op)->volume * \ + (eg_inc[(op)->eg_sel_ar + ((PSG->eg_cnt>>(op)->eg_sh_ar)&7)]) \ + ) >>4; \ + if ((op)->volume <= MIN_ATT_INDEX) \ + { \ + (op)->volume = MIN_ATT_INDEX; \ + (op)->state = EG_DEC; \ + } \ + } \ + (op)->key |= key_set; \ +} + +#define KEY_OFF(op, key_clr){ \ + if ((op)->key) \ + { \ + (op)->key &= key_clr; \ + if (!(op)->key) \ + { \ + if ((op)->state>EG_REL) \ + (op)->state = EG_REL;/* KEY OFF = release */\ + } \ + } \ +} + +INLINE void envelope_KONKOFF(YM2151 *PSG, YM2151Operator * op, int v) +{ + if (v&0x08) /* M1 */ + KEY_ON (op+0, 1) + else + KEY_OFF(op+0,~1) + + if (v&0x20) /* M2 */ + KEY_ON (op+1, 1) + else + KEY_OFF(op+1,~1) + + if (v&0x10) /* C1 */ + KEY_ON (op+2, 1) + else + KEY_OFF(op+2,~1) + + if (v&0x40) /* C2 */ + KEY_ON (op+3, 1) + else + KEY_OFF(op+3,~1) +} + + +INLINE void set_connect(YM2151 *PSG, YM2151Operator *om1, int cha, int v) +{ + YM2151Operator *om2 = om1+1; + YM2151Operator *oc1 = om1+2; + + /* set connect algorithm */ + + /* MEM is simply one sample delay */ + + switch( v&7 ) + { + case 0: + /* M1---C1---MEM---M2---C2---OUT */ + om1->connect = &PSG->c1; + oc1->connect = &PSG->mem; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->m2; + break; + + case 1: + /* M1------+-MEM---M2---C2---OUT */ + /* C1-+ */ + om1->connect = &PSG->mem; + oc1->connect = &PSG->mem; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->m2; + break; + + case 2: + /* M1-----------------+-C2---OUT */ + /* C1---MEM---M2-+ */ + om1->connect = &PSG->c2; + oc1->connect = &PSG->mem; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->m2; + break; + + case 3: + /* M1---C1---MEM------+-C2---OUT */ + /* M2-+ */ + om1->connect = &PSG->c1; + oc1->connect = &PSG->mem; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->c2; + break; + + case 4: + /* M1---C1-+-OUT */ + /* M2---C2-+ */ + /* MEM: not used */ + om1->connect = &PSG->c1; + oc1->connect = &PSG->chanout[cha]; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ + break; + + case 5: + /* +----C1----+ */ + /* M1-+-MEM---M2-+-OUT */ + /* +----C2----+ */ + om1->connect = 0; /* special mark */ + oc1->connect = &PSG->chanout[cha]; + om2->connect = &PSG->chanout[cha]; + om1->mem_connect = &PSG->m2; + break; + + case 6: + /* M1---C1-+ */ + /* M2-+-OUT */ + /* C2-+ */ + /* MEM: not used */ + om1->connect = &PSG->c1; + oc1->connect = &PSG->chanout[cha]; + om2->connect = &PSG->chanout[cha]; + om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ + break; + + case 7: + /* M1-+ */ + /* C1-+-OUT */ + /* M2-+ */ + /* C2-+ */ + /* MEM: not used*/ + om1->connect = &PSG->chanout[cha]; + oc1->connect = &PSG->chanout[cha]; + om2->connect = &PSG->chanout[cha]; + om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ + break; + } +} + + +INLINE void refresh_EG(YM2151Operator * op) +{ + UINT32 kc; + UINT32 v; + + kc = op->kc; + + /* v = 32 + 2*RATE + RKS = max 126 */ + + v = kc >> op->ks; + if ((op->ar+v) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + v ]; + op->eg_sel_ar = eg_rate_select[op->ar + v ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; + op->eg_sel_d1r= eg_rate_select[op->d1r + v]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; + op->eg_sel_d2r= eg_rate_select[op->d2r + v]; + op->eg_sh_rr = eg_rate_shift [op->rr + v]; + op->eg_sel_rr = eg_rate_select[op->rr + v]; + + + op+=1; + + v = kc >> op->ks; + if ((op->ar+v) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + v ]; + op->eg_sel_ar = eg_rate_select[op->ar + v ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; + op->eg_sel_d1r= eg_rate_select[op->d1r + v]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; + op->eg_sel_d2r= eg_rate_select[op->d2r + v]; + op->eg_sh_rr = eg_rate_shift [op->rr + v]; + op->eg_sel_rr = eg_rate_select[op->rr + v]; + + op+=1; + + v = kc >> op->ks; + if ((op->ar+v) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + v ]; + op->eg_sel_ar = eg_rate_select[op->ar + v ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; + op->eg_sel_d1r= eg_rate_select[op->d1r + v]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; + op->eg_sel_d2r= eg_rate_select[op->d2r + v]; + op->eg_sh_rr = eg_rate_shift [op->rr + v]; + op->eg_sel_rr = eg_rate_select[op->rr + v]; + + op+=1; + + v = kc >> op->ks; + if ((op->ar+v) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + v ]; + op->eg_sel_ar = eg_rate_select[op->ar + v ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; + op->eg_sel_d1r= eg_rate_select[op->d1r + v]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; + op->eg_sel_d2r= eg_rate_select[op->d2r + v]; + op->eg_sh_rr = eg_rate_shift [op->rr + v]; + op->eg_sel_rr = eg_rate_select[op->rr + v]; +} + + +/* write a register on YM2151 chip number 'n' */ +void ym2151_write_reg(void *_chip, int r, int v) +{ + YM2151 *chip = (YM2151 *)_chip; + YM2151Operator *op = &chip->oper[ (r&0x07)*4+((r&0x18)>>3) ]; + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + +#if 0 + /* There is no info on what YM2151 really does when busy flag is set */ + if ( chip->status & 0x80 ) return; + timer_set ( attotime::from_hz(chip->clock) * 64, chip, 0, timer_callback_chip_busy); + chip->status |= 0x80; /* set busy flag for 64 chip clock cycles */ +#endif + + + switch(r & 0xe0) + { + case 0x00: + switch(r){ + case 0x01: /* LFO reset(bit 1), Test Register (other bits) */ + chip->test = v; + if (v&2) chip->lfo_phase = 0; + break; + + case 0x08: + envelope_KONKOFF(chip, &chip->oper[ (v&7)*4 ], v ); + break; + + case 0x0f: /* noise mode enable, noise period */ + chip->noise = v; + chip->noise_f = chip->noise_tab[ v & 0x1f ]; + break; + + case 0x10: /* timer A hi */ + break; + + case 0x11: /* timer A low */ + break; + + case 0x12: /* timer B */ + break; + + case 0x14: /* CSM, irq flag reset, irq enable, timer start/stop */ + + chip->irq_enable = v; /* bit 3-timer B, bit 2-timer A, bit 7 - CSM */ + + break; + + case 0x18: /* LFO frequency */ + { + chip->lfo_overflow = ( 1 << ((15-(v>>4))+3) ) * (1<lfo_counter_add = 0x10 + (v & 0x0f); + } + break; + + case 0x19: /* PMD (bit 7==1) or AMD (bit 7==0) */ + if (v&0x80) + chip->pmd = v & 0x7f; + else + chip->amd = v & 0x7f; + break; + + case 0x1b: /* CT2, CT1, LFO waveform */ + chip->ct = v >> 6; + chip->lfo_wsel = v & 3; + break; + + default: + /*logerror("YM2151 Write %02x to undocumented register #%02x\n",v,r);*/ + break; + } + break; + + case 0x20: + op = &chip->oper[ (r&7) * 4 ]; + switch(r & 0x18) + { + case 0x00: /* RL enable, Feedback, Connection */ + op->fb_shift = ((v>>3)&7) ? ((v>>3)&7)+6:0; + chip->pan[ (r&7)*2 ] = (v & 0x40) ? ~0 : 0; + chip->pan[ (r&7)*2 +1 ] = (v & 0x80) ? ~0 : 0; + chip->connect[r&7] = v&7; + set_connect(chip, op, r&7, v&7); + break; + + case 0x08: /* Key Code */ + v &= 0x7f; + if (v != (int)(op->kc)) + { + UINT32 kc, kc_channel; + + kc_channel = (v - (v>>2))*64; + kc_channel += 768; + kc_channel |= (op->kc_i & 63); + + (op+0)->kc = v; + (op+0)->kc_i = kc_channel; + (op+1)->kc = v; + (op+1)->kc_i = kc_channel; + (op+2)->kc = v; + (op+2)->kc_i = kc_channel; + (op+3)->kc = v; + (op+3)->kc_i = kc_channel; + + kc = v>>2; + + (op+0)->dt1 = chip->dt1_freq[ (op+0)->dt1_i + kc ]; + (op+0)->freq = ( (chip->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; + + (op+1)->dt1 = chip->dt1_freq[ (op+1)->dt1_i + kc ]; + (op+1)->freq = ( (chip->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; + + (op+2)->dt1 = chip->dt1_freq[ (op+2)->dt1_i + kc ]; + (op+2)->freq = ( (chip->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; + + (op+3)->dt1 = chip->dt1_freq[ (op+3)->dt1_i + kc ]; + (op+3)->freq = ( (chip->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; + + refresh_EG( op ); + } + break; + + case 0x10: /* Key Fraction */ + v >>= 2; + if (v != (int)(op->kc_i & 63)) + { + UINT32 kc_channel; + + kc_channel = v; + kc_channel |= (op->kc_i & ~63); + + (op+0)->kc_i = kc_channel; + (op+1)->kc_i = kc_channel; + (op+2)->kc_i = kc_channel; + (op+3)->kc_i = kc_channel; + + (op+0)->freq = ( (chip->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; + (op+1)->freq = ( (chip->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; + (op+2)->freq = ( (chip->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; + (op+3)->freq = ( (chip->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; + } + break; + + case 0x18: /* PMS, AMS */ + op->pms = (v>>4) & 7; + op->ams = (v & 3); + break; + } + break; + + case 0x40: /* DT1, MUL */ + { + UINT32 olddt1_i = op->dt1_i; + UINT32 oldmul = op->mul; + + op->dt1_i = (v&0x70)<<1; + op->mul = (v&0x0f) ? (v&0x0f)<<1: 1; + + if (olddt1_i != op->dt1_i) + op->dt1 = chip->dt1_freq[ op->dt1_i + (op->kc>>2) ]; + + if ( (olddt1_i != op->dt1_i) || (oldmul != op->mul) ) + op->freq = ( (chip->freq[ op->kc_i + op->dt2 ] + op->dt1) * op->mul ) >> 1; + } + break; + + case 0x60: /* TL */ + op->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */ + break; + + case 0x80: /* KS, AR */ + { + UINT32 oldks = op->ks; + UINT32 oldar = op->ar; + + op->ks = 5-(v>>6); + op->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + if ( (op->ar != oldar) || (op->ks != oldks) ) + { + if ((op->ar + (op->kc>>op->ks)) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + (op->kc>>op->ks) ]; + op->eg_sel_ar = eg_rate_select[op->ar + (op->kc>>op->ks) ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + } + + if (op->ks != oldks) + { + op->eg_sh_d1r = eg_rate_shift [op->d1r + (op->kc>>op->ks) ]; + op->eg_sel_d1r= eg_rate_select[op->d1r + (op->kc>>op->ks) ]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + (op->kc>>op->ks) ]; + op->eg_sel_d2r= eg_rate_select[op->d2r + (op->kc>>op->ks) ]; + op->eg_sh_rr = eg_rate_shift [op->rr + (op->kc>>op->ks) ]; + op->eg_sel_rr = eg_rate_select[op->rr + (op->kc>>op->ks) ]; + } + } + break; + + case 0xa0: /* LFO AM enable, D1R */ + op->AMmask = (v&0x80) ? ~0 : 0; + op->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + op->eg_sh_d1r = eg_rate_shift [op->d1r + (op->kc>>op->ks) ]; + op->eg_sel_d1r= eg_rate_select[op->d1r + (op->kc>>op->ks) ]; + break; + + case 0xc0: /* DT2, D2R */ + { + UINT32 olddt2 = op->dt2; + op->dt2 = dt2_tab[ v>>6 ]; + if (op->dt2 != olddt2) + op->freq = ( (chip->freq[ op->kc_i + op->dt2 ] + op->dt1) * op->mul ) >> 1; + } + op->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + op->eg_sh_d2r = eg_rate_shift [op->d2r + (op->kc>>op->ks) ]; + op->eg_sel_d2r= eg_rate_select[op->d2r + (op->kc>>op->ks) ]; + break; + + case 0xe0: /* D1L, RR */ + op->d1l = d1l_tab[ v>>4 ]; + op->rr = 34 + ((v&0x0f)<<2); + op->eg_sh_rr = eg_rate_shift [op->rr + (op->kc>>op->ks) ]; + op->eg_sel_rr = eg_rate_select[op->rr + (op->kc>>op->ks) ]; + break; + } +} + + +/* +* Initialize YM2151 emulator(s). +* +* 'num' is the number of virtual YM2151's to allocate +* 'clock' is the chip clock in Hz +* 'rate' is sampling rate +*/ +void * ym2151_init(int clock, int rate) +{ + YM2151 *PSG; + + PSG = (YM2151 *) malloc(sizeof(YM2151)); + + memset(PSG, 0, sizeof(YM2151)); + + init_tables(); + + PSG->clock = clock; + /*rate = clock/64;*/ + PSG->sampfreq = rate ? rate : 44100; /* avoid division by 0 in init_chip_tables() */ + init_chip_tables( PSG ); + + PSG->lfo_timer_add = (1<sampfreq; + + PSG->eg_timer_add = (1<sampfreq; + PSG->eg_timer_overflow = ( 3 ) * (1<eg_timer_add, PSG->eg_timer_overflow);*/ + + ym2151_reset_chip(PSG); + /*logerror("YM2151[init] clock=%i sampfreq=%i\n", PSG->clock, PSG->sampfreq);*/ + + return PSG; +} + + + +void ym2151_shutdown(void *_chip) +{ + YM2151 *chip = (YM2151 *)_chip; + + free (chip); + +#ifdef SAVE_SAMPLE + fclose(sample[8]); +#endif +#ifdef SAVE_SEPARATE_CHANNELS + fclose(sample[0]); + fclose(sample[1]); + fclose(sample[2]); + fclose(sample[3]); + fclose(sample[4]); + fclose(sample[5]); + fclose(sample[6]); + fclose(sample[7]); +#endif +} + + + +/* +* Reset chip number 'n'. +*/ +void ym2151_reset_chip(void *_chip) +{ + int i; + YM2151 *chip = (YM2151 *)_chip; + + + /* initialize hardware registers */ + for (i=0; i<32; i++) + { + memset(&chip->oper[i],'\0',sizeof(YM2151Operator)); + chip->oper[i].volume = MAX_ATT_INDEX; + chip->oper[i].kc_i = 768; /* min kc_i value */ + } + + chip->eg_timer = 0; + chip->eg_cnt = 0; + + chip->lfo_timer = 0; + chip->lfo_counter= 0; + chip->lfo_phase = 0; + chip->lfo_wsel = 0; + chip->pmd = 0; + chip->amd = 0; + chip->lfa = 0; + chip->lfp = 0; + + chip->test= 0; + + chip->irq_enable = 0; + + chip->noise = 0; + chip->noise_rng = 0; + chip->noise_p = 0; + chip->noise_f = chip->noise_tab[0]; + + chip->csm_req = 0; + chip->status = 0; + + ym2151_write_reg(chip, 0x1b, 0); /* only because of CT1, CT2 output pins */ + ym2151_write_reg(chip, 0x18, 0); /* set LFO frequency */ + for (i=0x20; i<0x100; i++) /* set the operators */ + { + ym2151_write_reg(chip, i, 0); + } +} + + + +INLINE signed int op_calc(YM2151Operator * OP, unsigned int env, signed int pm) +{ + UINT32 p; + + + p = (env<<3) + sin_tab[ ( ((signed int)((OP->phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ]; + + if (p >= TL_TAB_LEN) + return 0; + + return tl_tab[p]; +} + +INLINE signed int op_calc1(YM2151Operator * OP, unsigned int env, signed int pm) +{ + UINT32 p; + INT32 i; + + + i = (OP->phase & ~FREQ_MASK) + pm; + +/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, OP->phase>>FREQ_SH, pm);*/ + + p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK]; + +/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ + + if (p >= TL_TAB_LEN) + return 0; + + return tl_tab[p]; +} + + + +#define volume_calc(OP) ((OP)->tl + ((UINT32)(OP)->volume) + (AM & (OP)->AMmask)) + +INLINE void chan_calc(YM2151 *PSG, unsigned int chan) +{ + YM2151Operator *op; + unsigned int env; + UINT32 AM = 0; + + PSG->m2 = PSG->c1 = PSG->c2 = PSG->mem = 0; + op = &PSG->oper[chan*4]; /* M1 */ + + *op->mem_connect = op->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ + + if (op->ams) + AM = PSG->lfa << (op->ams-1); + env = volume_calc(op); + { + INT32 out = op->fb_out_prev + op->fb_out_curr; + op->fb_out_prev = op->fb_out_curr; + + if (!op->connect) + /* algorithm 5 */ + PSG->mem = PSG->c1 = PSG->c2 = op->fb_out_prev; + else + /* other algorithms */ + *op->connect = op->fb_out_prev; + + op->fb_out_curr = 0; + if (env < ENV_QUIET) + { + if (!op->fb_shift) + out=0; + op->fb_out_curr = op_calc1(op, env, (out<fb_shift) ); + } + } + + env = volume_calc(op+1); /* M2 */ + if (env < ENV_QUIET) + *(op+1)->connect += op_calc(op+1, env, PSG->m2); + + env = volume_calc(op+2); /* C1 */ + if (env < ENV_QUIET) + *(op+2)->connect += op_calc(op+2, env, PSG->c1); + + env = volume_calc(op+3); /* C2 */ + if (env < ENV_QUIET) + PSG->chanout[chan] += op_calc(op+3, env, PSG->c2); + + /* M1 */ + op->mem_value = PSG->mem; +} + +INLINE void chan7_calc(YM2151 *PSG) +{ + YM2151Operator *op; + unsigned int env; + UINT32 AM = 0; + + PSG->m2 = PSG->c1 = PSG->c2 = PSG->mem = 0; + op = &PSG->oper[7*4]; /* M1 */ + + *op->mem_connect = op->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ + + if (op->ams) + AM = PSG->lfa << (op->ams-1); + env = volume_calc(op); + { + INT32 out = op->fb_out_prev + op->fb_out_curr; + op->fb_out_prev = op->fb_out_curr; + + if (!op->connect) + /* algorithm 5 */ + PSG->mem = PSG->c1 = PSG->c2 = op->fb_out_prev; + else + /* other algorithms */ + *op->connect = op->fb_out_prev; + + op->fb_out_curr = 0; + if (env < ENV_QUIET) + { + if (!op->fb_shift) + out=0; + op->fb_out_curr = op_calc1(op, env, (out<fb_shift) ); + } + } + + env = volume_calc(op+1); /* M2 */ + if (env < ENV_QUIET) + *(op+1)->connect += op_calc(op+1, env, PSG->m2); + + env = volume_calc(op+2); /* C1 */ + if (env < ENV_QUIET) + *(op+2)->connect += op_calc(op+2, env, PSG->c1); + + env = volume_calc(op+3); /* C2 */ + if (PSG->noise & 0x80) + { + UINT32 noiseout; + + noiseout = 0; + if (env < 0x3ff) + noiseout = (env ^ 0x3ff) * 2; /* range of the YM2151 noise output is -2044 to 2040 */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4146) +#endif + PSG->chanout[7] += ((PSG->noise_rng&0x10000) ? noiseout: -noiseout); /* bit 16 -> output */ +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + } + else + { + if (env < ENV_QUIET) + PSG->chanout[7] += op_calc(op+3, env, PSG->c2); + } + /* M1 */ + op->mem_value = PSG->mem; +} + + + + + + +/* +The 'rate' is calculated from following formula (example on decay rate): + rks = notecode after key scaling (a value from 0 to 31) + DR = value written to the chip register + rate = 2*DR + rks; (max rate = 2*31+31 = 93) +Four MSBs of the 'rate' above are the 'main' rate (from 00 to 15) +Two LSBs of the 'rate' above are the value 'x' (the shape type). +(eg. '11 2' means that 'rate' is 11*4+2=46) + +NOTE: A 'sample' in the description below is actually 3 output samples, +thats because the Envelope Generator clock is equal to internal_clock/3. + +Single '-' (minus) character in the diagrams below represents one sample +on the output; this is for rates 11 x (11 0, 11 1, 11 2 and 11 3) + +these 'main' rates: +00 x: single '-' = 2048 samples; (ie. level can change every 2048 samples) +01 x: single '-' = 1024 samples; +02 x: single '-' = 512 samples; +03 x: single '-' = 256 samples; +04 x: single '-' = 128 samples; +05 x: single '-' = 64 samples; +06 x: single '-' = 32 samples; +07 x: single '-' = 16 samples; +08 x: single '-' = 8 samples; +09 x: single '-' = 4 samples; +10 x: single '-' = 2 samples; +11 x: single '-' = 1 sample; (ie. level can change every 1 sample) + +Shapes for rates 11 x look like this: +rate: step: +11 0 01234567 + +level: +0 -- +1 -- +2 -- +3 -- + +rate: step: +11 1 01234567 + +level: +0 -- +1 -- +2 - +3 - +4 -- + +rate: step: +11 2 01234567 + +level: +0 -- +1 - +2 - +3 -- +4 - +5 - + +rate: step: +11 3 01234567 + +level: +0 -- +1 - +2 - +3 - +4 - +5 - +6 - + + +For rates 12 x, 13 x, 14 x and 15 x output level changes on every +sample - this means that the waveform looks like this: (but the level +changes by different values on different steps) +12 3 01234567 + +0 - +2 - +4 - +8 - +10 - +12 - +14 - +18 - +20 - + +Notes about the timing: +---------------------- + +1. Synchronism + +Output level of each two (or more) voices running at the same 'main' rate +(eg 11 0 and 11 1 in the diagram below) will always be changing in sync, +even if there're started with some delay. + +Note that, in the diagram below, the decay phase in channel 0 starts at +sample #2, while in channel 1 it starts at sample #6. Anyway, both channels +will always change their levels at exactly the same (following) samples. + +(S - start point of this channel, A-attack phase, D-decay phase): + +step: +01234567012345670123456 + +channel 0: + -- + | -- + | - + | - + | -- + | -- +| -- +| - +| - +| -- +AADDDDDDDDDDDDDDDD +S + +01234567012345670123456 +channel 1: + - + | - + | -- + | -- + | -- + | - + | - + | -- + | -- + | -- + AADDDDDDDDDDDDDDDD + S +01234567012345670123456 + + +2. Shifted (delayed) synchronism + +Output of each two (or more) voices running at different 'main' rate +(9 1, 10 1 and 11 1 in the diagrams below) will always be changing +in 'delayed-sync' (even if there're started with some delay as in "1.") + +Note that the shapes are delayed by exactly one sample per one 'main' rate +increment. (Normally one would expect them to start at the same samples.) + +See diagram below (* - start point of the shape). + +cycle: +0123456701234567012345670123456701234567012345670123456701234567 + +rate 09 1 +*------- + -------- + ---- + ---- + -------- + *------- + | -------- + | ---- + | ---- + | -------- +rate 10 1 | +-- | + *--- | + ---- | + -- | + -- | + ---- | + *--- | + | ---- | + | -- | | <- one step (two samples) delay between 9 1 and 10 1 + | -- | | + | ----| + | *--- + | ---- + | -- + | -- + | ---- +rate 11 1 | +- | + -- | + *- | + -- | + - | + - | + -- | + *- | + -- | + - || <- one step (one sample) delay between 10 1 and 11 1 + - || + --| + *- + -- + - + - + -- + *- + -- + - + - + -- +*/ + +INLINE void advance_eg(YM2151 *PSG) +{ + YM2151Operator *op; + unsigned int i; + + + + PSG->eg_timer += PSG->eg_timer_add; + + while (PSG->eg_timer >= PSG->eg_timer_overflow) + { + PSG->eg_timer -= PSG->eg_timer_overflow; + + PSG->eg_cnt++; + + /* envelope generator */ + op = &PSG->oper[0]; /* CH 0 M1 */ + i = 32; + do + { + switch(op->state) + { + case EG_ATT: /* attack phase */ + if ( !(PSG->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((PSG->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>4; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + break; + + case EG_DEC: /* decay phase */ + if ( !(PSG->eg_cnt & ((1<eg_sh_d1r)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_d1r + ((PSG->eg_cnt>>op->eg_sh_d1r)&7)]; + + if ( op->volume >= (INT32)(op->d1l) ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + if ( !(PSG->eg_cnt & ((1<eg_sh_d2r)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_d2r + ((PSG->eg_cnt>>op->eg_sh_d2r)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + case EG_REL: /* release phase */ + if ( !(PSG->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((PSG->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + } + op++; + i--; + }while (i); + } +} + + +INLINE void advance(YM2151 *PSG) +{ + YM2151Operator *op; + unsigned int i; + int a,p; + + /* LFO */ + if (PSG->test&2) + PSG->lfo_phase = 0; + else + { + PSG->lfo_timer += PSG->lfo_timer_add; + if (PSG->lfo_timer >= PSG->lfo_overflow) + { + PSG->lfo_timer -= PSG->lfo_overflow; + PSG->lfo_counter += PSG->lfo_counter_add; + PSG->lfo_phase += (PSG->lfo_counter>>4); + PSG->lfo_phase &= 255; + PSG->lfo_counter &= 15; + } + } + + i = PSG->lfo_phase; + /* calculate LFO AM and PM waveform value (all verified on real chip, except for noise algorithm which is impossible to analyse)*/ + switch (PSG->lfo_wsel) + { + case 0: + /* saw */ + /* AM: 255 down to 0 */ + /* PM: 0 to 127, -127 to 0 (at PMD=127: LFP = 0 to 126, -126 to 0) */ + a = 255 - i; + if (i<128) + p = i; + else + p = i - 255; + break; + case 1: + /* square */ + /* AM: 255, 0 */ + /* PM: 128,-128 (LFP = exactly +PMD, -PMD) */ + if (i<128) + { + a = 255; + p = 128; + } + else + { + a = 0; + p = -128; + } + break; + case 2: + /* triangle */ + /* AM: 255 down to 1 step -2; 0 up to 254 step +2 */ + /* PM: 0 to 126 step +2, 127 to 1 step -2, 0 to -126 step -2, -127 to -1 step +2*/ + if (i<128) + a = 255 - (i*2); + else + a = (i*2) - 256; + + if (i<64) /* i = 0..63 */ + p = i*2; /* 0 to 126 step +2 */ + else if (i<128) /* i = 64..127 */ + p = 255 - i*2; /* 127 to 1 step -2 */ + else if (i<192) /* i = 128..191 */ + p = 256 - i*2; /* 0 to -126 step -2*/ + else /* i = 192..255 */ + p = i*2 - 511; /*-127 to -1 step +2*/ + break; + case 3: + default: /*keep the compiler happy*/ + /* random */ + /* the real algorithm is unknown !!! + We just use a snapshot of data from real chip */ + + /* AM: range 0 to 255 */ + /* PM: range -128 to 127 */ + + a = lfo_noise_waveform[i]; + p = a-128; + break; + } + PSG->lfa = a * PSG->amd / 128; + PSG->lfp = p * PSG->pmd / 128; + + + /* The Noise Generator of the YM2151 is 17-bit shift register. + * Input to the bit16 is negated (bit0 XOR bit3) (EXNOR). + * Output of the register is negated (bit0 XOR bit3). + * Simply use bit16 as the noise output. + */ + PSG->noise_p += PSG->noise_f; + i = (PSG->noise_p>>16); /* number of events (shifts of the shift register) */ + PSG->noise_p &= 0xffff; + while (i) + { + UINT32 j; + j = ( (PSG->noise_rng ^ (PSG->noise_rng>>3) ) & 1) ^ 1; + PSG->noise_rng = (j<<16) | (PSG->noise_rng>>1); + i--; + } + + + /* phase generator */ + op = &PSG->oper[0]; /* CH 0 M1 */ + i = 8; + do + { + if (op->pms) /* only when phase modulation from LFO is enabled for this channel */ + { + INT32 mod_ind = PSG->lfp; /* -128..+127 (8bits signed) */ + if (op->pms < 6) + mod_ind >>= (6 - op->pms); + else + mod_ind <<= (op->pms - 5); + + if (mod_ind) + { + UINT32 kc_channel = op->kc_i + mod_ind; + (op+0)->phase += ( (PSG->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; + (op+1)->phase += ( (PSG->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; + (op+2)->phase += ( (PSG->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; + (op+3)->phase += ( (PSG->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; + } + else /* phase modulation from LFO is equal to zero */ + { + (op+0)->phase += (op+0)->freq; + (op+1)->phase += (op+1)->freq; + (op+2)->phase += (op+2)->freq; + (op+3)->phase += (op+3)->freq; + } + } + else /* phase modulation from LFO is disabled */ + { + (op+0)->phase += (op+0)->freq; + (op+1)->phase += (op+1)->freq; + (op+2)->phase += (op+2)->freq; + (op+3)->phase += (op+3)->freq; + } + + op+=4; + i--; + }while (i); + + + /* CSM is calculated *after* the phase generator calculations (verified on real chip) + * CSM keyon line seems to be ORed with the KO line inside of the chip. + * The result is that it only works when KO (register 0x08) is off, ie. 0 + * + * Interesting effect is that when timer A is set to 1023, the KEY ON happens + * on every sample, so there is no KEY OFF at all - the result is that + * the sound played is the same as after normal KEY ON. + */ + + if (PSG->csm_req) /* CSM KEYON/KEYOFF seqeunce request */ + { + if (PSG->csm_req==2) /* KEY ON */ + { + op = &PSG->oper[0]; /* CH 0 M1 */ + i = 32; + do + { + KEY_ON(op, 2); + op++; + i--; + }while (i); + PSG->csm_req = 1; + } + else /* KEY OFF */ + { + op = &PSG->oper[0]; /* CH 0 M1 */ + i = 32; + do + { + KEY_OFF(op,~2); + op++; + i--; + }while (i); + PSG->csm_req = 0; + } + } +} + +/* first macro saves left and right channels to mono file */ +/* second macro saves left and right channels to stereo file */ +#if 0 /*MONO*/ + #ifdef SAVE_SEPARATE_CHANNELS + #define SAVE_SINGLE_CHANNEL(j) \ + { signed int pom= -(chanout[j] & PSG->pan[j*2]); \ + if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ + fputc((unsigned short)pom&0xff,sample[j]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ + } + #else + #define SAVE_SINGLE_CHANNEL(j) + #endif +#else /*STEREO*/ + #ifdef SAVE_SEPARATE_CHANNELS + #define SAVE_SINGLE_CHANNEL(j) \ + { signed int pom = -(chanout[j] & PSG->pan[j*2]); \ + if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ + fputc((unsigned short)pom&0xff,sample[j]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ + pom = -(chanout[j] & PSG->pan[j*2+1]); \ + if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ + fputc((unsigned short)pom&0xff,sample[j]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ + } + #else + #define SAVE_SINGLE_CHANNEL(j) + #endif +#endif + +/* first macro saves left and right channels to mono file */ +/* second macro saves left and right channels to stereo file */ +#if 1 /*MONO*/ + #ifdef SAVE_SAMPLE + #define SAVE_ALL_CHANNELS \ + { signed int pom = outl; \ + /*pom = acc_calc(pom);*/ \ + /*fprintf(sample[8]," %i\n",pom);*/ \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + } + #else + #define SAVE_ALL_CHANNELS + #endif +#else /*STEREO*/ + #ifdef SAVE_SAMPLE + #define SAVE_ALL_CHANNELS \ + { signed int pom = outl; \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + pom = outr; \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + } + #else + #define SAVE_ALL_CHANNELS + #endif +#endif + + +/* Generate samples for one of the YM2151's +* +* 'num' is the number of virtual YM2151 +* '**buffers' is table of pointers to the buffers: left and right +* 'length' is the number of samples that should be generated +*/ +void ym2151_update_one(void *chip, SAMP **buffers, int length) +{ + YM2151 *PSG = (YM2151 *)chip; + signed int *chanout = PSG->chanout; + int i; + UINT32 mask = ~PSG->mask; + signed int outl,outr; + SAMP *bufL, *bufR; + + bufL = buffers[0]; + bufR = buffers[1]; + + for (i=0; ipan[0]; + if (mask & 1) outr += chanout[0] & PSG->pan[1]; + if (mask & 2) outl += (chanout[1] & PSG->pan[2]); + if (mask & 2) outr += (chanout[1] & PSG->pan[3]); + if (mask & 4) outl += (chanout[2] & PSG->pan[4]); + if (mask & 4) outr += (chanout[2] & PSG->pan[5]); + if (mask & 8) outl += (chanout[3] & PSG->pan[6]); + if (mask & 8) outr += (chanout[3] & PSG->pan[7]); + if (mask & 16) outl += (chanout[4] & PSG->pan[8]); + if (mask & 16) outr += (chanout[4] & PSG->pan[9]); + if (mask & 32) outl += (chanout[5] & PSG->pan[10]); + if (mask & 32) outr += (chanout[5] & PSG->pan[11]); + if (mask & 64) outl += (chanout[6] & PSG->pan[12]); + if (mask & 64) outr += (chanout[6] & PSG->pan[13]); + if (mask & 128) outl += (chanout[7] & PSG->pan[14]); + if (mask & 128) outr += (chanout[7] & PSG->pan[15]); + + outl >>= FINAL_SH; + outr >>= FINAL_SH; + if (outl > MAXOUT) outl = MAXOUT; + else if (outl < MINOUT) outl = MINOUT; + if (outr > MAXOUT) outr = MAXOUT; + else if (outr < MINOUT) outr = MINOUT; + ((SAMP*)bufL)[i] = (SAMP)outl; + ((SAMP*)bufR)[i] = (SAMP)outr; + + SAVE_ALL_CHANNELS + + advance(PSG); + } +} + +void ym2151_set_mask(void *_chip, UINT32 mask) +{ + YM2151 *PSG = (YM2151 *)_chip; + + PSG->mask = mask; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2151_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2151_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2151_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2151_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,75 +1,75 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Ym2151_Emu.h" -#include "ym2151.h" - -Ym2151_Emu::Ym2151_Emu() { PSG = 0; } - -Ym2151_Emu::~Ym2151_Emu() -{ - if ( PSG ) ym2151_shutdown( PSG ); -} - -int Ym2151_Emu::set_rate( double sample_rate, double clock_rate ) -{ - if ( PSG ) - { - ym2151_shutdown( PSG ); - PSG = 0; - } - - PSG = ym2151_init( clock_rate, sample_rate ); - if ( !PSG ) - return 1; - - reset(); - return 0; -} - -void Ym2151_Emu::reset() -{ - ym2151_reset_chip( PSG ); - ym2151_set_mask( PSG, 0 ); -} - -static stream_sample_t* DUMMYBUF[0x02] = {(stream_sample_t*)NULL, (stream_sample_t*)NULL}; - -void Ym2151_Emu::write( int addr, int data ) -{ - ym2151_update_one( PSG, DUMMYBUF, 0 ); - ym2151_write_reg( PSG, addr, data ); -} - -void Ym2151_Emu::mute_voices( int mask ) -{ - ym2151_set_mask( PSG, mask ); -} - -void Ym2151_Emu::run( int pair_count, sample_t* out ) -{ - SAMP bufL[ 1024 ]; - SAMP bufR[ 1024 ]; - SAMP * buffers[2] = { bufL, bufR }; - - while (pair_count > 0) - { - int todo = pair_count; - if (todo > 1024) todo = 1024; - ym2151_update_one( PSG, buffers, todo ); - - for (int i = 0; i < todo; i++) - { - int output_l = bufL [i]; - int output_r = bufR [i]; - output_l += out [0]; - output_r += out [1]; - if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); - if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); - out [0] = output_l; - out [1] = output_r; - out += 2; - } - - pair_count -= todo; - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Ym2151_Emu.h" +#include "ym2151.h" + +Ym2151_Emu::Ym2151_Emu() { PSG = 0; } + +Ym2151_Emu::~Ym2151_Emu() +{ + if ( PSG ) ym2151_shutdown( PSG ); +} + +int Ym2151_Emu::set_rate( double sample_rate, double clock_rate ) +{ + if ( PSG ) + { + ym2151_shutdown( PSG ); + PSG = 0; + } + + PSG = ym2151_init( clock_rate, sample_rate ); + if ( !PSG ) + return 1; + + reset(); + return 0; +} + +void Ym2151_Emu::reset() +{ + ym2151_reset_chip( PSG ); + ym2151_set_mask( PSG, 0 ); +} + +static stream_sample_t* DUMMYBUF[0x02] = {(stream_sample_t*)NULL, (stream_sample_t*)NULL}; + +void Ym2151_Emu::write( int addr, int data ) +{ + ym2151_update_one( PSG, DUMMYBUF, 0 ); + ym2151_write_reg( PSG, addr, data ); +} + +void Ym2151_Emu::mute_voices( int mask ) +{ + ym2151_set_mask( PSG, mask ); +} + +void Ym2151_Emu::run( int pair_count, sample_t* out ) +{ + SAMP bufL[ 1024 ]; + SAMP bufR[ 1024 ]; + SAMP * buffers[2] = { bufL, bufR }; + + while (pair_count > 0) + { + int todo = pair_count; + if (todo > 1024) todo = 1024; + ym2151_update_one( PSG, buffers, todo ); + + for (int i = 0; i < todo; i++) + { + int output_l = bufL [i]; + int output_r = bufR [i]; + output_l += out [0]; + output_r += out [1]; + if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); + if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); + out [0] = output_l; + out [1] = output_r; + out += 2; + } + + pair_count -= todo; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2151_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2151_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2151_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2151_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,33 +1,33 @@ -// YM2151 FM sound chip emulator interface - -// Game_Music_Emu $vers -#ifndef YM2151_EMU_H -#define YM2151_EMU_H - -class Ym2151_Emu { - void* PSG; -public: - Ym2151_Emu(); - ~Ym2151_Emu(); - - // Sets output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - int set_rate( double sample_rate, double clock_rate ); - - // Resets to power-up state - void reset(); - - // Mutes voice n if bit n (1 << n) of mask is set - enum { channel_count = 8 }; - void mute_voices( int mask ); - - // Writes data to addr - void write( int addr, int data ); - - // Runs and writes pair_count*2 samples to output - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif +// YM2151 FM sound chip emulator interface + +// Game_Music_Emu $vers +#ifndef YM2151_EMU_H +#define YM2151_EMU_H + +class Ym2151_Emu { + void* PSG; +public: + Ym2151_Emu(); + ~Ym2151_Emu(); + + // Sets output sample rate and chip clock rates, in Hz. Returns non-zero + // if error. + int set_rate( double sample_rate, double clock_rate ); + + // Resets to power-up state + void reset(); + + // Mutes voice n if bit n (1 << n) of mask is set + enum { channel_count = 8 }; + void mute_voices( int mask ); + + // Writes data to addr + void write( int addr, int data ); + + // Runs and writes pair_count*2 samples to output + typedef short sample_t; + enum { out_chan_count = 2 }; // stereo + void run( int pair_count, sample_t* out ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ym2151.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ym2151.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ym2151.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ym2151.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,89 +1,89 @@ -/* -** File: ym2151.h - header file for software implementation of YM2151 -** FM Operator Type-M(OPM) -** -** (c) 1997-2002 Jarek Burczynski (s0246@poczta.onet.pl, bujar@mame.net) -** Some of the optimizing ideas by Tatsuyuki Satoh -** -** Version 2.150 final beta May, 11th 2002 -** -** -** I would like to thank following people for making this project possible: -** -** Beauty Planets - for making a lot of real YM2151 samples and providing -** additional informations about the chip. Also for the time spent making -** the samples and the speed of replying to my endless requests. -** -** Shigeharu Isoda - for general help, for taking time to scan his YM2151 -** Japanese Manual first of all, and answering MANY of my questions. -** -** Nao - for giving me some info about YM2151 and pointing me to Shigeharu. -** Also for creating fmemu (which I still use to test the emulator). -** -** Aaron Giles and Chris Hardy - they made some samples of one of my favourite -** arcade games so I could compare it to my emulator. -** -** Bryan McPhail and Tim (powerjaw) - for making some samples. -** -** Ishmair - for the datasheet and motivation. -*/ - -#pragma once - -#ifndef __YM2151_H__ -#define __YM2151_H__ - - -/* 16- and 8-bit samples (signed) are supported*/ -#define SAMPLE_BITS 16 - -#include "mamedef.h" - -typedef stream_sample_t SAMP; -/* -#if (SAMPLE_BITS==16) - typedef INT16 SAMP; -#endif -#if (SAMPLE_BITS==8) - typedef signed char SAMP; -#endif -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Initialize YM2151 emulator(s). -** -** 'num' is the number of virtual YM2151's to allocate -** 'clock' is the chip clock in Hz -** 'rate' is sampling rate -*/ -void *ym2151_init(int clock, int rate); - -/* shutdown the YM2151 emulators*/ -void ym2151_shutdown(void *chip); - -/* reset all chip registers for YM2151 number 'num'*/ -void ym2151_reset_chip(void *chip); - -/* -** Generate samples for one of the YM2151's -** -** 'num' is the number of virtual YM2151 -** '**buffers' is table of pointers to the buffers: left and right -** 'length' is the number of samples that should be generated -*/ -void ym2151_update_one(void *chip, SAMP **buffers, int length); - -/* write 'v' to register 'r' on YM2151 chip number 'n'*/ -void ym2151_write_reg(void *chip, int r, int v); - -void ym2151_set_mask(void *chip, UINT32 mask); - -#ifdef __cplusplus -} -#endif - -#endif /*__YM2151_H__*/ +/* +** File: ym2151.h - header file for software implementation of YM2151 +** FM Operator Type-M(OPM) +** +** (c) 1997-2002 Jarek Burczynski (s0246@poczta.onet.pl, bujar@mame.net) +** Some of the optimizing ideas by Tatsuyuki Satoh +** +** Version 2.150 final beta May, 11th 2002 +** +** +** I would like to thank following people for making this project possible: +** +** Beauty Planets - for making a lot of real YM2151 samples and providing +** additional informations about the chip. Also for the time spent making +** the samples and the speed of replying to my endless requests. +** +** Shigeharu Isoda - for general help, for taking time to scan his YM2151 +** Japanese Manual first of all, and answering MANY of my questions. +** +** Nao - for giving me some info about YM2151 and pointing me to Shigeharu. +** Also for creating fmemu (which I still use to test the emulator). +** +** Aaron Giles and Chris Hardy - they made some samples of one of my favourite +** arcade games so I could compare it to my emulator. +** +** Bryan McPhail and Tim (powerjaw) - for making some samples. +** +** Ishmair - for the datasheet and motivation. +*/ + +#pragma once + +#ifndef __YM2151_H__ +#define __YM2151_H__ + + +/* 16- and 8-bit samples (signed) are supported*/ +#define SAMPLE_BITS 16 + +#include "mamedef.h" + +typedef stream_sample_t SAMP; +/* +#if (SAMPLE_BITS==16) + typedef INT16 SAMP; +#endif +#if (SAMPLE_BITS==8) + typedef signed char SAMP; +#endif +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Initialize YM2151 emulator(s). +** +** 'num' is the number of virtual YM2151's to allocate +** 'clock' is the chip clock in Hz +** 'rate' is sampling rate +*/ +void *ym2151_init(int clock, int rate); + +/* shutdown the YM2151 emulators*/ +void ym2151_shutdown(void *chip); + +/* reset all chip registers for YM2151 number 'num'*/ +void ym2151_reset_chip(void *chip); + +/* +** Generate samples for one of the YM2151's +** +** 'num' is the number of virtual YM2151 +** '**buffers' is table of pointers to the buffers: left and right +** 'length' is the number of samples that should be generated +*/ +void ym2151_update_one(void *chip, SAMP **buffers, int length); + +/* write 'v' to register 'r' on YM2151 chip number 'n'*/ +void ym2151_write_reg(void *chip, int r, int v); + +void ym2151_set_mask(void *chip, UINT32 mask); + +#ifdef __cplusplus +} +#endif + +#endif /*__YM2151_H__*/ diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ym2413.c kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ym2413.c --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ym2413.c 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ym2413.c 2013-05-31 22:59:22.000000000 +0000 @@ -1,2108 +1,2108 @@ -/* -** -** File: ym2413.c - software implementation of YM2413 -** FM sound generator type OPLL -** -** Copyright Jarek Burczynski -** -** Version 1.0 -** - - Features as listed in LSI-212413A2 data sheet: - 1. FM Sound Generator for real sound creation. - 2. Two Selectable modes: 9 simultaneous sounds or 6 melody sounds plus 5 rhythm sounds - (different tones can be used together in either case). - 3. Built-in Instruments data (15 melody tones, 5 rhythm tones, "CAPTAIN and TELETEXT applicalbe tones). - 4. Built-in DA Converter. - 5. Built-in Quartz Oscillator. - 6. Built-in Vibrato Oscillator/AM Oscillator - 7. TTL Compatible Input. - 8. Si-Gate NMOS LSI - 9. A single 5V power source. - -to do: - -- make sure of the sinus amplitude bits - -- make sure of the EG resolution bits (looks like the biggest - modulation index generated by the modulator is 123, 124 = no modulation) -- find proper algorithm for attack phase of EG - -- tune up instruments ROM - -- support sample replay in test mode (it is NOT as simple as setting bit 0 - in register 0x0f and using register 0x10 for sample data). - Which games use this feature ? - - -*/ - -#define _USE_MATH_DEFINES -#include -#include -#include -#include "mamedef.h" -#include "ym2413.h" - -#ifndef INLINE -#define INLINE static __inline -#endif -#ifndef logerror -#define logerror (void) -#endif - -#ifndef M_PI - #define M_PI 3.14159265358979323846 -#endif - -/* output final shift */ -#if (SAMPLE_BITS==16) - #define FINAL_SH (0) - #define MAXOUT (+32767) - #define MINOUT (-32768) -#else - #define FINAL_SH (8) - #define MAXOUT (+127) - #define MINOUT (-128) -#endif - - -#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define EG_SH 16 /* 16.16 fixed point (EG timing) */ -#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ - -#define FREQ_MASK ((1<>KSR */ - UINT8 mul; /* multiple: mul_tab[ML] */ - - /* Phase Generator */ - UINT32 phase; /* frequency counter */ - UINT32 freq; /* frequency counter step */ - UINT8 fb_shift; /* feedback shift value */ - INT32 op1_out[2]; /* slot1 output for feedback */ - - /* Envelope Generator */ - UINT8 eg_type; /* percussive/nonpercussive mode*/ - UINT8 state; /* phase type */ - UINT32 TL; /* total level: TL << 2 */ - INT32 TLL; /* adjusted now TL */ - INT32 volume; /* envelope counter */ - UINT32 sl; /* sustain level: sl_tab[SL] */ - - UINT8 eg_sh_dp; /* (dump state) */ - UINT8 eg_sel_dp; /* (dump state) */ - UINT8 eg_sh_ar; /* (attack state) */ - UINT8 eg_sel_ar; /* (attack state) */ - UINT8 eg_sh_dr; /* (decay state) */ - UINT8 eg_sel_dr; /* (decay state) */ - UINT8 eg_sh_rr; /* (release state for non-perc.)*/ - UINT8 eg_sel_rr; /* (release state for non-perc.)*/ - UINT8 eg_sh_rs; /* (release state for perc.mode)*/ - UINT8 eg_sel_rs; /* (release state for perc.mode)*/ - - UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ - - /* LFO */ - UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ - UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ - - /* waveform select */ - unsigned int wavetable; -} OPLL_SLOT; - -#define OPLL_MASK_CH(x) (1<<(x)) -#define OPLL_MASK_HH (1<<(9)) -#define OPLL_MASK_CYM (1<<(10)) -#define OPLL_MASK_TOM (1<<(11)) -#define OPLL_MASK_SD (1<<(12)) -#define OPLL_MASK_BD (1<<(13)) -#define OPLL_MASK_RHYTHM ( OPLL_MASK_HH | OPLL_MASK_CYM | OPLL_MASK_TOM | OPLL_MASK_SD | OPLL_MASK_BD ) - -typedef struct{ - OPLL_SLOT SLOT[2]; - /* phase generator state */ - UINT32 block_fnum; /* block+fnum */ - UINT32 fc; /* Freq. freqement base */ - UINT32 ksl_base; /* KeyScaleLevel Base step */ - UINT8 kcode; /* key code (for key scaling) */ - UINT8 sus; /* sus on/off (release speed in percussive mode)*/ -} OPLL_CH; - -/* chip state */ -typedef struct { - OPLL_CH P_CH[9]; /* OPLL chips have 9 channels*/ - UINT8 instvol_r[9]; /* instrument/volume (or volume/volume in percussive mode)*/ - - UINT32 eg_cnt; /* global envelope generator counter */ - UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ - UINT32 eg_timer_add; /* step of eg_timer */ - UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ - - UINT8 rhythm; /* Rhythm mode */ - - /* LFO */ - UINT32 lfo_am_cnt; - UINT32 lfo_am_inc; - UINT32 lfo_pm_cnt; - UINT32 lfo_pm_inc; - - UINT32 noise_rng; /* 23 bit noise shift register */ - UINT32 noise_p; /* current noise 'phase' */ - UINT32 noise_f; /* current noise period */ - - -/* instrument settings */ -/* - 0-user instrument - 1-15 - fixed instruments - 16 -bass drum settings - 17,18 - other percussion instruments -*/ - UINT8 inst_tab[19][8]; - - /* external event callback handlers */ - OPLL_UPDATEHANDLER UpdateHandler; /* stream update handler */ - void * UpdateParam; /* stream update parameter */ - - UINT32 fn_tab[1024]; /* fnumber->increment counter */ - - UINT8 address; /* address register */ - UINT8 status; /* status flag */ - - int clock; /* master clock (Hz) */ - int rate; /* sampling rate (Hz) */ - double freqbase; /* frequency base */ - - /* work table */ - OPLL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2; - - signed int output[2]; - - UINT32 LFO_AM; - INT32 LFO_PM; - - int chip_type; - UINT32 mask; -} YM2413; - -/* key scale level */ -/* table is 3dB/octave, DV converts this into 6dB/octave */ -/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ -#define DV (0.1875/1.0) -static const UINT32 ksl_tab[8*16]= -{ - /* OCT 0 */ - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - /* OCT 1 */ - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, - 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, - /* OCT 2 */ - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, - 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, - 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, - /* OCT 3 */ - 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, - 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, - 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, - 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, - /* OCT 4 */ - 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, - 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, - 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, - 10.875/DV,11.250/DV,11.625/DV,12.000/DV, - /* OCT 5 */ - 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, - 9.000/DV,10.125/DV,10.875/DV,11.625/DV, - 12.000/DV,12.750/DV,13.125/DV,13.500/DV, - 13.875/DV,14.250/DV,14.625/DV,15.000/DV, - /* OCT 6 */ - 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, - 12.000/DV,13.125/DV,13.875/DV,14.625/DV, - 15.000/DV,15.750/DV,16.125/DV,16.500/DV, - 16.875/DV,17.250/DV,17.625/DV,18.000/DV, - /* OCT 7 */ - 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, - 15.000/DV,16.125/DV,16.875/DV,17.625/DV, - 18.000/DV,18.750/DV,19.125/DV,19.500/DV, - 19.875/DV,20.250/DV,20.625/DV,21.000/DV -}; -#undef DV - -/* sustain level table (3dB per step) */ -/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,45 (dB)*/ -#define SC(db) (UINT32) ( db * (1.0/ENV_STEP) ) -static const UINT32 sl_tab[16]={ - SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), - SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(15) -}; -#undef SC - - -#define RATE_STEPS (8) -static const unsigned char eg_inc[15*RATE_STEPS]={ - -/*cycle:0 1 2 3 4 5 6 7*/ - -/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ -/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ -/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ -/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ - -/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ -/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ -/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ -/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ - -/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ -/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ -/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ -/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ - -/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ -/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ -/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ -}; - - -#define O(a) (a*RATE_STEPS) - -/*note that there is no O(13) in this table - it's directly in the code */ -static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ -/* 16 infinite time rates */ -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), - -/* rates 00-12 */ -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), - -/* rate 13 */ -O( 4),O( 5),O( 6),O( 7), - -/* rate 14 */ -O( 8),O( 9),O(10),O(11), - -/* rate 15 */ -O(12),O(12),O(12),O(12), - -/* 16 dummy rates (same as 15 3) */ -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), - -}; -#undef O - -/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ -/*shift 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0 */ -/*mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0 */ - -#define O(a) (a*1) -static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ -/* 16 infinite time rates */ -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), - -/* rates 00-12 */ -O(13),O(13),O(13),O(13), -O(12),O(12),O(12),O(12), -O(11),O(11),O(11),O(11), -O(10),O(10),O(10),O(10), -O( 9),O( 9),O( 9),O( 9), -O( 8),O( 8),O( 8),O( 8), -O( 7),O( 7),O( 7),O( 7), -O( 6),O( 6),O( 6),O( 6), -O( 5),O( 5),O( 5),O( 5), -O( 4),O( 4),O( 4),O( 4), -O( 3),O( 3),O( 3),O( 3), -O( 2),O( 2),O( 2),O( 2), -O( 1),O( 1),O( 1),O( 1), - -/* rate 13 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 14 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 15 */ -O( 0),O( 0),O( 0),O( 0), - -/* 16 dummy rates (same as 15 3) */ -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), - -}; -#undef O - - -/* multiple table */ -#define ML 2 -static const UINT8 mul_tab[16]= { -/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ - 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML, - 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML -}; -#undef ML - -/* TL_TAB_LEN is calculated as: -* 11 - sinus amplitude bits (Y axis) -* 2 - sinus sign bit (Y axis) -* TL_RES_LEN - sinus resolution (X axis) -*/ -#define TL_TAB_LEN (11*2*TL_RES_LEN) -static signed int tl_tab[TL_TAB_LEN]; - -#define ENV_QUIET (TL_TAB_LEN>>5) - -/* sin waveform table in 'decibel' scale */ -/* two waveforms on OPLL type chips */ -static unsigned int sin_tab[SIN_LEN * 2]; - - -/* LFO Amplitude Modulation table (verified on real YM3812) - 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples - - Length: 210 elements. - - Each of the elements has to be repeated - exactly 64 times (on 64 consecutive samples). - The whole table takes: 64 * 210 = 13440 samples. - -We use data>>1, until we find what it really is on real chip... - -*/ - -#define LFO_AM_TAB_ELEMENTS 210 - -static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { -0,0,0,0,0,0,0, -1,1,1,1, -2,2,2,2, -3,3,3,3, -4,4,4,4, -5,5,5,5, -6,6,6,6, -7,7,7,7, -8,8,8,8, -9,9,9,9, -10,10,10,10, -11,11,11,11, -12,12,12,12, -13,13,13,13, -14,14,14,14, -15,15,15,15, -16,16,16,16, -17,17,17,17, -18,18,18,18, -19,19,19,19, -20,20,20,20, -21,21,21,21, -22,22,22,22, -23,23,23,23, -24,24,24,24, -25,25,25,25, -26,26,26, -25,25,25,25, -24,24,24,24, -23,23,23,23, -22,22,22,22, -21,21,21,21, -20,20,20,20, -19,19,19,19, -18,18,18,18, -17,17,17,17, -16,16,16,16, -15,15,15,15, -14,14,14,14, -13,13,13,13, -12,12,12,12, -11,11,11,11, -10,10,10,10, -9,9,9,9, -8,8,8,8, -7,7,7,7, -6,6,6,6, -5,5,5,5, -4,4,4,4, -3,3,3,3, -2,2,2,2, -1,1,1,1 -}; - -/* LFO Phase Modulation table (verified on real YM2413) */ -static const INT8 lfo_pm_table[8*8] = { - -/* FNUM2/FNUM = 0 00xxxxxx (0x0000) */ -0, 0, 0, 0, 0, 0, 0, 0, - -/* FNUM2/FNUM = 0 01xxxxxx (0x0040) */ -1, 0, 0, 0,-1, 0, 0, 0, - -/* FNUM2/FNUM = 0 10xxxxxx (0x0080) */ -2, 1, 0,-1,-2,-1, 0, 1, - -/* FNUM2/FNUM = 0 11xxxxxx (0x00C0) */ -3, 1, 0,-1,-3,-1, 0, 1, - -/* FNUM2/FNUM = 1 00xxxxxx (0x0100) */ -4, 2, 0,-2,-4,-2, 0, 2, - -/* FNUM2/FNUM = 1 01xxxxxx (0x0140) */ -5, 2, 0,-2,-5,-2, 0, 2, - -/* FNUM2/FNUM = 1 10xxxxxx (0x0180) */ -6, 3, 0,-3,-6,-3, 0, 3, - -/* FNUM2/FNUM = 1 11xxxxxx (0x01C0) */ -7, 3, 0,-3,-7,-3, 0, 3, -}; - - - - - - -/* This is not 100% perfect yet but very close */ -/* - - multi parameters are 100% correct (instruments and drums) - - LFO PM and AM enable are 100% correct - - waveform DC and DM select are 100% correct -*/ - -static const unsigned char table[19][8] = { -/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */ -/* 0 1 2 3 4 5 6 7 */ - {0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, /* 0 */ - - {0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, /* 1 */ - {0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13 }, /* 2 */ - {0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23 }, /* 3 */ - {0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27 }, /* 4 */ - -/* {0x22, 0x21, 0x1e, 0x09, 0xf0, 0x76, 0x08, 0x28 }, //5 */ - {0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18 }, /* 5 */ - -/* {0x31, 0x22, 0x16, 0x09, 0x90, 0x7f, 0x00, 0x08 }, //6 */ - {0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13 }, /* 6 */ - - {0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17 }, /* 7 */ - {0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07 }, /* 8 */ - {0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, /* 9 */ - -/* {0x61, 0x61, 0x0c, 0x08, 0x85, 0xa0, 0x79, 0x07 }, //A */ - {0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07 }, /* A */ - - {0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22 }, /* B */ - {0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12 }, /* C */ - -/* {0x61, 0x10, 0x0c, 0x08, 0xf2, 0xc4, 0x40, 0xc8 }, //D */ - {0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44 }, /* D */ - - {0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3 }, /* E */ - {0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13 }, /* F */ - -/* drum instruments definitions */ -/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */ -/* 0 1 2 3 4 5 6 7 */ - {0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */ - {0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */ - {0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */ -}; - -static const unsigned char table_vrc7[15][8] = -{ -/* VRC7 instruments, January 17, 2004 update -Xodnizel */ - {0x03, 0x21, 0x04, 0x06, 0x8D, 0xF2, 0x42, 0x17}, - {0x13, 0x41, 0x05, 0x0E, 0x99, 0x96, 0x63, 0x12}, - {0x31, 0x11, 0x10, 0x0A, 0xF0, 0x9C, 0x32, 0x02}, - {0x21, 0x61, 0x1D, 0x07, 0x9F, 0x64, 0x20, 0x27}, - {0x22, 0x21, 0x1E, 0x06, 0xF0, 0x76, 0x08, 0x28}, - {0x02, 0x01, 0x06, 0x00, 0xF0, 0xF2, 0x03, 0x95}, - {0x21, 0x61, 0x1C, 0x07, 0x82, 0x81, 0x16, 0x07}, - {0x23, 0x21, 0x1A, 0x17, 0xEF, 0x82, 0x25, 0x15}, - {0x25, 0x11, 0x1F, 0x00, 0x86, 0x41, 0x20, 0x11}, - {0x85, 0x01, 0x1F, 0x0F, 0xE4, 0xA2, 0x11, 0x12}, - {0x07, 0xC1, 0x2B, 0x45, 0xB4, 0xF1, 0x24, 0xF4}, - {0x61, 0x23, 0x11, 0x06, 0x96, 0x96, 0x13, 0x16}, - {0x01, 0x02, 0xD3, 0x05, 0x82, 0xA2, 0x31, 0x51}, - {0x61, 0x22, 0x0D, 0x02, 0xC3, 0x7F, 0x24, 0x05}, - {0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x44, 0x17}, - -}; - -INLINE int limit( int val, int max, int min ) { - if ( val > max ) - val = max; - else if ( val < min ) - val = min; - - return val; -} - - -/* advance LFO to next sample */ -INLINE void advance_lfo(YM2413 *chip) -{ - /* LFO */ - chip->lfo_am_cnt += chip->lfo_am_inc; - if (chip->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<LFO_AM = lfo_am_table[ chip->lfo_am_cnt >> LFO_SH ] >> 1; - - chip->lfo_pm_cnt += chip->lfo_pm_inc; - chip->LFO_PM = (chip->lfo_pm_cnt>>LFO_SH) & 7; -} - -/* advance to next sample */ -INLINE void advance(YM2413 *chip) -{ - OPLL_CH *CH; - OPLL_SLOT *op; - unsigned int i; - - /* Envelope Generator */ - chip->eg_timer += chip->eg_timer_add; - - while (chip->eg_timer >= chip->eg_timer_overflow) - { - chip->eg_timer -= chip->eg_timer_overflow; - - chip->eg_cnt++; - - for (i=0; i<9*2; i++) - { - CH = &chip->P_CH[i/2]; - - op = &CH->SLOT[i&1]; - - switch(op->state) - { - - case EG_DMP: /* dump phase */ - /*dump phase is performed by both operators in each channel*/ - /*when CARRIER envelope gets down to zero level, - ** phases in BOTH opearators are reset (at the same time ?) - */ - if ( !(chip->eg_cnt & ((1<eg_sh_dp)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_dp + ((chip->eg_cnt>>op->eg_sh_dp)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_ATT; - /* restart Phase Generator */ - op->phase = 0; - } - } - break; - - case EG_ATT: /* attack phase */ - if ( !(chip->eg_cnt & ((1<eg_sh_ar)-1) ) ) - { - op->volume += (~op->volume * - (eg_inc[op->eg_sel_ar + ((chip->eg_cnt>>op->eg_sh_ar)&7)]) - ) >>2; - - if (op->volume <= MIN_ATT_INDEX) - { - op->volume = MIN_ATT_INDEX; - op->state = EG_DEC; - } - } - break; - - case EG_DEC: /* decay phase */ - if ( !(chip->eg_cnt & ((1<eg_sh_dr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_dr + ((chip->eg_cnt>>op->eg_sh_dr)&7)]; - - if ( op->volume >= (INT32)(op->sl) ) - op->state = EG_SUS; - } - break; - - case EG_SUS: /* sustain phase */ - /* this is important behaviour: - one can change percusive/non-percussive modes on the fly and - the chip will remain in sustain phase - verified on real YM3812 */ - - if(op->eg_type) /* non-percussive mode (sustained tone) */ - { - /* do nothing */ - } - else /* percussive mode */ - { - /* during sustain phase chip adds Release Rate (in percussive mode) */ - if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - op->volume = MAX_ATT_INDEX; - } - /* else do nothing in sustain phase */ - } - break; - - case EG_REL: /* release phase */ - /* exclude modulators in melody channels from performing anything in this mode*/ - /* allowed are only carriers in melody mode and rhythm slots in rhythm mode */ - - /*This table shows which operators and on what conditions are allowed to perform EG_REL: - (a) - always perform EG_REL - (n) - never perform EG_REL - (r) - perform EG_REL in Rhythm mode ONLY - 0: 0 (n), 1 (a) - 1: 2 (n), 3 (a) - 2: 4 (n), 5 (a) - 3: 6 (n), 7 (a) - 4: 8 (n), 9 (a) - 5: 10(n), 11(a) - 6: 12(r), 13(a) - 7: 14(r), 15(a) - 8: 16(r), 17(a) - */ - if ( (i&1) || ((chip->rhythm&0x20) && (i>=12)) )/* exclude modulators */ - { - if(op->eg_type) /* non-percussive mode (sustained tone) */ - /*this is correct: use RR when SUS = OFF*/ - /*and use RS when SUS = ON*/ - { - if (CH->sus) - { - if ( !(chip->eg_cnt & ((1<eg_sh_rs)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rs + ((chip->eg_cnt>>op->eg_sh_rs)&7)]; - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_OFF; - } - } - } - else - { - if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_OFF; - } - } - } - } - else /* percussive mode */ - { - if ( !(chip->eg_cnt & ((1<eg_sh_rs)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rs + ((chip->eg_cnt>>op->eg_sh_rs)&7)]; - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_OFF; - } - } - } - } - break; - - default: - break; - } - } - } - - for (i=0; i<9*2; i++) - { - CH = &chip->P_CH[i/2]; - op = &CH->SLOT[i&1]; - - /* Phase Generator */ - if(op->vib) - { - UINT8 block; - - unsigned int fnum_lfo = 8*((CH->block_fnum&0x01c0) >> 6); - unsigned int block_fnum = CH->block_fnum * 2; - signed int lfo_fn_table_index_offset = lfo_pm_table[chip->LFO_PM + fnum_lfo ]; - - if (lfo_fn_table_index_offset) /* LFO phase modulation active */ - { - block_fnum += lfo_fn_table_index_offset; - block = (block_fnum&0x1c00) >> 10; - op->phase += (chip->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; - } - else /* LFO phase modulation = zero */ - { - op->phase += op->freq; - } - } - else /* LFO phase modulation disabled for this operator */ - { - op->phase += op->freq; - } - } - - /* The Noise Generator of the YM3812 is 23-bit shift register. - * Period is equal to 2^23-2 samples. - * Register works at sampling frequency of the chip, so output - * can change on every sample. - * - * Output of the register and input to the bit 22 is: - * bit0 XOR bit14 XOR bit15 XOR bit22 - * - * Simply use bit 22 as the noise output. - */ - - chip->noise_p += chip->noise_f; - i = chip->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ - chip->noise_p &= FREQ_MASK; - while (i) - { - /* - UINT32 j; - j = ( (chip->noise_rng) ^ (chip->noise_rng>>14) ^ (chip->noise_rng>>15) ^ (chip->noise_rng>>22) ) & 1; - chip->noise_rng = (j<<22) | (chip->noise_rng>>1); - */ - - /* - Instead of doing all the logic operations above, we - use a trick here (and use bit 0 as the noise output). - The difference is only that the noise bit changes one - step ahead. This doesn't matter since we don't know - what is real state of the noise_rng after the reset. - */ - - if (chip->noise_rng & 1) chip->noise_rng ^= 0x800302; - chip->noise_rng >>= 1; - - i--; - } -} - - -INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - UINT32 p; - - p = (env<<5) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<17))) >> FREQ_SH ) & SIN_MASK) ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - -INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - UINT32 p; - INT32 i; - - i = (phase & ~FREQ_MASK) + pm; - -/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/ - - p = (env<<5) + sin_tab[ wave_tab + ((i>>FREQ_SH) & SIN_MASK)]; - -/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - - -#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (chip->LFO_AM & (OP)->AMmask)) - -/* calculate output */ -INLINE void chan_calc( YM2413 *chip, OPLL_CH *CH ) -{ - OPLL_SLOT *SLOT; - unsigned int env; - signed int out; - signed int phase_modulation; /* phase modulation input (SLOT 2) */ - - - /* SLOT 1 */ - SLOT = &CH->SLOT[SLOT1]; - env = volume_calc(SLOT); - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - - SLOT->op1_out[0] = SLOT->op1_out[1]; - phase_modulation = SLOT->op1_out[0]; - - SLOT->op1_out[1] = 0; - - if( env < ENV_QUIET ) - { - if (!SLOT->fb_shift) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->phase, env, (out<fb_shift), SLOT->wavetable ); - } - - /* SLOT 2 */ - - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - { - signed int outp = op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable); - chip->output[0] += outp; - /* output[0] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable); */ - } -} - -/* - operators used in the rhythm sounds generation process: - - Envelope Generator: - -channel operator register number Bass High Snare Tom Top -/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal - 6 / 0 12 50 70 90 f0 + - 6 / 1 15 53 73 93 f3 + - 7 / 0 13 51 71 91 f1 + - 7 / 1 16 54 74 94 f4 + - 8 / 0 14 52 72 92 f2 + - 8 / 1 17 55 75 95 f5 + - - Phase Generator: - -channel operator register number Bass High Snare Tom Top -/ slot number MULTIPLE Drum Hat Drum Tom Cymbal - 6 / 0 12 30 + - 6 / 1 15 33 + - 7 / 0 13 31 + + + - 7 / 1 16 34 ----- n o t u s e d ----- - 8 / 0 14 32 + - 8 / 1 17 35 + + - -channel operator register number Bass High Snare Tom Top -number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal - 6 12,15 B6 A6 + - - 7 13,16 B7 A7 + + + - - 8 14,17 B8 A8 + + + - -*/ - -/* calculate rhythm */ - -INLINE void rhythm_calc( YM2413 *chip, OPLL_CH *CH, unsigned int noise ) -{ - OPLL_SLOT *SLOT; - signed int out; - unsigned int env; - signed int phase_modulation; /* phase modulation input (SLOT 2) */ - - - /* Bass Drum (verified on real YM3812): - - depends on the channel 6 'connect' register: - when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) - when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored - - output sample always is multiplied by 2 - */ - - - /* SLOT 1 */ - if ( !(chip->mask & OPLL_MASK_BD) ) - { - SLOT = &CH[6].SLOT[SLOT1]; - env = volume_calc(SLOT); - - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - SLOT->op1_out[0] = SLOT->op1_out[1]; - - phase_modulation = SLOT->op1_out[0]; - - SLOT->op1_out[1] = 0; - if( env < ENV_QUIET ) - { - if (!SLOT->fb_shift) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->phase, env, (out<fb_shift), SLOT->wavetable ); - } - - /* SLOT 2 */ - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - chip->output[1] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable) * 2; - } - - - /* Phase generation is based on: - HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) - SD (16) channel 7->slot 1 - TOM (14) channel 8->slot 1 - TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ - - /* Envelope generation based on: - HH channel 7->slot1 - SD channel 7->slot2 - TOM channel 8->slot1 - TOP channel 8->slot2 */ - - - /* The following formulas can be well optimized. - I leave them in direct form for now (in case I've missed something). - */ - - /* High Hat (verified on real YM3812) */ - if ( !(chip->mask & OPLL_MASK_HH) ) - { - env = volume_calc(chip->SLOT7_1); - if( env < ENV_QUIET ) - { - - /* high hat phase generation: - phase = d0 or 234 (based on frequency only) - phase = 34 or 2d0 (based on noise) - */ - - /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit7 = ((chip->SLOT7_1->phase>>FREQ_SH)>>7)&1; - unsigned char bit3 = ((chip->SLOT7_1->phase>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((chip->SLOT7_1->phase>>FREQ_SH)>>2)&1; - - unsigned char res1 = (bit2 ^ bit7) | bit3; - - /* when res1 = 0 phase = 0x000 | 0xd0; */ - /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ - UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; - - /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((chip->SLOT8_2->phase>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((chip->SLOT8_2->phase>>FREQ_SH)>>3)&1; - - unsigned char res2 = (bit3e | bit5e); - - /* when res2 = 0 pass the phase from calculation above (res1); */ - /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ - if (res2) - phase = (0x200|(0xd0>>2)); - - - /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ - /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ - if (phase&0x200) - { - if (noise) - phase = 0x200|0xd0; - } - else - /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ - /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ - { - if (noise) - phase = 0xd0>>2; - } - - chip->output[1] += op_calc(phase<SLOT7_1->wavetable) * 2; - } - } - - /* Snare Drum (verified on real YM3812) */ - if ( !(chip->mask & OPLL_MASK_SD) ) - { - env = volume_calc(chip->SLOT7_2); - if( env < ENV_QUIET ) - { - /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit8 = ((chip->SLOT7_1->phase>>FREQ_SH)>>8)&1; - - /* when bit8 = 0 phase = 0x100; */ - /* when bit8 = 1 phase = 0x200; */ - UINT32 phase = bit8 ? 0x200 : 0x100; - - /* Noise bit XOR'es phase by 0x100 */ - /* when noisebit = 0 pass the phase from calculation above */ - /* when noisebit = 1 phase ^= 0x100; */ - /* in other words: phase ^= (noisebit<<8); */ - if (noise) - phase ^= 0x100; - - chip->output[1] += op_calc(phase<SLOT7_2->wavetable) * 2; - } - } - - /* Tom Tom (verified on real YM3812) */ - if ( !(chip->mask & OPLL_MASK_TOM) ) - { - env = volume_calc(chip->SLOT8_1); - if( env < ENV_QUIET ) - chip->output[1] += op_calc(chip->SLOT8_1->phase, env, 0, chip->SLOT8_1->wavetable) * 2; - } - - /* Top Cymbal (verified on real YM2413) */ - if ( !(chip->mask & OPLL_MASK_CYM) ) - { - env = volume_calc(chip->SLOT8_2); - if( env < ENV_QUIET ) - { - /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit7 = ((chip->SLOT7_1->phase>>FREQ_SH)>>7)&1; - unsigned char bit3 = ((chip->SLOT7_1->phase>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((chip->SLOT7_1->phase>>FREQ_SH)>>2)&1; - - unsigned char res1 = (bit2 ^ bit7) | bit3; - - /* when res1 = 0 phase = 0x000 | 0x100; */ - /* when res1 = 1 phase = 0x200 | 0x100; */ - UINT32 phase = res1 ? 0x300 : 0x100; - - /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((chip->SLOT8_2->phase>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((chip->SLOT8_2->phase>>FREQ_SH)>>3)&1; - - unsigned char res2 = (bit3e | bit5e); - /* when res2 = 0 pass the phase from calculation above (res1); */ - /* when res2 = 1 phase = 0x200 | 0x100; */ - if (res2) - phase = 0x300; - - chip->output[1] += op_calc(phase<SLOT8_2->wavetable) * 2; - } - } -} - - -/* generic table initialize */ -static int init_tables(void) -{ - signed int i,x; - signed int n; - double o,m; - - - for (x=0; x>= 4; /* 12 bits here */ - if (n&1) /* round to nearest */ - n = (n>>1)+1; - else - n = n>>1; - /* 11 bits here (rounded) */ - tl_tab[ x*2 + 0 ] = n; - tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; - - for (i=1; i<11; i++) - { - tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; - tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; - } - #if 0 - logerror("tl %04i", x*2); - for (i=0; i<11; i++) - logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); - logerror("\n"); - #endif - } - /*logerror("ym2413.c: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ - - - for (i=0; i0.0) - o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ - else - o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ - - o = o / (ENV_STEP/4); - - n = (int)(2.0*o); - if (n&1) /* round to nearest */ - n = (n>>1)+1; - else - n = n>>1; - - /* waveform 0: standard sinus */ - sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); - - /*logerror("ym2413.c: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ - - - /* waveform 1: __ __ */ - /* / \____/ \____*/ - /* output only first half of the sinus waveform (positive one) */ - if (i & (1<<(SIN_BITS-1)) ) - sin_tab[1*SIN_LEN+i] = TL_TAB_LEN; - else - sin_tab[1*SIN_LEN+i] = sin_tab[i]; - - /*logerror("ym2413.c: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] );*/ - } -#if 0 - logerror("YM2413.C: ENV_QUIET= %08x (*32=%08x)\n", ENV_QUIET, ENV_QUIET*32 ); - for (i=0; ifreqbase = (chip->rate) ? ((double)chip->clock / 72.0) / chip->rate : 0; - if ( fabs( chip->freqbase - 1.0 ) < 0.0000001 ) - chip->freqbase = 1.0; -#if 0 - chip->rate = (double)chip->clock / 72.0; - chip->freqbase = 1.0; - logerror("freqbase=%f\n", chip->freqbase); -#endif - - - - /* make fnumber -> increment counter table */ - for( i = 0 ; i < 1024; i++ ) - { - /* OPLL (YM2413) phase increment counter = 18bit */ - - chip->fn_tab[i] = (UINT32)( (double)i * 64 * chip->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ -#if 0 - logerror("ym2413.c: fn_tab[%4i] = %08x (dec=%8i)\n", - i, chip->fn_tab[i]>>6, chip->fn_tab[i]>>6 ); -#endif - } - -#if 0 - for( i=0 ; i < 16 ; i++ ) - { - logerror("ym2413.c: sl_tab[%i] = %08x\n", i, sl_tab[i] ); - } - for( i=0 ; i < 8 ; i++ ) - { - int j; - logerror("ym2413.c: ksl_tab[oct=%2i] =",i); - for (j=0; j<16; j++) - { - logerror("%08x ", ksl_tab[i*16+j] ); - } - logerror("\n"); - } -#endif - - - /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ - /* One entry from LFO_AM_TABLE lasts for 64 samples */ - chip->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; - - /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ - chip->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; - - /*logerror ("chip->lfo_am_inc = %8x ; chip->lfo_pm_inc = %8x\n", chip->lfo_am_inc, chip->lfo_pm_inc);*/ - - /* Noise generator: a step takes 1 sample */ - chip->noise_f = (1.0 / 1.0) * (1<freqbase; - /*logerror("YM2413init noise_f=%8x\n", chip->noise_f);*/ - - chip->eg_timer_add = (1<freqbase; - chip->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, chip->eg_timer_overflow);*/ -} - -INLINE void KEY_ON(OPLL_SLOT *SLOT, UINT32 key_set) -{ - if( !SLOT->key ) - { - /* do NOT restart Phase Generator (verified on real YM2413)*/ - /* phase -> Dump */ - SLOT->state = EG_DMP; - } - SLOT->key |= key_set; -} - -INLINE void KEY_OFF(OPLL_SLOT *SLOT, UINT32 key_clr) -{ - if( SLOT->key ) - { - SLOT->key &= key_clr; - - if( !SLOT->key ) - { - /* phase -> Release */ - if (SLOT->state>EG_REL) - SLOT->state = EG_REL; - } - } -} - -/* update phase increment counter of operator (also update the EG rates if necessary) */ -INLINE void CALC_FCSLOT(OPLL_CH *CH,OPLL_SLOT *SLOT) -{ - int ksr; - UINT32 SLOT_rs; - UINT32 SLOT_dp; - - /* (frequency) phase increment counter */ - SLOT->freq = CH->fc * SLOT->mul; - ksr = CH->kcode >> SLOT->KSR; - - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - - /* calculate envelope generator rates */ - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; - - } - - if (CH->sus) - SLOT_rs = 16 + (5<<2); - else - SLOT_rs = 16 + (7<<2); - - SLOT->eg_sh_rs = eg_rate_shift [SLOT_rs + SLOT->ksr ]; - SLOT->eg_sel_rs = eg_rate_select[SLOT_rs + SLOT->ksr ]; - - SLOT_dp = 16 + (13<<2); - SLOT->eg_sh_dp = eg_rate_shift [SLOT_dp + SLOT->ksr ]; - SLOT->eg_sel_dp = eg_rate_select[SLOT_dp + SLOT->ksr ]; -} - -/* set multi,am,vib,EG-TYP,KSR,mul */ -INLINE void set_mul(YM2413 *chip,int slot,int v) -{ - OPLL_CH *CH = &chip->P_CH[slot/2]; - OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->mul = mul_tab[v&0x0f]; - SLOT->KSR = (v&0x10) ? 0 : 2; - SLOT->eg_type = (v&0x20); - SLOT->vib = (v&0x40); - SLOT->AMmask = (v&0x80) ? ~0 : 0; - CALC_FCSLOT(CH,SLOT); -} - -/* set ksl, tl */ -INLINE void set_ksl_tl(YM2413 *chip,int chan,int v) -{ - int ksl; - OPLL_CH *CH = &chip->P_CH[chan]; -/* modulator */ - OPLL_SLOT *SLOT = &CH->SLOT[SLOT1]; - - ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ - - SLOT->ksl = ksl ? 3-ksl : 31; - SLOT->TL = (v&0x3f)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); -} - -/* set ksl , waveforms, feedback */ -INLINE void set_ksl_wave_fb(YM2413 *chip,int chan,int v) -{ - int ksl; - OPLL_CH *CH = &chip->P_CH[chan]; -/* modulator */ - OPLL_SLOT *SLOT = &CH->SLOT[SLOT1]; - SLOT->wavetable = ((v&0x08)>>3)*SIN_LEN; - SLOT->fb_shift = (v&7) ? (v&7) + 8 : 0; - -/*carrier*/ - SLOT = &CH->SLOT[SLOT2]; - ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ - - SLOT->ksl = ksl ? 3-ksl : 31; - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); - - SLOT->wavetable = ((v&0x10)>>4)*SIN_LEN; -} - -/* set attack rate & decay rate */ -INLINE void set_ar_dr(YM2413 *chip,int slot,int v) -{ - OPLL_CH *CH = &chip->P_CH[slot/2]; - OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; - - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - - SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; -} - -/* set sustain level & release rate */ -INLINE void set_sl_rr(YM2413 *chip,int slot,int v) -{ - OPLL_CH *CH = &chip->P_CH[slot/2]; - OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->sl = sl_tab[ v>>4 ]; - - SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; -} - -static void load_instrument(YM2413 *chip, UINT32 chan, UINT32 slot, UINT8* inst ) -{ - set_mul (chip, slot, inst[0]); - set_mul (chip, slot+1, inst[1]); - set_ksl_tl (chip, chan, inst[2]); - set_ksl_wave_fb (chip, chan, inst[3]); - set_ar_dr (chip, slot, inst[4]); - set_ar_dr (chip, slot+1, inst[5]); - set_sl_rr (chip, slot, inst[6]); - set_sl_rr (chip, slot+1, inst[7]); -} -static void update_instrument_zero(YM2413 *chip, UINT8 r ) -{ - UINT8* inst = &chip->inst_tab[0][0]; /* point to user instrument */ - UINT32 chan; - UINT32 chan_max; - - chan_max = 9; - if (chip->rhythm & 0x20) - chan_max=6; - - switch(r) - { - case 0: - for (chan=0; chaninstvol_r[chan]&0xf0)==0) - { - set_mul (chip, chan*2, inst[0]); - } - } - break; - case 1: - for (chan=0; chaninstvol_r[chan]&0xf0)==0) - { - set_mul (chip, chan*2+1,inst[1]); - } - } - break; - case 2: - for (chan=0; chaninstvol_r[chan]&0xf0)==0) - { - set_ksl_tl (chip, chan, inst[2]); - } - } - break; - case 3: - for (chan=0; chaninstvol_r[chan]&0xf0)==0) - { - set_ksl_wave_fb (chip, chan, inst[3]); - } - } - break; - case 4: - for (chan=0; chaninstvol_r[chan]&0xf0)==0) - { - set_ar_dr (chip, chan*2, inst[4]); - } - } - break; - case 5: - for (chan=0; chaninstvol_r[chan]&0xf0)==0) - { - set_ar_dr (chip, chan*2+1,inst[5]); - } - } - break; - case 6: - for (chan=0; chaninstvol_r[chan]&0xf0)==0) - { - set_sl_rr (chip, chan*2, inst[6]); - } - } - break; - case 7: - for (chan=0; chaninstvol_r[chan]&0xf0)==0) - { - set_sl_rr (chip, chan*2+1,inst[7]); - } - } - break; - } -} - -/* write a value v to register r on chip chip */ -static void OPLLWriteReg(YM2413 *chip, int r, int v) -{ - OPLL_CH *CH; - OPLL_SLOT *SLOT; - UINT8 *inst; - int chan; - int slot; - - /* adjust bus to 8 bits */ - r &= 0xff; - v &= 0xff; - - - switch(r&0xf0) - { - case 0x00: /* 00-0f:control */ - { - switch(r&0x0f) - { - case 0x00: /* AM/VIB/EGTYP/KSR/MULTI (modulator) */ - case 0x01: /* AM/VIB/EGTYP/KSR/MULTI (carrier) */ - case 0x02: /* Key Scale Level, Total Level (modulator) */ - case 0x03: /* Key Scale Level, carrier waveform, modulator waveform, Feedback */ - case 0x04: /* Attack, Decay (modulator) */ - case 0x05: /* Attack, Decay (carrier) */ - case 0x06: /* Sustain, Release (modulator) */ - case 0x07: /* Sustain, Release (carrier) */ - chip->inst_tab[0][r & 0x07] = v; - update_instrument_zero(chip,r&7); - break; - - case 0x0e: /* x, x, r,bd,sd,tom,tc,hh */ - { - if(v&0x20) - { - if ((chip->rhythm&0x20)==0) - /*rhythm off to on*/ - { - /*logerror("YM2413: Rhythm mode enable\n");*/ - - /* Load instrument settings for channel seven(chan=6 since we're zero based). (Bass drum) */ - chan = 6; - inst = &chip->inst_tab[16][0]; - slot = chan*2; - - load_instrument(chip, chan, slot, inst); - - /* Load instrument settings for channel eight. (High hat and snare drum) */ - chan = 7; - inst = &chip->inst_tab[17][0]; - slot = chan*2; - - load_instrument(chip, chan, slot, inst); - - CH = &chip->P_CH[chan]; - SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is HH */ - SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); - - /* Load instrument settings for channel nine. (Tom-tom and top cymbal) */ - chan = 8; - inst = &chip->inst_tab[18][0]; - slot = chan*2; - - load_instrument(chip, chan, slot, inst); - - CH = &chip->P_CH[chan]; - SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is TOM */ - SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); - } - /* BD key on/off */ - if(v&0x10) - { - KEY_ON (&chip->P_CH[6].SLOT[SLOT1], 2); - KEY_ON (&chip->P_CH[6].SLOT[SLOT2], 2); - } - else - { - KEY_OFF(&chip->P_CH[6].SLOT[SLOT1],~2); - KEY_OFF(&chip->P_CH[6].SLOT[SLOT2],~2); - } - /* HH key on/off */ - if(v&0x01) KEY_ON (&chip->P_CH[7].SLOT[SLOT1], 2); - else KEY_OFF(&chip->P_CH[7].SLOT[SLOT1],~2); - /* SD key on/off */ - if(v&0x08) KEY_ON (&chip->P_CH[7].SLOT[SLOT2], 2); - else KEY_OFF(&chip->P_CH[7].SLOT[SLOT2],~2); - /* TOM key on/off */ - if(v&0x04) KEY_ON (&chip->P_CH[8].SLOT[SLOT1], 2); - else KEY_OFF(&chip->P_CH[8].SLOT[SLOT1],~2); - /* TOP-CY key on/off */ - if(v&0x02) KEY_ON (&chip->P_CH[8].SLOT[SLOT2], 2); - else KEY_OFF(&chip->P_CH[8].SLOT[SLOT2],~2); - } - else - { - if ((chip->rhythm&0x20)==1) - /*rhythm on to off*/ - { - /*logerror("YM2413: Rhythm mode disable\n");*/ - /* Load instrument settings for channel seven(chan=6 since we're zero based).*/ - chan = 6; - inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; - slot = chan*2; - - load_instrument(chip, chan, slot, inst); - - /* Load instrument settings for channel eight.*/ - chan = 7; - inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; - slot = chan*2; - - load_instrument(chip, chan, slot, inst); - - /* Load instrument settings for channel nine.*/ - chan = 8; - inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; - slot = chan*2; - - load_instrument(chip, chan, slot, inst); - } - /* BD key off */ - KEY_OFF(&chip->P_CH[6].SLOT[SLOT1],~2); - KEY_OFF(&chip->P_CH[6].SLOT[SLOT2],~2); - /* HH key off */ - KEY_OFF(&chip->P_CH[7].SLOT[SLOT1],~2); - /* SD key off */ - KEY_OFF(&chip->P_CH[7].SLOT[SLOT2],~2); - /* TOM key off */ - KEY_OFF(&chip->P_CH[8].SLOT[SLOT1],~2); - /* TOP-CY off */ - KEY_OFF(&chip->P_CH[8].SLOT[SLOT2],~2); - } - chip->rhythm = v&0x3f; - } - break; - } - } - break; - - case 0x10: - case 0x20: - { - UINT32 block_fnum; - - chan = r&0x0f; - - if (chan >= 9) - chan -= 9; /* verified on real YM2413 */ - - CH = &chip->P_CH[chan]; - - if(r&0x10) - { /* 10-18: FNUM 0-7 */ - block_fnum = (CH->block_fnum&0x0f00) | v; - } - else - { /* 20-28: suson, keyon, block, FNUM 8 */ - block_fnum = ((v&0x0f)<<8) | (CH->block_fnum&0xff); - - if(v&0x10) - { - KEY_ON (&CH->SLOT[SLOT1], 1); - KEY_ON (&CH->SLOT[SLOT2], 1); - } - else - { - KEY_OFF(&CH->SLOT[SLOT1],~1); - KEY_OFF(&CH->SLOT[SLOT2],~1); - } - - - /*if (CH->sus!=(v&0x20)) - logerror("chan=%i sus=%2x\n",chan,v&0x20);*/ - - CH->sus = v & 0x20; - } - /* update */ - if(CH->block_fnum != block_fnum) - { - UINT8 block; - - CH->block_fnum = block_fnum; - - /* BLK 2,1,0 bits -> bits 3,2,1 of kcode, FNUM MSB -> kcode LSB */ - CH->kcode = (block_fnum&0x0f00)>>8; - - CH->ksl_base = ksl_tab[block_fnum>>5]; - - block_fnum = block_fnum * 2; - block = (block_fnum&0x1c00) >> 10; - CH->fc = chip->fn_tab[block_fnum&0x03ff] >> (7-block); - - /* refresh Total Level in both SLOTs of this channel */ - CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); - CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); - - /* refresh frequency counter in both SLOTs of this channel */ - CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); - CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); - } - } - break; - - case 0x30: /* inst 4 MSBs, VOL 4 LSBs */ - { - UINT8 old_instvol; - - chan = r&0x0f; - - if (chan >= 9) - chan -= 9; /* verified on real YM2413 */ - - old_instvol = chip->instvol_r[chan]; - chip->instvol_r[chan] = v; /* store for later use */ - - CH = &chip->P_CH[chan]; - SLOT = &CH->SLOT[SLOT2]; /* carrier */ - SLOT->TL = ((v&0x0f)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); - - - /*check wether we are in rhythm mode and handle instrument/volume register accordingly*/ - if ((chan>=6) && (chip->rhythm&0x20)) - { - /* we're in rhythm mode*/ - - if (chan>=7) /* only for channel 7 and 8 (channel 6 is handled in usual way)*/ - { - SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is HH(chan=7) or TOM(chan=8) */ - SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); - } - } - else - { - if ( (old_instvol&0xf0) == (v&0xf0) ) - return; - - inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; - slot = chan*2; - - load_instrument(chip, chan, slot, inst); - - #if 0 - logerror("YM2413: chan#%02i inst=%02i: (r=%2x, v=%2x)\n",chan,v>>4,r,v); - logerror(" 0:%2x 1:%2x\n",inst[0],inst[1]); logerror(" 2:%2x 3:%2x\n",inst[2],inst[3]); - logerror(" 4:%2x 5:%2x\n",inst[4],inst[5]); logerror(" 6:%2x 7:%2x\n",inst[6],inst[7]); - #endif - } - } - break; - - default: - break; - } -} - -/* lock/unlock for common table */ -static void OPLLResetChip(YM2413 *chip) -{ - int c,s; - int i; - - chip->eg_timer = 0; - chip->eg_cnt = 0; - - chip->noise_rng = 1; /* noise shift register */ - - chip->mask = 0; - - /* setup instruments table */ - if (!chip->chip_type) - { - for (i=0; i<19; i++) - { - for (c=0; c<8; c++) - { - chip->inst_tab[i][c] = table[i][c]; - } - } - } - else - { - memset( &chip->inst_tab, 0, sizeof(chip->inst_tab) ); - - for (i=0; i<15; i++) - { - for (c=0; c<8; c++) - { - chip->inst_tab[i+1][c] = table_vrc7[i][c]; - } - } - } - - - /* reset with register write */ - OPLLWriteReg(chip,0x0f,0); /*test reg*/ - for(i = 0x3f ; i >= 0x10 ; i-- ) OPLLWriteReg(chip,i,0x00); - - /* reset operator parameters */ - for( c = 0 ; c < 9 ; c++ ) - { - OPLL_CH *CH = &chip->P_CH[c]; - for(s = 0 ; s < 2 ; s++ ) - { - /* wave table */ - CH->SLOT[s].wavetable = 0; - CH->SLOT[s].state = EG_OFF; - CH->SLOT[s].volume = MAX_ATT_INDEX; - } - } -} - -/* Create one of virtual YM2413 */ -/* 'clock' is chip clock in Hz */ -/* 'rate' is sampling rate */ -static YM2413 *OPLLCreate(int clock, int rate, int type) -{ - char *ptr; - YM2413 *chip; - int state_size; - - init_tables(); - - /* calculate chip state size */ - state_size = sizeof(YM2413); - - /* allocate memory block */ - ptr = (char *)malloc(state_size); - - if (ptr==NULL) - return NULL; - - /* clear */ - memset(ptr,0,state_size); - - chip = (YM2413 *)ptr; - - chip->clock = clock; - chip->rate = rate; - - chip->chip_type = type; - - chip->mask = 0; - - /* init global tables */ - OPLL_initalize(chip); - - /* reset chip */ - OPLLResetChip(chip); - return chip; -} - -/* Destroy one of virtual YM3812 */ -static void OPLLDestroy(YM2413 *chip) -{ - free(chip); -} - -/* Option handlers */ - -static void OPLLSetUpdateHandler(YM2413 *chip,OPLL_UPDATEHANDLER UpdateHandler,void * param) -{ - chip->UpdateHandler = UpdateHandler; - chip->UpdateParam = param; -} - -/* YM3812 I/O interface */ -static void OPLLWrite(YM2413 *chip,int a,int v) -{ - if( !(a&1) ) - { /* address port */ - chip->address = v & 0xff; - } - else - { /* data port */ - if(chip->UpdateHandler) chip->UpdateHandler(chip->UpdateParam,0); - OPLLWriteReg(chip,chip->address,v); - } -} - -static unsigned char OPLLRead(YM2413 *chip,int a) -{ - if( !(a&1) ) - { - /* status port */ - return chip->status; - } - return 0xff; -} - - - - - -void * ym2413_init(int clock, int rate, int type) -{ - /* emulator create */ - return OPLLCreate(clock, rate, type); -} - -void ym2413_shutdown(void *chip) -{ - YM2413 *OPLL = (YM2413 *)chip; - - /* emulator shutdown */ - OPLLDestroy(OPLL); -} - -void ym2413_reset_chip(void *chip) -{ - YM2413 *OPLL = (YM2413 *)chip; - OPLLResetChip(OPLL); -} - -void ym2413_write(void *chip, int a, int v) -{ - YM2413 *OPLL = (YM2413 *)chip; - OPLLWrite(OPLL, a, v); -} - -unsigned char ym2413_read(void *chip, int a) -{ - YM2413 *OPLL = (YM2413 *)chip; - return OPLLRead(OPLL, a) & 0x03 ; -} - -void ym2413_set_update_handler(void *chip,OPLL_UPDATEHANDLER UpdateHandler,void *param) -{ - YM2413 *OPLL = (YM2413 *)chip; - OPLLSetUpdateHandler(OPLL, UpdateHandler, param); -} - - -/* -** Generate samples for one of the YM2413's -** -** 'which' is the virtual YM2413 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void ym2413_update_one(void *_chip, SAMP **buffers, int length) -{ - YM2413 *chip = (YM2413 *)_chip; - UINT8 rhythm = chip->rhythm&0x20; - SAMP *bufMO = buffers[0]; - SAMP *bufRO = buffers[1]; - - int i,j; - - chip->SLOT7_1 = &chip->P_CH[7].SLOT[SLOT1]; - chip->SLOT7_2 = &chip->P_CH[7].SLOT[SLOT2]; - chip->SLOT8_1 = &chip->P_CH[8].SLOT[SLOT1]; - chip->SLOT8_2 = &chip->P_CH[8].SLOT[SLOT2]; - - - for( i=0; i < length ; i++ ) - { - int mo,ro; - - chip->output[0] = 0; - chip->output[1] = 0; - - advance_lfo(chip); - -#if 0 - /* FM part */ - chan_calc(chip,&chip->P_CH[0]); -/* SAVE_SEPARATE_CHANNEL(0); */ - chan_calc(chip,&chip->P_CH[1]); - chan_calc(chip,&chip->P_CH[2]); - chan_calc(chip,&chip->P_CH[3]); - chan_calc(chip,&chip->P_CH[4]); - chan_calc(chip,&chip->P_CH[5]); -#else - for ( j=0; j < 6; j++ ) - { - if (!(chip->mask & OPLL_MASK_CH(j))) chan_calc(chip, &chip->P_CH[j]); - } -#endif - - if(!rhythm) - { -#if 0 - chan_calc(chip,&chip->P_CH[6]); - chan_calc(chip,&chip->P_CH[7]); - chan_calc(chip,&chip->P_CH[8]); -#else - for ( j=6; j < 9; j++ ) - { - if (!(chip->mask & OPLL_MASK_CH(j))) chan_calc(chip, &chip->P_CH[j]); - } -#endif - } - else /* Rhythm part */ - { - if ( ( chip->mask & OPLL_MASK_RHYTHM ) != OPLL_MASK_RHYTHM ) - rhythm_calc(chip,&chip->P_CH[0], (chip->noise_rng>>0)&1 ); - } - - mo = chip->output[0]; - ro = chip->output[1]; - - mo >>= FINAL_SH; - ro >>= FINAL_SH; - - /* limit check */ - mo = limit( mo , MAXOUT, MINOUT ); - ro = limit( ro , MAXOUT, MINOUT ); - - /* store to sound buffer */ - bufMO[i] = mo; - bufRO[i] = ro; - - advance(chip); - } - -} - -void ym2413_advance_lfo(void *_chip) -{ - YM2413 *chip = (YM2413 *)_chip; - advance_lfo(chip); -} - -void ym2413_advance(void *_chip) -{ - YM2413 *chip = (YM2413 *)_chip; - advance(chip); -} - -SAMP ym2413_calcch(void *_chip, int ch) -{ - YM2413 *chip = (YM2413 *)_chip; - - int output; - - chip->output[0] = 0; - chip->output[1] = 0; - - if (ch >= 0 && ch < 6) chan_calc( chip, &chip->P_CH[ch] ); - else if (ch >= 6 && ch < 9) - { - UINT8 rhythm = chip->rhythm&0x20; - if (!rhythm) chan_calc( chip, &chip->P_CH[ch] ); - else if (ch == 6) rhythm_calc(chip,&chip->P_CH[0], (chip->noise_rng>>0)&1 ); - } - - output = chip->output[0]; - output += chip->output[1]; - - return output; -} - -void * ym2413_get_inst0(void *_chip) -{ - YM2413 *chip = (YM2413 *)_chip; - - return &chip->inst_tab; -} - -void ym2413_set_mask(void *_chip, UINT32 mask) -{ - YM2413 *chip = (YM2413 *)_chip; - - chip->mask = mask; -} +/* +** +** File: ym2413.c - software implementation of YM2413 +** FM sound generator type OPLL +** +** Copyright Jarek Burczynski +** +** Version 1.0 +** + + Features as listed in LSI-212413A2 data sheet: + 1. FM Sound Generator for real sound creation. + 2. Two Selectable modes: 9 simultaneous sounds or 6 melody sounds plus 5 rhythm sounds + (different tones can be used together in either case). + 3. Built-in Instruments data (15 melody tones, 5 rhythm tones, "CAPTAIN and TELETEXT applicalbe tones). + 4. Built-in DA Converter. + 5. Built-in Quartz Oscillator. + 6. Built-in Vibrato Oscillator/AM Oscillator + 7. TTL Compatible Input. + 8. Si-Gate NMOS LSI + 9. A single 5V power source. + +to do: + +- make sure of the sinus amplitude bits + +- make sure of the EG resolution bits (looks like the biggest + modulation index generated by the modulator is 123, 124 = no modulation) +- find proper algorithm for attack phase of EG + +- tune up instruments ROM + +- support sample replay in test mode (it is NOT as simple as setting bit 0 + in register 0x0f and using register 0x10 for sample data). + Which games use this feature ? + + +*/ + +#define _USE_MATH_DEFINES +#include +#include +#include +#include "mamedef.h" +#include "ym2413.h" + +#ifndef INLINE +#define INLINE static __inline +#endif +#ifndef logerror +#define logerror (void) +#endif + +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif + +/* output final shift */ +#if (SAMPLE_BITS==16) + #define FINAL_SH (0) + #define MAXOUT (+32767) + #define MINOUT (-32768) +#else + #define FINAL_SH (8) + #define MAXOUT (+127) + #define MINOUT (-128) +#endif + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ + +#define FREQ_MASK ((1<>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 phase; /* frequency counter */ + UINT32 freq; /* frequency counter step */ + UINT8 fb_shift; /* feedback shift value */ + INT32 op1_out[2]; /* slot1 output for feedback */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/nonpercussive mode*/ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + + UINT8 eg_sh_dp; /* (dump state) */ + UINT8 eg_sel_dp; /* (dump state) */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT8 eg_sh_rr; /* (release state for non-perc.)*/ + UINT8 eg_sel_rr; /* (release state for non-perc.)*/ + UINT8 eg_sh_rs; /* (release state for perc.mode)*/ + UINT8 eg_sel_rs; /* (release state for perc.mode)*/ + + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + unsigned int wavetable; +} OPLL_SLOT; + +#define OPLL_MASK_CH(x) (1<<(x)) +#define OPLL_MASK_HH (1<<(9)) +#define OPLL_MASK_CYM (1<<(10)) +#define OPLL_MASK_TOM (1<<(11)) +#define OPLL_MASK_SD (1<<(12)) +#define OPLL_MASK_BD (1<<(13)) +#define OPLL_MASK_RHYTHM ( OPLL_MASK_HH | OPLL_MASK_CYM | OPLL_MASK_TOM | OPLL_MASK_SD | OPLL_MASK_BD ) + +typedef struct{ + OPLL_SLOT SLOT[2]; + /* phase generator state */ + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. freqement base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ + UINT8 sus; /* sus on/off (release speed in percussive mode)*/ +} OPLL_CH; + +/* chip state */ +typedef struct { + OPLL_CH P_CH[9]; /* OPLL chips have 9 channels*/ + UINT8 instvol_r[9]; /* instrument/volume (or volume/volume in percussive mode)*/ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT8 rhythm; /* Rhythm mode */ + + /* LFO */ + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + +/* instrument settings */ +/* + 0-user instrument + 1-15 - fixed instruments + 16 -bass drum settings + 17,18 - other percussion instruments +*/ + UINT8 inst_tab[19][8]; + + /* external event callback handlers */ + OPLL_UPDATEHANDLER UpdateHandler; /* stream update handler */ + void * UpdateParam; /* stream update parameter */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + + /* work table */ + OPLL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2; + + signed int output[2]; + + UINT32 LFO_AM; + INT32 LFO_PM; + + int chip_type; + UINT32 mask; +} YM2413; + +/* key scale level */ +/* table is 3dB/octave, DV converts this into 6dB/octave */ +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define DV (0.1875/1.0) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + /* OCT 1 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, + 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, + /* OCT 2 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, + 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, + 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, + /* OCT 3 */ + 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, + 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, + 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, + 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, + /* OCT 4 */ + 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, + 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, + 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, + 10.875/DV,11.250/DV,11.625/DV,12.000/DV, + /* OCT 5 */ + 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, + 9.000/DV,10.125/DV,10.875/DV,11.625/DV, + 12.000/DV,12.750/DV,13.125/DV,13.500/DV, + 13.875/DV,14.250/DV,14.625/DV,15.000/DV, + /* OCT 6 */ + 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, + 12.000/DV,13.125/DV,13.875/DV,14.625/DV, + 15.000/DV,15.750/DV,16.125/DV,16.500/DV, + 16.875/DV,17.250/DV,17.625/DV,18.000/DV, + /* OCT 7 */ + 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, + 15.000/DV,16.125/DV,16.875/DV,17.625/DV, + 18.000/DV,18.750/DV,19.125/DV,19.500/DV, + 19.875/DV,20.250/DV,20.625/DV,21.000/DV +}; +#undef DV + +/* sustain level table (3dB per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,45 (dB)*/ +#define SC(db) (UINT32) ( db * (1.0/ENV_STEP) ) +static const UINT32 sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(15) +}; +#undef SC + + +#define RATE_STEPS (8) +static const unsigned char eg_inc[15*RATE_STEPS]={ + +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ +/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ +/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(13) in this table - it's directly in the code */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), + +/* rates 00-12 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 13 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 14 */ +O( 8),O( 9),O(10),O(11), + +/* rate 15 */ +O(12),O(12),O(12),O(12), + +/* 16 dummy rates (same as 15 3) */ +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ +/*shift 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0 */ +/*mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0 */ + +#define O(a) (a*1) +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-12 */ +O(13),O(13),O(13),O(13), +O(12),O(12),O(12),O(12), +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 16 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), + +}; +#undef O + + +/* multiple table */ +#define ML 2 +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML, + 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML +}; +#undef ML + +/* TL_TAB_LEN is calculated as: +* 11 - sinus amplitude bits (Y axis) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +#define TL_TAB_LEN (11*2*TL_RES_LEN) +static signed int tl_tab[TL_TAB_LEN]; + +#define ENV_QUIET (TL_TAB_LEN>>5) + +/* sin waveform table in 'decibel' scale */ +/* two waveforms on OPLL type chips */ +static unsigned int sin_tab[SIN_LEN * 2]; + + +/* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples + + Length: 210 elements. + + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. + +We use data>>1, until we find what it really is on real chip... + +*/ + +#define LFO_AM_TAB_ELEMENTS 210 + +static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +0,0,0,0,0,0,0, +1,1,1,1, +2,2,2,2, +3,3,3,3, +4,4,4,4, +5,5,5,5, +6,6,6,6, +7,7,7,7, +8,8,8,8, +9,9,9,9, +10,10,10,10, +11,11,11,11, +12,12,12,12, +13,13,13,13, +14,14,14,14, +15,15,15,15, +16,16,16,16, +17,17,17,17, +18,18,18,18, +19,19,19,19, +20,20,20,20, +21,21,21,21, +22,22,22,22, +23,23,23,23, +24,24,24,24, +25,25,25,25, +26,26,26, +25,25,25,25, +24,24,24,24, +23,23,23,23, +22,22,22,22, +21,21,21,21, +20,20,20,20, +19,19,19,19, +18,18,18,18, +17,17,17,17, +16,16,16,16, +15,15,15,15, +14,14,14,14, +13,13,13,13, +12,12,12,12, +11,11,11,11, +10,10,10,10, +9,9,9,9, +8,8,8,8, +7,7,7,7, +6,6,6,6, +5,5,5,5, +4,4,4,4, +3,3,3,3, +2,2,2,2, +1,1,1,1 +}; + +/* LFO Phase Modulation table (verified on real YM2413) */ +static const INT8 lfo_pm_table[8*8] = { + +/* FNUM2/FNUM = 0 00xxxxxx (0x0000) */ +0, 0, 0, 0, 0, 0, 0, 0, + +/* FNUM2/FNUM = 0 01xxxxxx (0x0040) */ +1, 0, 0, 0,-1, 0, 0, 0, + +/* FNUM2/FNUM = 0 10xxxxxx (0x0080) */ +2, 1, 0,-1,-2,-1, 0, 1, + +/* FNUM2/FNUM = 0 11xxxxxx (0x00C0) */ +3, 1, 0,-1,-3,-1, 0, 1, + +/* FNUM2/FNUM = 1 00xxxxxx (0x0100) */ +4, 2, 0,-2,-4,-2, 0, 2, + +/* FNUM2/FNUM = 1 01xxxxxx (0x0140) */ +5, 2, 0,-2,-5,-2, 0, 2, + +/* FNUM2/FNUM = 1 10xxxxxx (0x0180) */ +6, 3, 0,-3,-6,-3, 0, 3, + +/* FNUM2/FNUM = 1 11xxxxxx (0x01C0) */ +7, 3, 0,-3,-7,-3, 0, 3, +}; + + + + + + +/* This is not 100% perfect yet but very close */ +/* + - multi parameters are 100% correct (instruments and drums) + - LFO PM and AM enable are 100% correct + - waveform DC and DM select are 100% correct +*/ + +static const unsigned char table[19][8] = { +/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */ +/* 0 1 2 3 4 5 6 7 */ + {0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, /* 0 */ + + {0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, /* 1 */ + {0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13 }, /* 2 */ + {0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23 }, /* 3 */ + {0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27 }, /* 4 */ + +/* {0x22, 0x21, 0x1e, 0x09, 0xf0, 0x76, 0x08, 0x28 }, //5 */ + {0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18 }, /* 5 */ + +/* {0x31, 0x22, 0x16, 0x09, 0x90, 0x7f, 0x00, 0x08 }, //6 */ + {0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13 }, /* 6 */ + + {0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17 }, /* 7 */ + {0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07 }, /* 8 */ + {0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, /* 9 */ + +/* {0x61, 0x61, 0x0c, 0x08, 0x85, 0xa0, 0x79, 0x07 }, //A */ + {0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07 }, /* A */ + + {0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22 }, /* B */ + {0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12 }, /* C */ + +/* {0x61, 0x10, 0x0c, 0x08, 0xf2, 0xc4, 0x40, 0xc8 }, //D */ + {0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44 }, /* D */ + + {0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3 }, /* E */ + {0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13 }, /* F */ + +/* drum instruments definitions */ +/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */ +/* 0 1 2 3 4 5 6 7 */ + {0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */ + {0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */ + {0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */ +}; + +static const unsigned char table_vrc7[15][8] = +{ +/* VRC7 instruments, January 17, 2004 update -Xodnizel */ + {0x03, 0x21, 0x04, 0x06, 0x8D, 0xF2, 0x42, 0x17}, + {0x13, 0x41, 0x05, 0x0E, 0x99, 0x96, 0x63, 0x12}, + {0x31, 0x11, 0x10, 0x0A, 0xF0, 0x9C, 0x32, 0x02}, + {0x21, 0x61, 0x1D, 0x07, 0x9F, 0x64, 0x20, 0x27}, + {0x22, 0x21, 0x1E, 0x06, 0xF0, 0x76, 0x08, 0x28}, + {0x02, 0x01, 0x06, 0x00, 0xF0, 0xF2, 0x03, 0x95}, + {0x21, 0x61, 0x1C, 0x07, 0x82, 0x81, 0x16, 0x07}, + {0x23, 0x21, 0x1A, 0x17, 0xEF, 0x82, 0x25, 0x15}, + {0x25, 0x11, 0x1F, 0x00, 0x86, 0x41, 0x20, 0x11}, + {0x85, 0x01, 0x1F, 0x0F, 0xE4, 0xA2, 0x11, 0x12}, + {0x07, 0xC1, 0x2B, 0x45, 0xB4, 0xF1, 0x24, 0xF4}, + {0x61, 0x23, 0x11, 0x06, 0x96, 0x96, 0x13, 0x16}, + {0x01, 0x02, 0xD3, 0x05, 0x82, 0xA2, 0x31, 0x51}, + {0x61, 0x22, 0x0D, 0x02, 0xC3, 0x7F, 0x24, 0x05}, + {0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x44, 0x17}, + +}; + +INLINE int limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + + +/* advance LFO to next sample */ +INLINE void advance_lfo(YM2413 *chip) +{ + /* LFO */ + chip->lfo_am_cnt += chip->lfo_am_inc; + if (chip->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<LFO_AM = lfo_am_table[ chip->lfo_am_cnt >> LFO_SH ] >> 1; + + chip->lfo_pm_cnt += chip->lfo_pm_inc; + chip->LFO_PM = (chip->lfo_pm_cnt>>LFO_SH) & 7; +} + +/* advance to next sample */ +INLINE void advance(YM2413 *chip) +{ + OPLL_CH *CH; + OPLL_SLOT *op; + unsigned int i; + + /* Envelope Generator */ + chip->eg_timer += chip->eg_timer_add; + + while (chip->eg_timer >= chip->eg_timer_overflow) + { + chip->eg_timer -= chip->eg_timer_overflow; + + chip->eg_cnt++; + + for (i=0; i<9*2; i++) + { + CH = &chip->P_CH[i/2]; + + op = &CH->SLOT[i&1]; + + switch(op->state) + { + + case EG_DMP: /* dump phase */ + /*dump phase is performed by both operators in each channel*/ + /*when CARRIER envelope gets down to zero level, + ** phases in BOTH opearators are reset (at the same time ?) + */ + if ( !(chip->eg_cnt & ((1<eg_sh_dp)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dp + ((chip->eg_cnt>>op->eg_sh_dp)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_ATT; + /* restart Phase Generator */ + op->phase = 0; + } + } + break; + + case EG_ATT: /* attack phase */ + if ( !(chip->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((chip->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>2; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + } + break; + + case EG_DEC: /* decay phase */ + if ( !(chip->eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((chip->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= (INT32)(op->sl) ) + op->state = EG_SUS; + } + break; + + case EG_SUS: /* sustain phase */ + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode (sustained tone) */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ + if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ + /* exclude modulators in melody channels from performing anything in this mode*/ + /* allowed are only carriers in melody mode and rhythm slots in rhythm mode */ + + /*This table shows which operators and on what conditions are allowed to perform EG_REL: + (a) - always perform EG_REL + (n) - never perform EG_REL + (r) - perform EG_REL in Rhythm mode ONLY + 0: 0 (n), 1 (a) + 1: 2 (n), 3 (a) + 2: 4 (n), 5 (a) + 3: 6 (n), 7 (a) + 4: 8 (n), 9 (a) + 5: 10(n), 11(a) + 6: 12(r), 13(a) + 7: 14(r), 15(a) + 8: 16(r), 17(a) + */ + if ( (i&1) || ((chip->rhythm&0x20) && (i>=12)) )/* exclude modulators */ + { + if(op->eg_type) /* non-percussive mode (sustained tone) */ + /*this is correct: use RR when SUS = OFF*/ + /*and use RS when SUS = ON*/ + { + if (CH->sus) + { + if ( !(chip->eg_cnt & ((1<eg_sh_rs)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rs + ((chip->eg_cnt>>op->eg_sh_rs)&7)]; + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + } + } + else + { + if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + } + } + } + else /* percussive mode */ + { + if ( !(chip->eg_cnt & ((1<eg_sh_rs)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rs + ((chip->eg_cnt>>op->eg_sh_rs)&7)]; + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + } + } + } + break; + + default: + break; + } + } + } + + for (i=0; i<9*2; i++) + { + CH = &chip->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Phase Generator */ + if(op->vib) + { + UINT8 block; + + unsigned int fnum_lfo = 8*((CH->block_fnum&0x01c0) >> 6); + unsigned int block_fnum = CH->block_fnum * 2; + signed int lfo_fn_table_index_offset = lfo_pm_table[chip->LFO_PM + fnum_lfo ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + block_fnum += lfo_fn_table_index_offset; + block = (block_fnum&0x1c00) >> 10; + op->phase += (chip->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; + } + else /* LFO phase modulation = zero */ + { + op->phase += op->freq; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->phase += op->freq; + } + } + + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. + * + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 + * + * Simply use bit 22 as the noise output. + */ + + chip->noise_p += chip->noise_f; + i = chip->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + chip->noise_p &= FREQ_MASK; + while (i) + { + /* + UINT32 j; + j = ( (chip->noise_rng) ^ (chip->noise_rng>>14) ^ (chip->noise_rng>>15) ^ (chip->noise_rng>>22) ) & 1; + chip->noise_rng = (j<<22) | (chip->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (chip->noise_rng & 1) chip->noise_rng ^= 0x800302; + chip->noise_rng >>= 1; + + i--; + } +} + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<5) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<17))) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + INT32 i; + + i = (phase & ~FREQ_MASK) + pm; + +/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/ + + p = (env<<5) + sin_tab[ wave_tab + ((i>>FREQ_SH) & SIN_MASK)]; + +/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (chip->LFO_AM & (OP)->AMmask)) + +/* calculate output */ +INLINE void chan_calc( YM2413 *chip, OPLL_CH *CH ) +{ + OPLL_SLOT *SLOT; + unsigned int env; + signed int out; + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + + SLOT->op1_out[0] = SLOT->op1_out[1]; + phase_modulation = SLOT->op1_out[0]; + + SLOT->op1_out[1] = 0; + + if( env < ENV_QUIET ) + { + if (!SLOT->fb_shift) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->phase, env, (out<fb_shift), SLOT->wavetable ); + } + + /* SLOT 2 */ + + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + { + signed int outp = op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable); + chip->output[0] += outp; + /* output[0] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable); */ + } +} + +/* + operators used in the rhythm sounds generation process: + + Envelope Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal + 6 / 0 12 50 70 90 f0 + + 6 / 1 15 53 73 93 f3 + + 7 / 0 13 51 71 91 f1 + + 7 / 1 16 54 74 94 f4 + + 8 / 0 14 52 72 92 f2 + + 8 / 1 17 55 75 95 f5 + + + Phase Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number MULTIPLE Drum Hat Drum Tom Cymbal + 6 / 0 12 30 + + 6 / 1 15 33 + + 7 / 0 13 31 + + + + 7 / 1 16 34 ----- n o t u s e d ----- + 8 / 0 14 32 + + 8 / 1 17 35 + + + +channel operator register number Bass High Snare Tom Top +number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal + 6 12,15 B6 A6 + + + 7 13,16 B7 A7 + + + + + 8 14,17 B8 A8 + + + + +*/ + +/* calculate rhythm */ + +INLINE void rhythm_calc( YM2413 *chip, OPLL_CH *CH, unsigned int noise ) +{ + OPLL_SLOT *SLOT; + signed int out; + unsigned int env; + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + + + /* Bass Drum (verified on real YM3812): + - depends on the channel 6 'connect' register: + when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) + when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored + - output sample always is multiplied by 2 + */ + + + /* SLOT 1 */ + if ( !(chip->mask & OPLL_MASK_BD) ) + { + SLOT = &CH[6].SLOT[SLOT1]; + env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + phase_modulation = SLOT->op1_out[0]; + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->fb_shift) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->phase, env, (out<fb_shift), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + chip->output[1] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable) * 2; + } + + + /* Phase generation is based on: + HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) + SD (16) channel 7->slot 1 + TOM (14) channel 8->slot 1 + TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ + + /* Envelope generation based on: + HH channel 7->slot1 + SD channel 7->slot2 + TOM channel 8->slot1 + TOP channel 8->slot2 */ + + + /* The following formulas can be well optimized. + I leave them in direct form for now (in case I've missed something). + */ + + /* High Hat (verified on real YM3812) */ + if ( !(chip->mask & OPLL_MASK_HH) ) + { + env = volume_calc(chip->SLOT7_1); + if( env < ENV_QUIET ) + { + + /* high hat phase generation: + phase = d0 or 234 (based on frequency only) + phase = 34 or 2d0 (based on noise) + */ + + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((chip->SLOT7_1->phase>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((chip->SLOT7_1->phase>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((chip->SLOT7_1->phase>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0xd0; */ + /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ + UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((chip->SLOT8_2->phase>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((chip->SLOT8_2->phase>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e | bit5e); + + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ + if (res2) + phase = (0x200|(0xd0>>2)); + + + /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ + /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ + if (phase&0x200) + { + if (noise) + phase = 0x200|0xd0; + } + else + /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ + /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ + { + if (noise) + phase = 0xd0>>2; + } + + chip->output[1] += op_calc(phase<SLOT7_1->wavetable) * 2; + } + } + + /* Snare Drum (verified on real YM3812) */ + if ( !(chip->mask & OPLL_MASK_SD) ) + { + env = volume_calc(chip->SLOT7_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit8 = ((chip->SLOT7_1->phase>>FREQ_SH)>>8)&1; + + /* when bit8 = 0 phase = 0x100; */ + /* when bit8 = 1 phase = 0x200; */ + UINT32 phase = bit8 ? 0x200 : 0x100; + + /* Noise bit XOR'es phase by 0x100 */ + /* when noisebit = 0 pass the phase from calculation above */ + /* when noisebit = 1 phase ^= 0x100; */ + /* in other words: phase ^= (noisebit<<8); */ + if (noise) + phase ^= 0x100; + + chip->output[1] += op_calc(phase<SLOT7_2->wavetable) * 2; + } + } + + /* Tom Tom (verified on real YM3812) */ + if ( !(chip->mask & OPLL_MASK_TOM) ) + { + env = volume_calc(chip->SLOT8_1); + if( env < ENV_QUIET ) + chip->output[1] += op_calc(chip->SLOT8_1->phase, env, 0, chip->SLOT8_1->wavetable) * 2; + } + + /* Top Cymbal (verified on real YM2413) */ + if ( !(chip->mask & OPLL_MASK_CYM) ) + { + env = volume_calc(chip->SLOT8_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((chip->SLOT7_1->phase>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((chip->SLOT7_1->phase>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((chip->SLOT7_1->phase>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0x100; */ + /* when res1 = 1 phase = 0x200 | 0x100; */ + UINT32 phase = res1 ? 0x300 : 0x100; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((chip->SLOT8_2->phase>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((chip->SLOT8_2->phase>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e | bit5e); + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | 0x100; */ + if (res2) + phase = 0x300; + + chip->output[1] += op_calc(phase<SLOT8_2->wavetable) * 2; + } + } +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<11; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<11; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); + logerror("\n"); + #endif + } + /*logerror("ym2413.c: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + /* waveform 0: standard sinus */ + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + + /*logerror("ym2413.c: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ + + + /* waveform 1: __ __ */ + /* / \____/ \____*/ + /* output only first half of the sinus waveform (positive one) */ + if (i & (1<<(SIN_BITS-1)) ) + sin_tab[1*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[1*SIN_LEN+i] = sin_tab[i]; + + /*logerror("ym2413.c: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] );*/ + } +#if 0 + logerror("YM2413.C: ENV_QUIET= %08x (*32=%08x)\n", ENV_QUIET, ENV_QUIET*32 ); + for (i=0; ifreqbase = (chip->rate) ? ((double)chip->clock / 72.0) / chip->rate : 0; + if ( fabs( chip->freqbase - 1.0 ) < 0.0000001 ) + chip->freqbase = 1.0; +#if 0 + chip->rate = (double)chip->clock / 72.0; + chip->freqbase = 1.0; + logerror("freqbase=%f\n", chip->freqbase); +#endif + + + + /* make fnumber -> increment counter table */ + for( i = 0 ; i < 1024; i++ ) + { + /* OPLL (YM2413) phase increment counter = 18bit */ + + chip->fn_tab[i] = (UINT32)( (double)i * 64 * chip->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("ym2413.c: fn_tab[%4i] = %08x (dec=%8i)\n", + i, chip->fn_tab[i]>>6, chip->fn_tab[i]>>6 ); +#endif + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("ym2413.c: sl_tab[%i] = %08x\n", i, sl_tab[i] ); + } + for( i=0 ; i < 8 ; i++ ) + { + int j; + logerror("ym2413.c: ksl_tab[oct=%2i] =",i); + for (j=0; j<16; j++) + { + logerror("%08x ", ksl_tab[i*16+j] ); + } + logerror("\n"); + } +#endif + + + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ + chip->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + chip->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; + + /*logerror ("chip->lfo_am_inc = %8x ; chip->lfo_pm_inc = %8x\n", chip->lfo_am_inc, chip->lfo_pm_inc);*/ + + /* Noise generator: a step takes 1 sample */ + chip->noise_f = (1.0 / 1.0) * (1<freqbase; + /*logerror("YM2413init noise_f=%8x\n", chip->noise_f);*/ + + chip->eg_timer_add = (1<freqbase; + chip->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, chip->eg_timer_overflow);*/ +} + +INLINE void KEY_ON(OPLL_SLOT *SLOT, UINT32 key_set) +{ + if( !SLOT->key ) + { + /* do NOT restart Phase Generator (verified on real YM2413)*/ + /* phase -> Dump */ + SLOT->state = EG_DMP; + } + SLOT->key |= key_set; +} + +INLINE void KEY_OFF(OPLL_SLOT *SLOT, UINT32 key_clr) +{ + if( SLOT->key ) + { + SLOT->key &= key_clr; + + if( !SLOT->key ) + { + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } + } +} + +/* update phase increment counter of operator (also update the EG rates if necessary) */ +INLINE void CALC_FCSLOT(OPLL_CH *CH,OPLL_SLOT *SLOT) +{ + int ksr; + UINT32 SLOT_rs; + UINT32 SLOT_dp; + + /* (frequency) phase increment counter */ + SLOT->freq = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + + } + + if (CH->sus) + SLOT_rs = 16 + (5<<2); + else + SLOT_rs = 16 + (7<<2); + + SLOT->eg_sh_rs = eg_rate_shift [SLOT_rs + SLOT->ksr ]; + SLOT->eg_sel_rs = eg_rate_select[SLOT_rs + SLOT->ksr ]; + + SLOT_dp = 16 + (13<<2); + SLOT->eg_sh_dp = eg_rate_shift [SLOT_dp + SLOT->ksr ]; + SLOT->eg_sel_dp = eg_rate_select[SLOT_dp + SLOT->ksr ]; +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(YM2413 *chip,int slot,int v) +{ + OPLL_CH *CH = &chip->P_CH[slot/2]; + OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = mul_tab[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_type = (v&0x20); + SLOT->vib = (v&0x40); + SLOT->AMmask = (v&0x80) ? ~0 : 0; + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl, tl */ +INLINE void set_ksl_tl(YM2413 *chip,int chan,int v) +{ + int ksl; + OPLL_CH *CH = &chip->P_CH[chan]; +/* modulator */ + OPLL_SLOT *SLOT = &CH->SLOT[SLOT1]; + + ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TL = (v&0x3f)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set ksl , waveforms, feedback */ +INLINE void set_ksl_wave_fb(YM2413 *chip,int chan,int v) +{ + int ksl; + OPLL_CH *CH = &chip->P_CH[chan]; +/* modulator */ + OPLL_SLOT *SLOT = &CH->SLOT[SLOT1]; + SLOT->wavetable = ((v&0x08)>>3)*SIN_LEN; + SLOT->fb_shift = (v&7) ? (v&7) + 8 : 0; + +/*carrier*/ + SLOT = &CH->SLOT[SLOT2]; + ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + + SLOT->wavetable = ((v&0x10)>>4)*SIN_LEN; +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(YM2413 *chip,int slot,int v) +{ + OPLL_CH *CH = &chip->P_CH[slot/2]; + OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; + + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(YM2413 *chip,int slot,int v) +{ + OPLL_CH *CH = &chip->P_CH[slot/2]; + OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->sl = sl_tab[ v>>4 ]; + + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +} + +static void load_instrument(YM2413 *chip, UINT32 chan, UINT32 slot, UINT8* inst ) +{ + set_mul (chip, slot, inst[0]); + set_mul (chip, slot+1, inst[1]); + set_ksl_tl (chip, chan, inst[2]); + set_ksl_wave_fb (chip, chan, inst[3]); + set_ar_dr (chip, slot, inst[4]); + set_ar_dr (chip, slot+1, inst[5]); + set_sl_rr (chip, slot, inst[6]); + set_sl_rr (chip, slot+1, inst[7]); +} +static void update_instrument_zero(YM2413 *chip, UINT8 r ) +{ + UINT8* inst = &chip->inst_tab[0][0]; /* point to user instrument */ + UINT32 chan; + UINT32 chan_max; + + chan_max = 9; + if (chip->rhythm & 0x20) + chan_max=6; + + switch(r) + { + case 0: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_mul (chip, chan*2, inst[0]); + } + } + break; + case 1: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_mul (chip, chan*2+1,inst[1]); + } + } + break; + case 2: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_ksl_tl (chip, chan, inst[2]); + } + } + break; + case 3: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_ksl_wave_fb (chip, chan, inst[3]); + } + } + break; + case 4: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_ar_dr (chip, chan*2, inst[4]); + } + } + break; + case 5: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_ar_dr (chip, chan*2+1,inst[5]); + } + } + break; + case 6: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_sl_rr (chip, chan*2, inst[6]); + } + } + break; + case 7: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_sl_rr (chip, chan*2+1,inst[7]); + } + } + break; + } +} + +/* write a value v to register r on chip chip */ +static void OPLLWriteReg(YM2413 *chip, int r, int v) +{ + OPLL_CH *CH; + OPLL_SLOT *SLOT; + UINT8 *inst; + int chan; + int slot; + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + + + switch(r&0xf0) + { + case 0x00: /* 00-0f:control */ + { + switch(r&0x0f) + { + case 0x00: /* AM/VIB/EGTYP/KSR/MULTI (modulator) */ + case 0x01: /* AM/VIB/EGTYP/KSR/MULTI (carrier) */ + case 0x02: /* Key Scale Level, Total Level (modulator) */ + case 0x03: /* Key Scale Level, carrier waveform, modulator waveform, Feedback */ + case 0x04: /* Attack, Decay (modulator) */ + case 0x05: /* Attack, Decay (carrier) */ + case 0x06: /* Sustain, Release (modulator) */ + case 0x07: /* Sustain, Release (carrier) */ + chip->inst_tab[0][r & 0x07] = v; + update_instrument_zero(chip,r&7); + break; + + case 0x0e: /* x, x, r,bd,sd,tom,tc,hh */ + { + if(v&0x20) + { + if ((chip->rhythm&0x20)==0) + /*rhythm off to on*/ + { + /*logerror("YM2413: Rhythm mode enable\n");*/ + + /* Load instrument settings for channel seven(chan=6 since we're zero based). (Bass drum) */ + chan = 6; + inst = &chip->inst_tab[16][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + /* Load instrument settings for channel eight. (High hat and snare drum) */ + chan = 7; + inst = &chip->inst_tab[17][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + CH = &chip->P_CH[chan]; + SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is HH */ + SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + + /* Load instrument settings for channel nine. (Tom-tom and top cymbal) */ + chan = 8; + inst = &chip->inst_tab[18][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + CH = &chip->P_CH[chan]; + SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is TOM */ + SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + /* BD key on/off */ + if(v&0x10) + { + KEY_ON (&chip->P_CH[6].SLOT[SLOT1], 2); + KEY_ON (&chip->P_CH[6].SLOT[SLOT2], 2); + } + else + { + KEY_OFF(&chip->P_CH[6].SLOT[SLOT1],~2); + KEY_OFF(&chip->P_CH[6].SLOT[SLOT2],~2); + } + /* HH key on/off */ + if(v&0x01) KEY_ON (&chip->P_CH[7].SLOT[SLOT1], 2); + else KEY_OFF(&chip->P_CH[7].SLOT[SLOT1],~2); + /* SD key on/off */ + if(v&0x08) KEY_ON (&chip->P_CH[7].SLOT[SLOT2], 2); + else KEY_OFF(&chip->P_CH[7].SLOT[SLOT2],~2); + /* TOM key on/off */ + if(v&0x04) KEY_ON (&chip->P_CH[8].SLOT[SLOT1], 2); + else KEY_OFF(&chip->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY key on/off */ + if(v&0x02) KEY_ON (&chip->P_CH[8].SLOT[SLOT2], 2); + else KEY_OFF(&chip->P_CH[8].SLOT[SLOT2],~2); + } + else + { + if ((chip->rhythm&0x20)==1) + /*rhythm on to off*/ + { + /*logerror("YM2413: Rhythm mode disable\n");*/ + /* Load instrument settings for channel seven(chan=6 since we're zero based).*/ + chan = 6; + inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + /* Load instrument settings for channel eight.*/ + chan = 7; + inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + /* Load instrument settings for channel nine.*/ + chan = 8; + inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + } + /* BD key off */ + KEY_OFF(&chip->P_CH[6].SLOT[SLOT1],~2); + KEY_OFF(&chip->P_CH[6].SLOT[SLOT2],~2); + /* HH key off */ + KEY_OFF(&chip->P_CH[7].SLOT[SLOT1],~2); + /* SD key off */ + KEY_OFF(&chip->P_CH[7].SLOT[SLOT2],~2); + /* TOM key off */ + KEY_OFF(&chip->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY off */ + KEY_OFF(&chip->P_CH[8].SLOT[SLOT2],~2); + } + chip->rhythm = v&0x3f; + } + break; + } + } + break; + + case 0x10: + case 0x20: + { + UINT32 block_fnum; + + chan = r&0x0f; + + if (chan >= 9) + chan -= 9; /* verified on real YM2413 */ + + CH = &chip->P_CH[chan]; + + if(r&0x10) + { /* 10-18: FNUM 0-7 */ + block_fnum = (CH->block_fnum&0x0f00) | v; + } + else + { /* 20-28: suson, keyon, block, FNUM 8 */ + block_fnum = ((v&0x0f)<<8) | (CH->block_fnum&0xff); + + if(v&0x10) + { + KEY_ON (&CH->SLOT[SLOT1], 1); + KEY_ON (&CH->SLOT[SLOT2], 1); + } + else + { + KEY_OFF(&CH->SLOT[SLOT1],~1); + KEY_OFF(&CH->SLOT[SLOT2],~1); + } + + + /*if (CH->sus!=(v&0x20)) + logerror("chan=%i sus=%2x\n",chan,v&0x20);*/ + + CH->sus = v & 0x20; + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block; + + CH->block_fnum = block_fnum; + + /* BLK 2,1,0 bits -> bits 3,2,1 of kcode, FNUM MSB -> kcode LSB */ + CH->kcode = (block_fnum&0x0f00)>>8; + + CH->ksl_base = ksl_tab[block_fnum>>5]; + + block_fnum = block_fnum * 2; + block = (block_fnum&0x1c00) >> 10; + CH->fc = chip->fn_tab[block_fnum&0x03ff] >> (7-block); + + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + } + break; + + case 0x30: /* inst 4 MSBs, VOL 4 LSBs */ + { + UINT8 old_instvol; + + chan = r&0x0f; + + if (chan >= 9) + chan -= 9; /* verified on real YM2413 */ + + old_instvol = chip->instvol_r[chan]; + chip->instvol_r[chan] = v; /* store for later use */ + + CH = &chip->P_CH[chan]; + SLOT = &CH->SLOT[SLOT2]; /* carrier */ + SLOT->TL = ((v&0x0f)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + + + /*check wether we are in rhythm mode and handle instrument/volume register accordingly*/ + if ((chan>=6) && (chip->rhythm&0x20)) + { + /* we're in rhythm mode*/ + + if (chan>=7) /* only for channel 7 and 8 (channel 6 is handled in usual way)*/ + { + SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is HH(chan=7) or TOM(chan=8) */ + SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + } + else + { + if ( (old_instvol&0xf0) == (v&0xf0) ) + return; + + inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + #if 0 + logerror("YM2413: chan#%02i inst=%02i: (r=%2x, v=%2x)\n",chan,v>>4,r,v); + logerror(" 0:%2x 1:%2x\n",inst[0],inst[1]); logerror(" 2:%2x 3:%2x\n",inst[2],inst[3]); + logerror(" 4:%2x 5:%2x\n",inst[4],inst[5]); logerror(" 6:%2x 7:%2x\n",inst[6],inst[7]); + #endif + } + } + break; + + default: + break; + } +} + +/* lock/unlock for common table */ +static void OPLLResetChip(YM2413 *chip) +{ + int c,s; + int i; + + chip->eg_timer = 0; + chip->eg_cnt = 0; + + chip->noise_rng = 1; /* noise shift register */ + + chip->mask = 0; + + /* setup instruments table */ + if (!chip->chip_type) + { + for (i=0; i<19; i++) + { + for (c=0; c<8; c++) + { + chip->inst_tab[i][c] = table[i][c]; + } + } + } + else + { + memset( &chip->inst_tab, 0, sizeof(chip->inst_tab) ); + + for (i=0; i<15; i++) + { + for (c=0; c<8; c++) + { + chip->inst_tab[i+1][c] = table_vrc7[i][c]; + } + } + } + + + /* reset with register write */ + OPLLWriteReg(chip,0x0f,0); /*test reg*/ + for(i = 0x3f ; i >= 0x10 ; i-- ) OPLLWriteReg(chip,i,0x00); + + /* reset operator parameters */ + for( c = 0 ; c < 9 ; c++ ) + { + OPLL_CH *CH = &chip->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = 0; + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +} + +/* Create one of virtual YM2413 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static YM2413 *OPLLCreate(int clock, int rate, int type) +{ + char *ptr; + YM2413 *chip; + int state_size; + + init_tables(); + + /* calculate chip state size */ + state_size = sizeof(YM2413); + + /* allocate memory block */ + ptr = (char *)malloc(state_size); + + if (ptr==NULL) + return NULL; + + /* clear */ + memset(ptr,0,state_size); + + chip = (YM2413 *)ptr; + + chip->clock = clock; + chip->rate = rate; + + chip->chip_type = type; + + chip->mask = 0; + + /* init global tables */ + OPLL_initalize(chip); + + /* reset chip */ + OPLLResetChip(chip); + return chip; +} + +/* Destroy one of virtual YM3812 */ +static void OPLLDestroy(YM2413 *chip) +{ + free(chip); +} + +/* Option handlers */ + +static void OPLLSetUpdateHandler(YM2413 *chip,OPLL_UPDATEHANDLER UpdateHandler,void * param) +{ + chip->UpdateHandler = UpdateHandler; + chip->UpdateParam = param; +} + +/* YM3812 I/O interface */ +static void OPLLWrite(YM2413 *chip,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + chip->address = v & 0xff; + } + else + { /* data port */ + if(chip->UpdateHandler) chip->UpdateHandler(chip->UpdateParam,0); + OPLLWriteReg(chip,chip->address,v); + } +} + +static unsigned char OPLLRead(YM2413 *chip,int a) +{ + if( !(a&1) ) + { + /* status port */ + return chip->status; + } + return 0xff; +} + + + + + +void * ym2413_init(int clock, int rate, int type) +{ + /* emulator create */ + return OPLLCreate(clock, rate, type); +} + +void ym2413_shutdown(void *chip) +{ + YM2413 *OPLL = (YM2413 *)chip; + + /* emulator shutdown */ + OPLLDestroy(OPLL); +} + +void ym2413_reset_chip(void *chip) +{ + YM2413 *OPLL = (YM2413 *)chip; + OPLLResetChip(OPLL); +} + +void ym2413_write(void *chip, int a, int v) +{ + YM2413 *OPLL = (YM2413 *)chip; + OPLLWrite(OPLL, a, v); +} + +unsigned char ym2413_read(void *chip, int a) +{ + YM2413 *OPLL = (YM2413 *)chip; + return OPLLRead(OPLL, a) & 0x03 ; +} + +void ym2413_set_update_handler(void *chip,OPLL_UPDATEHANDLER UpdateHandler,void *param) +{ + YM2413 *OPLL = (YM2413 *)chip; + OPLLSetUpdateHandler(OPLL, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM2413's +** +** 'which' is the virtual YM2413 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym2413_update_one(void *_chip, SAMP **buffers, int length) +{ + YM2413 *chip = (YM2413 *)_chip; + UINT8 rhythm = chip->rhythm&0x20; + SAMP *bufMO = buffers[0]; + SAMP *bufRO = buffers[1]; + + int i,j; + + chip->SLOT7_1 = &chip->P_CH[7].SLOT[SLOT1]; + chip->SLOT7_2 = &chip->P_CH[7].SLOT[SLOT2]; + chip->SLOT8_1 = &chip->P_CH[8].SLOT[SLOT1]; + chip->SLOT8_2 = &chip->P_CH[8].SLOT[SLOT2]; + + + for( i=0; i < length ; i++ ) + { + int mo,ro; + + chip->output[0] = 0; + chip->output[1] = 0; + + advance_lfo(chip); + +#if 0 + /* FM part */ + chan_calc(chip,&chip->P_CH[0]); +/* SAVE_SEPARATE_CHANNEL(0); */ + chan_calc(chip,&chip->P_CH[1]); + chan_calc(chip,&chip->P_CH[2]); + chan_calc(chip,&chip->P_CH[3]); + chan_calc(chip,&chip->P_CH[4]); + chan_calc(chip,&chip->P_CH[5]); +#else + for ( j=0; j < 6; j++ ) + { + if (!(chip->mask & OPLL_MASK_CH(j))) chan_calc(chip, &chip->P_CH[j]); + } +#endif + + if(!rhythm) + { +#if 0 + chan_calc(chip,&chip->P_CH[6]); + chan_calc(chip,&chip->P_CH[7]); + chan_calc(chip,&chip->P_CH[8]); +#else + for ( j=6; j < 9; j++ ) + { + if (!(chip->mask & OPLL_MASK_CH(j))) chan_calc(chip, &chip->P_CH[j]); + } +#endif + } + else /* Rhythm part */ + { + if ( ( chip->mask & OPLL_MASK_RHYTHM ) != OPLL_MASK_RHYTHM ) + rhythm_calc(chip,&chip->P_CH[0], (chip->noise_rng>>0)&1 ); + } + + mo = chip->output[0]; + ro = chip->output[1]; + + mo >>= FINAL_SH; + ro >>= FINAL_SH; + + /* limit check */ + mo = limit( mo , MAXOUT, MINOUT ); + ro = limit( ro , MAXOUT, MINOUT ); + + /* store to sound buffer */ + bufMO[i] = mo; + bufRO[i] = ro; + + advance(chip); + } + +} + +void ym2413_advance_lfo(void *_chip) +{ + YM2413 *chip = (YM2413 *)_chip; + advance_lfo(chip); +} + +void ym2413_advance(void *_chip) +{ + YM2413 *chip = (YM2413 *)_chip; + advance(chip); +} + +SAMP ym2413_calcch(void *_chip, int ch) +{ + YM2413 *chip = (YM2413 *)_chip; + + int output; + + chip->output[0] = 0; + chip->output[1] = 0; + + if (ch >= 0 && ch < 6) chan_calc( chip, &chip->P_CH[ch] ); + else if (ch >= 6 && ch < 9) + { + UINT8 rhythm = chip->rhythm&0x20; + if (!rhythm) chan_calc( chip, &chip->P_CH[ch] ); + else if (ch == 6) rhythm_calc(chip,&chip->P_CH[0], (chip->noise_rng>>0)&1 ); + } + + output = chip->output[0]; + output += chip->output[1]; + + return output; +} + +void * ym2413_get_inst0(void *_chip) +{ + YM2413 *chip = (YM2413 *)_chip; + + return &chip->inst_tab; +} + +void ym2413_set_mask(void *_chip, UINT32 mask) +{ + YM2413 *chip = (YM2413 *)_chip; + + chip->mask = mask; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2413_Emu.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2413_Emu.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2413_Emu.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2413_Emu.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,78 +1,78 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Ym2413_Emu.h" -#include "ym2413.h" - -Ym2413_Emu::Ym2413_Emu() { opll = 0; } - -Ym2413_Emu::~Ym2413_Emu() -{ - if ( opll ) ym2413_shutdown( opll ); -} - -int Ym2413_Emu::set_rate( int sample_rate, int clock_rate ) -{ - if ( opll ) - { - ym2413_shutdown( opll ); - opll = 0; - } - - opll = ym2413_init( clock_rate, sample_rate, 0 ); - if ( !opll ) - return 1; - - reset(); - return 0; -} - -void Ym2413_Emu::reset() -{ - ym2413_reset_chip( opll ); - ym2413_set_mask( opll, 0 ); -} - -static stream_sample_t* DUMMYBUF[0x02] = {(stream_sample_t*)NULL, (stream_sample_t*)NULL}; - -void Ym2413_Emu::write( int addr, int data ) -{ - ym2413_update_one( opll, DUMMYBUF, 0 ); - ym2413_write( opll, 0, addr ); - ym2413_write( opll, 1, data ); -} - -void Ym2413_Emu::mute_voices( int mask ) -{ - ym2413_set_mask( opll, mask ); -} - -void Ym2413_Emu::run( int pair_count, sample_t* out ) -{ - SAMP bufMO[ 1024 ]; - SAMP bufRO[ 1024 ]; - SAMP * buffers[2] = { bufMO, bufRO }; - - while (pair_count > 0) - { - int todo = pair_count; - if (todo > 1024) todo = 1024; - ym2413_update_one( opll, buffers, todo ); - - for (int i = 0; i < todo; i++) - { - int output_l, output_r; - int output = bufMO [i]; - output += bufRO [i]; - output *= 3; - output_l = output + out [0]; - output_r = output + out [1]; - if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); - if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); - out [0] = output_l; - out [1] = output_r; - out += 2; - } - - pair_count -= todo; - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Ym2413_Emu.h" +#include "ym2413.h" + +Ym2413_Emu::Ym2413_Emu() { opll = 0; } + +Ym2413_Emu::~Ym2413_Emu() +{ + if ( opll ) ym2413_shutdown( opll ); +} + +int Ym2413_Emu::set_rate( int sample_rate, int clock_rate ) +{ + if ( opll ) + { + ym2413_shutdown( opll ); + opll = 0; + } + + opll = ym2413_init( clock_rate, sample_rate, 0 ); + if ( !opll ) + return 1; + + reset(); + return 0; +} + +void Ym2413_Emu::reset() +{ + ym2413_reset_chip( opll ); + ym2413_set_mask( opll, 0 ); +} + +static stream_sample_t* DUMMYBUF[0x02] = {(stream_sample_t*)NULL, (stream_sample_t*)NULL}; + +void Ym2413_Emu::write( int addr, int data ) +{ + ym2413_update_one( opll, DUMMYBUF, 0 ); + ym2413_write( opll, 0, addr ); + ym2413_write( opll, 1, data ); +} + +void Ym2413_Emu::mute_voices( int mask ) +{ + ym2413_set_mask( opll, mask ); +} + +void Ym2413_Emu::run( int pair_count, sample_t* out ) +{ + SAMP bufMO[ 1024 ]; + SAMP bufRO[ 1024 ]; + SAMP * buffers[2] = { bufMO, bufRO }; + + while (pair_count > 0) + { + int todo = pair_count; + if (todo > 1024) todo = 1024; + ym2413_update_one( opll, buffers, todo ); + + for (int i = 0; i < todo; i++) + { + int output_l, output_r; + int output = bufMO [i]; + output += bufRO [i]; + output *= 3; + output_l = output + out [0]; + output_r = output + out [1]; + if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); + if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); + out [0] = output_l; + out [1] = output_r; + out += 2; + } + + pair_count -= todo; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2413_Emu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2413_Emu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2413_Emu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2413_Emu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,37 +1,37 @@ -// YM2413 FM sound chip emulator interface - -// Game_Music_Emu $vers -#ifndef YM2413_EMU_H -#define YM2413_EMU_H - -struct OPLL; - -class Ym2413_Emu { - void* opll; -public: - Ym2413_Emu(); - ~Ym2413_Emu(); - - static bool supported() { return true; } - - // Sets output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - int set_rate( int sample_rate, int clock_rate ); - - // Resets to power-up state - void reset(); - - // Mutes voice n if bit n (1 << n) of mask is set - enum { channel_count = 14 }; - void mute_voices( int mask ); - - // Writes data to addr - void write( int addr, int data ); - - // Runs and writes pair_count*2 samples to output - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif +// YM2413 FM sound chip emulator interface + +// Game_Music_Emu $vers +#ifndef YM2413_EMU_H +#define YM2413_EMU_H + +struct OPLL; + +class Ym2413_Emu { + void* opll; +public: + Ym2413_Emu(); + ~Ym2413_Emu(); + + static bool supported() { return true; } + + // Sets output sample rate and chip clock rates, in Hz. Returns non-zero + // if error. + int set_rate( int sample_rate, int clock_rate ); + + // Resets to power-up state + void reset(); + + // Mutes voice n if bit n (1 << n) of mask is set + enum { channel_count = 14 }; + void mute_voices( int mask ); + + // Writes data to addr + void write( int addr, int data ); + + // Runs and writes pair_count*2 samples to output + typedef short sample_t; + enum { out_chan_count = 2 }; // stereo + void run( int pair_count, sample_t* out ); +}; + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ym2413.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ym2413.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ym2413.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ym2413.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,50 +1,50 @@ -#pragma once - -#ifndef __YM2413_H__ -#define __YM2413_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/* select output bits size of output : 8 or 16 */ -#define SAMPLE_BITS 16 - -#include "mamedef.h" - -typedef stream_sample_t SAMP; -/* -#if (SAMPLE_BITS==16) -typedef INT16 SAMP; -#endif -#if (SAMPLE_BITS==8) -typedef INT8 SAMP; -#endif -*/ - - - -void *ym2413_init(int clock, int rate, int type); -void ym2413_shutdown(void *chip); -void ym2413_reset_chip(void *chip); -void ym2413_write(void *chip, int a, int v); -unsigned char ym2413_read(void *chip, int a); -void ym2413_update_one(void *chip, SAMP **buffers, int length); - -void ym2413_advance_lfo(void *chip); /* call this once */ -SAMP ym2413_calcch(void *chip, int ch); /* then call this for each channel */ -void ym2413_advance(void *chip); /* then call this */ - -void * ym2413_get_inst0(void *chip); - -void ym2413_set_mask(void *chip, UINT32 mask); - -typedef void (*OPLL_UPDATEHANDLER)(void *param,int min_interval_us); - -void ym2413_set_update_handler(void *chip, OPLL_UPDATEHANDLER UpdateHandler, void *param); - -#ifdef __cplusplus -} -#endif - -#endif /*__YM2413_H__*/ +#pragma once + +#ifndef __YM2413_H__ +#define __YM2413_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* select output bits size of output : 8 or 16 */ +#define SAMPLE_BITS 16 + +#include "mamedef.h" + +typedef stream_sample_t SAMP; +/* +#if (SAMPLE_BITS==16) +typedef INT16 SAMP; +#endif +#if (SAMPLE_BITS==8) +typedef INT8 SAMP; +#endif +*/ + + + +void *ym2413_init(int clock, int rate, int type); +void ym2413_shutdown(void *chip); +void ym2413_reset_chip(void *chip); +void ym2413_write(void *chip, int a, int v); +unsigned char ym2413_read(void *chip, int a); +void ym2413_update_one(void *chip, SAMP **buffers, int length); + +void ym2413_advance_lfo(void *chip); /* call this once */ +SAMP ym2413_calcch(void *chip, int ch); /* then call this for each channel */ +void ym2413_advance(void *chip); /* then call this */ + +void * ym2413_get_inst0(void *chip); + +void ym2413_set_mask(void *chip, UINT32 mask); + +typedef void (*OPLL_UPDATEHANDLER)(void *param,int min_interval_us); + +void ym2413_set_update_handler(void *chip, OPLL_UPDATEHANDLER UpdateHandler, void *param); + +#ifdef __cplusplus +} +#endif + +#endif /*__YM2413_H__*/ diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2612_Emu_MAME.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2612_Emu_MAME.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Ym2612_Emu_MAME.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Ym2612_Emu_MAME.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,87 +1,87 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Ym2612_Emu.h" -#include "fm.h" - -#include "blargg_errors.h" - -// Ym2612_Emu - -Ym2612_Emu::~Ym2612_Emu() -{ - if ( impl ) - ym2612_shutdown( impl ); -} - -const char* Ym2612_Emu::set_rate( double sample_rate, double clock_rate ) -{ - if ( impl ) - { - ym2612_shutdown( impl ); - impl = 0; - } - - if ( !clock_rate ) - clock_rate = sample_rate * 144.; - - impl = ym2612_init( (long) (clock_rate + 0.5), (long) (sample_rate + 0.5) ); - if ( !impl ) - return blargg_err_memory; - - return 0; -} - -void Ym2612_Emu::reset() -{ - ym2612_reset_chip( impl ); -} - -static stream_sample_t* DUMMYBUF[0x02] = {(stream_sample_t*)NULL, (stream_sample_t*)NULL}; - -void Ym2612_Emu::write0( int addr, int data ) -{ - ym2612_update_one( impl, DUMMYBUF, 0 ); - ym2612_write( impl, 0, addr ); - ym2612_write( impl, 1, data ); -} - -void Ym2612_Emu::write1( int addr, int data ) -{ - ym2612_update_one( impl, DUMMYBUF, 0 ); - ym2612_write( impl, 2, addr ); - ym2612_write( impl, 3, data ); -} - -void Ym2612_Emu::mute_voices( int mask ) -{ - ym2612_set_mutemask( impl, mask ); -} - -void Ym2612_Emu::run( int pair_count, sample_t* out ) -{ - stream_sample_t bufL[ 1024 ]; - stream_sample_t bufR[ 1024 ]; - stream_sample_t * buffers[2] = { bufL, bufR }; - - while (pair_count > 0) - { - int todo = pair_count; - if (todo > 1024) todo = 1024; - ym2612_update_one( impl, buffers, todo ); - - for (int i = 0; i < todo; i++) - { - int output_l = bufL [i]; - int output_r = bufR [i]; - output_l += out [0]; - output_r += out [1]; - if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); - if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); - out [0] = output_l; - out [1] = output_r; - out += 2; - } - - pair_count -= todo; - } -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Ym2612_Emu.h" +#include "fm.h" + +#include "blargg_errors.h" + +// Ym2612_Emu + +Ym2612_Emu::~Ym2612_Emu() +{ + if ( impl ) + ym2612_shutdown( impl ); +} + +const char* Ym2612_Emu::set_rate( double sample_rate, double clock_rate ) +{ + if ( impl ) + { + ym2612_shutdown( impl ); + impl = 0; + } + + if ( !clock_rate ) + clock_rate = sample_rate * 144.; + + impl = ym2612_init( (long) (clock_rate + 0.5), (long) (sample_rate + 0.5) ); + if ( !impl ) + return blargg_err_memory; + + return 0; +} + +void Ym2612_Emu::reset() +{ + ym2612_reset_chip( impl ); +} + +static stream_sample_t* DUMMYBUF[0x02] = {(stream_sample_t*)NULL, (stream_sample_t*)NULL}; + +void Ym2612_Emu::write0( int addr, int data ) +{ + ym2612_update_one( impl, DUMMYBUF, 0 ); + ym2612_write( impl, 0, addr ); + ym2612_write( impl, 1, data ); +} + +void Ym2612_Emu::write1( int addr, int data ) +{ + ym2612_update_one( impl, DUMMYBUF, 0 ); + ym2612_write( impl, 2, addr ); + ym2612_write( impl, 3, data ); +} + +void Ym2612_Emu::mute_voices( int mask ) +{ + ym2612_set_mutemask( impl, mask ); +} + +void Ym2612_Emu::run( int pair_count, sample_t* out ) +{ + stream_sample_t bufL[ 1024 ]; + stream_sample_t bufR[ 1024 ]; + stream_sample_t * buffers[2] = { bufL, bufR }; + + while (pair_count > 0) + { + int todo = pair_count; + if (todo > 1024) todo = 1024; + ym2612_update_one( impl, buffers, todo ); + + for (int i = 0; i < todo; i++) + { + int output_l = bufL [i]; + int output_r = bufR [i]; + output_l += out [0]; + output_r += out [1]; + if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 ); + if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 ); + out [0] = output_l; + out [1] = output_r; + out += 2; + } + + pair_count -= todo; + } +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ymdeltat.cpp kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ymdeltat.cpp --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ymdeltat.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ymdeltat.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,659 +1,659 @@ -/* -** -** File: ymdeltat.c -** -** YAMAHA DELTA-T adpcm sound emulation subroutine -** used by fmopl.c (Y8950) and fm.c (YM2608 and YM2610/B) -** -** Base program is YM2610 emulator by Hiromitsu Shioya. -** Written by Tatsuyuki Satoh -** Improvements by Jarek Burczynski (bujar at mame dot net) -** -** -** History: -** -** 03-08-2003 Jarek Burczynski: -** - fixed BRDY flag implementation. -** -** 24-07-2003 Jarek Burczynski, Frits Hilderink: -** - fixed delault value for control2 in YM_DELTAT_ADPCM_Reset -** -** 22-07-2003 Jarek Burczynski, Frits Hilderink: -** - fixed external memory support -** -** 15-06-2003 Jarek Burczynski: -** - implemented CPU -> AUDIO ADPCM synthesis (via writes to the ADPCM data reg $08) -** - implemented support for the Limit address register -** - supported two bits from the control register 2 ($01): RAM TYPE (x1 bit/x8 bit), ROM/RAM -** - implemented external memory access (read/write) via the ADPCM data reg reads/writes -** Thanks go to Frits Hilderink for the example code. -** -** 14-06-2003 Jarek Burczynski: -** - various fixes to enable proper support for status register flags: BSRDY, PCM BSY, ZERO -** - modified EOS handling -** -** 05-04-2003 Jarek Burczynski: -** - implemented partial support for external/processor memory on sample replay -** -** 01-12-2002 Jarek Burczynski: -** - fixed first missing sound in gigandes thanks to previous fix (interpolator) by ElSemi -** - renamed/removed some YM_DELTAT struct fields -** -** 28-12-2001 Acho A. Tang -** - added EOS status report on ADPCM playback. -** -** 05-08-2001 Jarek Burczynski: -** - now_step is initialized with 0 at the start of play. -** -** 12-06-2001 Jarek Burczynski: -** - corrected end of sample bug in YM_DELTAT_ADPCM_CALC. -** Checked on real YM2610 chip - address register is 24 bits wide. -** Thanks go to Stefan Jokisch (stefan.jokisch@gmx.de) for tracking down the problem. -** -** TO DO: -** Check size of the address register on the other chips.... -** -** Version 0.72 -** -** sound chips that have this unit: -** YM2608 OPNA -** YM2610/B OPNB -** Y8950 MSX AUDIO -** -*/ - -#include "ymdeltat.h" -#ifndef INLINE -#define INLINE __inline -#endif -#ifndef logerror -#define logerror (void) -#endif - -#define YM_DELTAT_DELTA_MAX (24576) -#define YM_DELTAT_DELTA_MIN (127) -#define YM_DELTAT_DELTA_DEF (127) - -#define YM_DELTAT_DECODE_RANGE 32768 -#define YM_DELTAT_DECODE_MIN (-(YM_DELTAT_DECODE_RANGE)) -#define YM_DELTAT_DECODE_MAX ((YM_DELTAT_DECODE_RANGE)-1) - - -/* Forecast to next Forecast (rate = *8) */ -/* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */ -static const INT32 ym_deltat_decode_tableB1[16] = { - 1, 3, 5, 7, 9, 11, 13, 15, - -1, -3, -5, -7, -9, -11, -13, -15, -}; -/* delta to next delta (rate= *64) */ -/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */ -static const INT32 ym_deltat_decode_tableB2[16] = { - 57, 57, 57, 57, 77, 102, 128, 153, - 57, 57, 57, 57, 77, 102, 128, 153 -}; - -#if 0 -void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT) -{ - logerror("BRDY_callback reached (flag set) !\n"); - - /* set BRDY bit in status register */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); -} -#endif - -UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT) -{ - UINT8 v = 0; - - /* external memory read */ - if ( (DELTAT->portstate & 0xe0)==0x20 ) - { - /* two dummy reads */ - if (DELTAT->memread) - { - DELTAT->now_addr = DELTAT->start << 1; - DELTAT->memread--; - return 0; - } - - - if ( DELTAT->now_addr != (DELTAT->end<<1) ) - { - v = DELTAT->memory[DELTAT->now_addr>>1]; - - /*logerror("YM Delta-T memory read $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/ - - DELTAT->now_addr+=2; /* two nibbles at a time */ - - /* reset BRDY bit in status register, which means we are reading the memory now */ - if(DELTAT->status_reset_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); - - /* setup a timer that will callback us in 10 master clock cycles for Y8950 - * in the callback set the BRDY flag to 1 , which means we have another data ready. - * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work. - */ - /* set BRDY bit in status register */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); - } - else - { - /* set EOS bit in status register */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_EOS_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); - } - } - - return v; -} - - -/* 0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */ -static const UINT8 dram_rightshift[4]={3,0,0,0}; - -/* DELTA-T ADPCM write register */ -void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v) -{ - if(r>=0x10) return; - DELTAT->reg[r] = v; /* stock data */ - - switch( r ) - { - case 0x00: -/* -START: - Accessing *external* memory is started when START bit (D7) is set to "1", so - you must set all conditions needed for recording/playback before starting. - If you access *CPU-managed* memory, recording/playback starts after - read/write of ADPCM data register $08. - -REC: - 0 = ADPCM synthesis (playback) - 1 = ADPCM analysis (record) - -MEMDATA: - 0 = processor (*CPU-managed*) memory (means: using register $08) - 1 = external memory (using start/end/limit registers to access memory: RAM or ROM) - - -SPOFF: - controls output pin that should disable the speaker while ADPCM analysis - -RESET and REPEAT only work with external memory. - - -some examples: -value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: - C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register - E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register - 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register - a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register - - 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 - 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 - -*/ - /* handle emulation mode */ - if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) - { - v |= 0x20; /* YM2610 always uses external memory and doesn't even have memory flag bit. */ - } - - DELTAT->portstate = v & (0x80|0x40|0x20|0x10|0x01); /* start, rec, memory mode, repeat flag copy, reset(bit0) */ - - if( DELTAT->portstate&0x80 )/* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */ - { - /* set PCM BUSY bit */ - DELTAT->PCM_BSY = 1; - - /* start ADPCM */ - DELTAT->now_step = 0; - DELTAT->acc = 0; - DELTAT->prev_acc = 0; - DELTAT->adpcml = 0; - DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; - DELTAT->now_data = 0; - - } - - if( DELTAT->portstate&0x20 ) /* do we access external memory? */ - { - DELTAT->now_addr = DELTAT->start << 1; - DELTAT->memread = 2; /* two dummy reads needed before accesing external memory via register $08*/ - - /* if yes, then let's check if ADPCM memory is mapped and big enough */ - if(DELTAT->memory == 0) - { - /*logerror("YM Delta-T ADPCM rom not mapped\n");*/ - DELTAT->portstate = 0x00; - DELTAT->PCM_BSY = 0; - } - else - { - if( DELTAT->end >= DELTAT->memory_size ) /* Check End in Range */ - { - /*logerror("YM Delta-T ADPCM end out of range: $%08x\n", DELTAT->end);*/ - DELTAT->end = DELTAT->memory_size - 1; - } - if( DELTAT->start >= DELTAT->memory_size ) /* Check Start in Range */ - { - /*logerror("YM Delta-T ADPCM start out of range: $%08x\n", DELTAT->start);*/ - DELTAT->portstate = 0x00; - DELTAT->PCM_BSY = 0; - } - } - } - else /* we access CPU memory (ADPCM data register $08) so we only reset now_addr here */ - { - DELTAT->now_addr = 0; - } - - if( DELTAT->portstate&0x01 ) - { - DELTAT->portstate = 0x00; - - /* clear PCM BUSY bit (in status register) */ - DELTAT->PCM_BSY = 0; - - /* set BRDY flag */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); - } - break; - case 0x01: /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */ - /* handle emulation mode */ - if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) - { - v |= 0x01; /* YM2610 always uses ROM as an external memory and doesn't tave ROM/RAM memory flag bit. */ - } - - DELTAT->pan = &DELTAT->output_pointer[(v>>6)&0x03]; - if ((DELTAT->control2 & 3) != (v & 3)) - { - /*0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */ - if (DELTAT->DRAMportshift != dram_rightshift[v&3]) - { - DELTAT->DRAMportshift = dram_rightshift[v&3]; - - /* final shift value depends on chip type and memory type selected: - 8 for YM2610 (ROM only), - 5 for ROM for Y8950 and YM2608, - 5 for x8bit DRAMs for Y8950 and YM2608, - 2 for x1bit DRAMs for Y8950 and YM2608. - */ - - /* refresh addresses */ - DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift); - DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift); - DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1; - DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift); - } - } - DELTAT->control2 = v; - break; - case 0x02: /* Start Address L */ - case 0x03: /* Start Address H */ - DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift); - /*logerror("DELTAT start: 02=%2x 03=%2x addr=%8x\n",DELTAT->reg[0x2], DELTAT->reg[0x3],DELTAT->start );*/ - break; - case 0x04: /* Stop Address L */ - case 0x05: /* Stop Address H */ - DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift); - DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1; - /*logerror("DELTAT end : 04=%2x 05=%2x addr=%8x\n",DELTAT->reg[0x4], DELTAT->reg[0x5],DELTAT->end );*/ - break; - case 0x06: /* Prescale L (ADPCM and Record frq) */ - case 0x07: /* Prescale H */ - break; - case 0x08: /* ADPCM data */ - -/* -some examples: -value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: - C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register - E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register - 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register - a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register - - 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 - 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 - -*/ - - /* external memory write */ - if ( (DELTAT->portstate & 0xe0)==0x60 ) - { - if (DELTAT->memread) - { - DELTAT->now_addr = DELTAT->start << 1; - DELTAT->memread = 0; - } - - /*logerror("YM Delta-T memory write $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/ - - if ( DELTAT->now_addr != (DELTAT->end<<1) ) - { - DELTAT->memory[DELTAT->now_addr>>1] = v; - DELTAT->now_addr+=2; /* two nibbles at a time */ - - /* reset BRDY bit in status register, which means we are processing the write */ - if(DELTAT->status_reset_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); - - /* setup a timer that will callback us in 10 master clock cycles for Y8950 - * in the callback set the BRDY flag to 1 , which means we have written the data. - * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work. - */ - /* set BRDY bit in status register */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); - - } - else - { - /* set EOS bit in status register */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_EOS_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); - } - - return; - } - - /* ADPCM synthesis from CPU */ - if ( (DELTAT->portstate & 0xe0)==0x80 ) - { - DELTAT->CPU_data = v; - - /* Reset BRDY bit in status register, which means we are full of data */ - if(DELTAT->status_reset_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); - return; - } - - break; - case 0x09: /* DELTA-N L (ADPCM Playback Prescaler) */ - case 0x0a: /* DELTA-N H */ - DELTAT->delta = (DELTAT->reg[0xa]*0x0100 | DELTAT->reg[0x9]); - DELTAT->step = (UINT32)( (double)(DELTAT->delta /* *(1<<(YM_DELTAT_SHIFT-16)) */ ) * (DELTAT->freqbase) ); - /*logerror("DELTAT deltan:09=%2x 0a=%2x\n",DELTAT->reg[0x9], DELTAT->reg[0xa]);*/ - break; - case 0x0b: /* Output level control (volume, linear) */ - { - INT32 oldvol = DELTAT->volume; - DELTAT->volume = (v&0xff) * (DELTAT->output_range/256) / YM_DELTAT_DECODE_RANGE; -/* v * ((1<<16)>>8) >> 15; -* thus: v * (1<<8) >> 15; -* thus: output_range must be (1 << (15+8)) at least -* v * ((1<<23)>>8) >> 15; -* v * (1<<15) >> 15; -*/ - /*logerror("DELTAT vol = %2x\n",v&0xff);*/ - if( oldvol != 0 ) - { - DELTAT->adpcml = (int)((double)DELTAT->adpcml / (double)oldvol * (double)DELTAT->volume); - } - } - break; - case 0x0c: /* Limit Address L */ - case 0x0d: /* Limit Address H */ - DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift); - /*logerror("DELTAT limit: 0c=%2x 0d=%2x addr=%8x\n",DELTAT->reg[0xc], DELTAT->reg[0xd],DELTAT->limit );*/ - break; - } -} - -void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode) -{ - DELTAT->now_addr = 0; - DELTAT->now_step = 0; - DELTAT->step = 0; - DELTAT->start = 0; - DELTAT->end = 0; - DELTAT->limit = ~0; /* this way YM2610 and Y8950 (both of which don't have limit address reg) will still work */ - DELTAT->volume = 0; - DELTAT->pan = &DELTAT->output_pointer[pan]; - DELTAT->acc = 0; - DELTAT->prev_acc = 0; - DELTAT->adpcmd = 127; - DELTAT->adpcml = 0; - DELTAT->emulation_mode = (UINT8)emulation_mode; - DELTAT->portstate = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x20 : 0; - DELTAT->control2 = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x01 : 0; /* default setting depends on the emulation mode. MSX demo called "facdemo_4" doesn't setup control2 register at all and still works */ - DELTAT->DRAMportshift = dram_rightshift[DELTAT->control2 & 3]; - - /* The flag mask register disables the BRDY after the reset, however - ** as soon as the mask is enabled the flag needs to be set. */ - - /* set BRDY bit in status register */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); -} - -#if 0 -void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs) -{ - int r; - - /* to keep adpcml */ - DELTAT->volume = 0; - /* update */ - for(r=1;r<16;r++) - YM_DELTAT_ADPCM_Write(DELTAT,r,regs[r]); - DELTAT->reg[0] = regs[0]; - - /* current rom data */ - if (DELTAT->memory) - DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1) ); - -} -void YM_DELTAT_savestate(const device_config *device,YM_DELTAT *DELTAT) -{ -#ifdef __STATE_H__ - state_save_register_device_item(device, 0, DELTAT->portstate); - state_save_register_device_item(device, 0, DELTAT->now_addr); - state_save_register_device_item(device, 0, DELTAT->now_step); - state_save_register_device_item(device, 0, DELTAT->acc); - state_save_register_device_item(device, 0, DELTAT->prev_acc); - state_save_register_device_item(device, 0, DELTAT->adpcmd); - state_save_register_device_item(device, 0, DELTAT->adpcml); -#endif -} -#endif - - -#define YM_DELTAT_Limit(val,max,min) \ -{ \ - if ( val > max ) val = max; \ - else if ( val < min ) val = min; \ -} - -INLINE void YM_DELTAT_synthesis_from_external_memory(YM_DELTAT *DELTAT) -{ - UINT32 step; - int data; - - DELTAT->now_step += DELTAT->step; - if ( DELTAT->now_step >= (1<now_step >> YM_DELTAT_SHIFT; - DELTAT->now_step &= (1<now_addr == (DELTAT->limit<<1) ) - DELTAT->now_addr = 0; - - if ( DELTAT->now_addr == (DELTAT->end<<1) ) { /* 12-06-2001 JB: corrected comparison. Was > instead of == */ - if( DELTAT->portstate&0x10 ){ - /* repeat start */ - DELTAT->now_addr = DELTAT->start<<1; - DELTAT->acc = 0; - DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; - DELTAT->prev_acc = 0; - }else{ - /* set EOS bit in status register */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_EOS_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); - - /* clear PCM BUSY bit (reflected in status register) */ - DELTAT->PCM_BSY = 0; - - DELTAT->portstate = 0; - DELTAT->adpcml = 0; - DELTAT->prev_acc = 0; - return; - } - } - - if( DELTAT->now_addr&1 ) data = DELTAT->now_data & 0x0f; - else - { - DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1)); - data = DELTAT->now_data >> 4; - } - - DELTAT->now_addr++; - /* 12-06-2001 JB: */ - /* YM2610 address register is 24 bits wide.*/ - /* The "+1" is there because we use 1 bit more for nibble calculations.*/ - /* WARNING: */ - /* Side effect: we should take the size of the mapped ROM into account */ - DELTAT->now_addr &= ( (1<<(24+1))-1); - - /* store accumulator value */ - DELTAT->prev_acc = DELTAT->acc; - - /* Forecast to next Forecast */ - DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8); - YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); - - /* delta to next delta */ - DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64; - YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN ); - - /* ElSemi: Fix interpolator. */ - /*DELTAT->prev_acc = prev_acc + ((DELTAT->acc - prev_acc) / 2 );*/ - - }while(--step); - - } - - /* ElSemi: Fix interpolator. */ - DELTAT->adpcml = DELTAT->prev_acc * (int)((1<now_step); - DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step); - DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume; - - /* output for work of output channels (outd[OPNxxxx])*/ - *(DELTAT->pan) += DELTAT->adpcml; -} - - - -INLINE void YM_DELTAT_synthesis_from_CPU_memory(YM_DELTAT *DELTAT) -{ - UINT32 step; - int data; - - DELTAT->now_step += DELTAT->step; - if ( DELTAT->now_step >= (1<now_step >> YM_DELTAT_SHIFT; - DELTAT->now_step &= (1<now_addr&1 ) - { - data = DELTAT->now_data & 0x0f; - - DELTAT->now_data = DELTAT->CPU_data; - - /* after we used CPU_data, we set BRDY bit in status register, - * which means we are ready to accept another byte of data */ - if(DELTAT->status_set_handler) - if(DELTAT->status_change_BRDY_bit) - (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); - } - else - { - data = DELTAT->now_data >> 4; - } - - DELTAT->now_addr++; - - /* store accumulator value */ - DELTAT->prev_acc = DELTAT->acc; - - /* Forecast to next Forecast */ - DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8); - YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); - - /* delta to next delta */ - DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64; - YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN ); - - - }while(--step); - - } - - /* ElSemi: Fix interpolator. */ - DELTAT->adpcml = DELTAT->prev_acc * (int)((1<now_step); - DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step); - DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume; - - /* output for work of output channels (outd[OPNxxxx])*/ - *(DELTAT->pan) += DELTAT->adpcml; -} - - - -/* ADPCM B (Delta-T control type) */ -void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT) -{ - -/* -some examples: -value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: - 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register - a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register - C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register - E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register - - 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 - 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 - -*/ - - if ( (DELTAT->portstate & 0xe0)==0xa0 ) - { - YM_DELTAT_synthesis_from_external_memory(DELTAT); - return; - } - - if ( (DELTAT->portstate & 0xe0)==0x80 ) - { - /* ADPCM synthesis from CPU-managed memory (from reg $08) */ - YM_DELTAT_synthesis_from_CPU_memory(DELTAT); /* change output based on data in ADPCM data reg ($08) */ - return; - } - -//todo: ADPCM analysis -// if ( (DELTAT->portstate & 0xe0)==0xc0 ) -// if ( (DELTAT->portstate & 0xe0)==0xe0 ) - - return; -} - +/* +** +** File: ymdeltat.c +** +** YAMAHA DELTA-T adpcm sound emulation subroutine +** used by fmopl.c (Y8950) and fm.c (YM2608 and YM2610/B) +** +** Base program is YM2610 emulator by Hiromitsu Shioya. +** Written by Tatsuyuki Satoh +** Improvements by Jarek Burczynski (bujar at mame dot net) +** +** +** History: +** +** 03-08-2003 Jarek Burczynski: +** - fixed BRDY flag implementation. +** +** 24-07-2003 Jarek Burczynski, Frits Hilderink: +** - fixed delault value for control2 in YM_DELTAT_ADPCM_Reset +** +** 22-07-2003 Jarek Burczynski, Frits Hilderink: +** - fixed external memory support +** +** 15-06-2003 Jarek Burczynski: +** - implemented CPU -> AUDIO ADPCM synthesis (via writes to the ADPCM data reg $08) +** - implemented support for the Limit address register +** - supported two bits from the control register 2 ($01): RAM TYPE (x1 bit/x8 bit), ROM/RAM +** - implemented external memory access (read/write) via the ADPCM data reg reads/writes +** Thanks go to Frits Hilderink for the example code. +** +** 14-06-2003 Jarek Burczynski: +** - various fixes to enable proper support for status register flags: BSRDY, PCM BSY, ZERO +** - modified EOS handling +** +** 05-04-2003 Jarek Burczynski: +** - implemented partial support for external/processor memory on sample replay +** +** 01-12-2002 Jarek Burczynski: +** - fixed first missing sound in gigandes thanks to previous fix (interpolator) by ElSemi +** - renamed/removed some YM_DELTAT struct fields +** +** 28-12-2001 Acho A. Tang +** - added EOS status report on ADPCM playback. +** +** 05-08-2001 Jarek Burczynski: +** - now_step is initialized with 0 at the start of play. +** +** 12-06-2001 Jarek Burczynski: +** - corrected end of sample bug in YM_DELTAT_ADPCM_CALC. +** Checked on real YM2610 chip - address register is 24 bits wide. +** Thanks go to Stefan Jokisch (stefan.jokisch@gmx.de) for tracking down the problem. +** +** TO DO: +** Check size of the address register on the other chips.... +** +** Version 0.72 +** +** sound chips that have this unit: +** YM2608 OPNA +** YM2610/B OPNB +** Y8950 MSX AUDIO +** +*/ + +#include "ymdeltat.h" +#ifndef INLINE +#define INLINE __inline +#endif +#ifndef logerror +#define logerror (void) +#endif + +#define YM_DELTAT_DELTA_MAX (24576) +#define YM_DELTAT_DELTA_MIN (127) +#define YM_DELTAT_DELTA_DEF (127) + +#define YM_DELTAT_DECODE_RANGE 32768 +#define YM_DELTAT_DECODE_MIN (-(YM_DELTAT_DECODE_RANGE)) +#define YM_DELTAT_DECODE_MAX ((YM_DELTAT_DECODE_RANGE)-1) + + +/* Forecast to next Forecast (rate = *8) */ +/* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */ +static const INT32 ym_deltat_decode_tableB1[16] = { + 1, 3, 5, 7, 9, 11, 13, 15, + -1, -3, -5, -7, -9, -11, -13, -15, +}; +/* delta to next delta (rate= *64) */ +/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */ +static const INT32 ym_deltat_decode_tableB2[16] = { + 57, 57, 57, 57, 77, 102, 128, 153, + 57, 57, 57, 57, 77, 102, 128, 153 +}; + +#if 0 +void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT) +{ + logerror("BRDY_callback reached (flag set) !\n"); + + /* set BRDY bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); +} +#endif + +UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT) +{ + UINT8 v = 0; + + /* external memory read */ + if ( (DELTAT->portstate & 0xe0)==0x20 ) + { + /* two dummy reads */ + if (DELTAT->memread) + { + DELTAT->now_addr = DELTAT->start << 1; + DELTAT->memread--; + return 0; + } + + + if ( DELTAT->now_addr != (DELTAT->end<<1) ) + { + v = DELTAT->memory[DELTAT->now_addr>>1]; + + /*logerror("YM Delta-T memory read $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/ + + DELTAT->now_addr+=2; /* two nibbles at a time */ + + /* reset BRDY bit in status register, which means we are reading the memory now */ + if(DELTAT->status_reset_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + + /* setup a timer that will callback us in 10 master clock cycles for Y8950 + * in the callback set the BRDY flag to 1 , which means we have another data ready. + * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work. + */ + /* set BRDY bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + } + else + { + /* set EOS bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_EOS_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); + } + } + + return v; +} + + +/* 0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */ +static const UINT8 dram_rightshift[4]={3,0,0,0}; + +/* DELTA-T ADPCM write register */ +void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v) +{ + if(r>=0x10) return; + DELTAT->reg[r] = v; /* stock data */ + + switch( r ) + { + case 0x00: +/* +START: + Accessing *external* memory is started when START bit (D7) is set to "1", so + you must set all conditions needed for recording/playback before starting. + If you access *CPU-managed* memory, recording/playback starts after + read/write of ADPCM data register $08. + +REC: + 0 = ADPCM synthesis (playback) + 1 = ADPCM analysis (record) + +MEMDATA: + 0 = processor (*CPU-managed*) memory (means: using register $08) + 1 = external memory (using start/end/limit registers to access memory: RAM or ROM) + + +SPOFF: + controls output pin that should disable the speaker while ADPCM analysis + +RESET and REPEAT only work with external memory. + + +some examples: +value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: + C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register + E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register + 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register + a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register + + 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 + 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 + +*/ + /* handle emulation mode */ + if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) + { + v |= 0x20; /* YM2610 always uses external memory and doesn't even have memory flag bit. */ + } + + DELTAT->portstate = v & (0x80|0x40|0x20|0x10|0x01); /* start, rec, memory mode, repeat flag copy, reset(bit0) */ + + if( DELTAT->portstate&0x80 )/* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */ + { + /* set PCM BUSY bit */ + DELTAT->PCM_BSY = 1; + + /* start ADPCM */ + DELTAT->now_step = 0; + DELTAT->acc = 0; + DELTAT->prev_acc = 0; + DELTAT->adpcml = 0; + DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; + DELTAT->now_data = 0; + + } + + if( DELTAT->portstate&0x20 ) /* do we access external memory? */ + { + DELTAT->now_addr = DELTAT->start << 1; + DELTAT->memread = 2; /* two dummy reads needed before accesing external memory via register $08*/ + + /* if yes, then let's check if ADPCM memory is mapped and big enough */ + if(DELTAT->memory == 0) + { + /*logerror("YM Delta-T ADPCM rom not mapped\n");*/ + DELTAT->portstate = 0x00; + DELTAT->PCM_BSY = 0; + } + else + { + if( DELTAT->end >= DELTAT->memory_size ) /* Check End in Range */ + { + /*logerror("YM Delta-T ADPCM end out of range: $%08x\n", DELTAT->end);*/ + DELTAT->end = DELTAT->memory_size - 1; + } + if( DELTAT->start >= DELTAT->memory_size ) /* Check Start in Range */ + { + /*logerror("YM Delta-T ADPCM start out of range: $%08x\n", DELTAT->start);*/ + DELTAT->portstate = 0x00; + DELTAT->PCM_BSY = 0; + } + } + } + else /* we access CPU memory (ADPCM data register $08) so we only reset now_addr here */ + { + DELTAT->now_addr = 0; + } + + if( DELTAT->portstate&0x01 ) + { + DELTAT->portstate = 0x00; + + /* clear PCM BUSY bit (in status register) */ + DELTAT->PCM_BSY = 0; + + /* set BRDY flag */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + } + break; + case 0x01: /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */ + /* handle emulation mode */ + if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) + { + v |= 0x01; /* YM2610 always uses ROM as an external memory and doesn't tave ROM/RAM memory flag bit. */ + } + + DELTAT->pan = &DELTAT->output_pointer[(v>>6)&0x03]; + if ((DELTAT->control2 & 3) != (v & 3)) + { + /*0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */ + if (DELTAT->DRAMportshift != dram_rightshift[v&3]) + { + DELTAT->DRAMportshift = dram_rightshift[v&3]; + + /* final shift value depends on chip type and memory type selected: + 8 for YM2610 (ROM only), + 5 for ROM for Y8950 and YM2608, + 5 for x8bit DRAMs for Y8950 and YM2608, + 2 for x1bit DRAMs for Y8950 and YM2608. + */ + + /* refresh addresses */ + DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift); + DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift); + DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1; + DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift); + } + } + DELTAT->control2 = v; + break; + case 0x02: /* Start Address L */ + case 0x03: /* Start Address H */ + DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift); + /*logerror("DELTAT start: 02=%2x 03=%2x addr=%8x\n",DELTAT->reg[0x2], DELTAT->reg[0x3],DELTAT->start );*/ + break; + case 0x04: /* Stop Address L */ + case 0x05: /* Stop Address H */ + DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift); + DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1; + /*logerror("DELTAT end : 04=%2x 05=%2x addr=%8x\n",DELTAT->reg[0x4], DELTAT->reg[0x5],DELTAT->end );*/ + break; + case 0x06: /* Prescale L (ADPCM and Record frq) */ + case 0x07: /* Prescale H */ + break; + case 0x08: /* ADPCM data */ + +/* +some examples: +value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: + C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register + E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register + 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register + a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register + + 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 + 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 + +*/ + + /* external memory write */ + if ( (DELTAT->portstate & 0xe0)==0x60 ) + { + if (DELTAT->memread) + { + DELTAT->now_addr = DELTAT->start << 1; + DELTAT->memread = 0; + } + + /*logerror("YM Delta-T memory write $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/ + + if ( DELTAT->now_addr != (DELTAT->end<<1) ) + { + DELTAT->memory[DELTAT->now_addr>>1] = v; + DELTAT->now_addr+=2; /* two nibbles at a time */ + + /* reset BRDY bit in status register, which means we are processing the write */ + if(DELTAT->status_reset_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + + /* setup a timer that will callback us in 10 master clock cycles for Y8950 + * in the callback set the BRDY flag to 1 , which means we have written the data. + * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work. + */ + /* set BRDY bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + + } + else + { + /* set EOS bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_EOS_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); + } + + return; + } + + /* ADPCM synthesis from CPU */ + if ( (DELTAT->portstate & 0xe0)==0x80 ) + { + DELTAT->CPU_data = v; + + /* Reset BRDY bit in status register, which means we are full of data */ + if(DELTAT->status_reset_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + return; + } + + break; + case 0x09: /* DELTA-N L (ADPCM Playback Prescaler) */ + case 0x0a: /* DELTA-N H */ + DELTAT->delta = (DELTAT->reg[0xa]*0x0100 | DELTAT->reg[0x9]); + DELTAT->step = (UINT32)( (double)(DELTAT->delta /* *(1<<(YM_DELTAT_SHIFT-16)) */ ) * (DELTAT->freqbase) ); + /*logerror("DELTAT deltan:09=%2x 0a=%2x\n",DELTAT->reg[0x9], DELTAT->reg[0xa]);*/ + break; + case 0x0b: /* Output level control (volume, linear) */ + { + INT32 oldvol = DELTAT->volume; + DELTAT->volume = (v&0xff) * (DELTAT->output_range/256) / YM_DELTAT_DECODE_RANGE; +/* v * ((1<<16)>>8) >> 15; +* thus: v * (1<<8) >> 15; +* thus: output_range must be (1 << (15+8)) at least +* v * ((1<<23)>>8) >> 15; +* v * (1<<15) >> 15; +*/ + /*logerror("DELTAT vol = %2x\n",v&0xff);*/ + if( oldvol != 0 ) + { + DELTAT->adpcml = (int)((double)DELTAT->adpcml / (double)oldvol * (double)DELTAT->volume); + } + } + break; + case 0x0c: /* Limit Address L */ + case 0x0d: /* Limit Address H */ + DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift); + /*logerror("DELTAT limit: 0c=%2x 0d=%2x addr=%8x\n",DELTAT->reg[0xc], DELTAT->reg[0xd],DELTAT->limit );*/ + break; + } +} + +void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode) +{ + DELTAT->now_addr = 0; + DELTAT->now_step = 0; + DELTAT->step = 0; + DELTAT->start = 0; + DELTAT->end = 0; + DELTAT->limit = ~0; /* this way YM2610 and Y8950 (both of which don't have limit address reg) will still work */ + DELTAT->volume = 0; + DELTAT->pan = &DELTAT->output_pointer[pan]; + DELTAT->acc = 0; + DELTAT->prev_acc = 0; + DELTAT->adpcmd = 127; + DELTAT->adpcml = 0; + DELTAT->emulation_mode = (UINT8)emulation_mode; + DELTAT->portstate = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x20 : 0; + DELTAT->control2 = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x01 : 0; /* default setting depends on the emulation mode. MSX demo called "facdemo_4" doesn't setup control2 register at all and still works */ + DELTAT->DRAMportshift = dram_rightshift[DELTAT->control2 & 3]; + + /* The flag mask register disables the BRDY after the reset, however + ** as soon as the mask is enabled the flag needs to be set. */ + + /* set BRDY bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); +} + +#if 0 +void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs) +{ + int r; + + /* to keep adpcml */ + DELTAT->volume = 0; + /* update */ + for(r=1;r<16;r++) + YM_DELTAT_ADPCM_Write(DELTAT,r,regs[r]); + DELTAT->reg[0] = regs[0]; + + /* current rom data */ + if (DELTAT->memory) + DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1) ); + +} +void YM_DELTAT_savestate(const device_config *device,YM_DELTAT *DELTAT) +{ +#ifdef __STATE_H__ + state_save_register_device_item(device, 0, DELTAT->portstate); + state_save_register_device_item(device, 0, DELTAT->now_addr); + state_save_register_device_item(device, 0, DELTAT->now_step); + state_save_register_device_item(device, 0, DELTAT->acc); + state_save_register_device_item(device, 0, DELTAT->prev_acc); + state_save_register_device_item(device, 0, DELTAT->adpcmd); + state_save_register_device_item(device, 0, DELTAT->adpcml); +#endif +} +#endif + + +#define YM_DELTAT_Limit(val,max,min) \ +{ \ + if ( val > max ) val = max; \ + else if ( val < min ) val = min; \ +} + +INLINE void YM_DELTAT_synthesis_from_external_memory(YM_DELTAT *DELTAT) +{ + UINT32 step; + int data; + + DELTAT->now_step += DELTAT->step; + if ( DELTAT->now_step >= (1<now_step >> YM_DELTAT_SHIFT; + DELTAT->now_step &= (1<now_addr == (DELTAT->limit<<1) ) + DELTAT->now_addr = 0; + + if ( DELTAT->now_addr == (DELTAT->end<<1) ) { /* 12-06-2001 JB: corrected comparison. Was > instead of == */ + if( DELTAT->portstate&0x10 ){ + /* repeat start */ + DELTAT->now_addr = DELTAT->start<<1; + DELTAT->acc = 0; + DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; + DELTAT->prev_acc = 0; + }else{ + /* set EOS bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_EOS_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); + + /* clear PCM BUSY bit (reflected in status register) */ + DELTAT->PCM_BSY = 0; + + DELTAT->portstate = 0; + DELTAT->adpcml = 0; + DELTAT->prev_acc = 0; + return; + } + } + + if( DELTAT->now_addr&1 ) data = DELTAT->now_data & 0x0f; + else + { + DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1)); + data = DELTAT->now_data >> 4; + } + + DELTAT->now_addr++; + /* 12-06-2001 JB: */ + /* YM2610 address register is 24 bits wide.*/ + /* The "+1" is there because we use 1 bit more for nibble calculations.*/ + /* WARNING: */ + /* Side effect: we should take the size of the mapped ROM into account */ + DELTAT->now_addr &= ( (1<<(24+1))-1); + + /* store accumulator value */ + DELTAT->prev_acc = DELTAT->acc; + + /* Forecast to next Forecast */ + DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8); + YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); + + /* delta to next delta */ + DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64; + YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN ); + + /* ElSemi: Fix interpolator. */ + /*DELTAT->prev_acc = prev_acc + ((DELTAT->acc - prev_acc) / 2 );*/ + + }while(--step); + + } + + /* ElSemi: Fix interpolator. */ + DELTAT->adpcml = DELTAT->prev_acc * (int)((1<now_step); + DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step); + DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume; + + /* output for work of output channels (outd[OPNxxxx])*/ + *(DELTAT->pan) += DELTAT->adpcml; +} + + + +INLINE void YM_DELTAT_synthesis_from_CPU_memory(YM_DELTAT *DELTAT) +{ + UINT32 step; + int data; + + DELTAT->now_step += DELTAT->step; + if ( DELTAT->now_step >= (1<now_step >> YM_DELTAT_SHIFT; + DELTAT->now_step &= (1<now_addr&1 ) + { + data = DELTAT->now_data & 0x0f; + + DELTAT->now_data = DELTAT->CPU_data; + + /* after we used CPU_data, we set BRDY bit in status register, + * which means we are ready to accept another byte of data */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + } + else + { + data = DELTAT->now_data >> 4; + } + + DELTAT->now_addr++; + + /* store accumulator value */ + DELTAT->prev_acc = DELTAT->acc; + + /* Forecast to next Forecast */ + DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8); + YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); + + /* delta to next delta */ + DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64; + YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN ); + + + }while(--step); + + } + + /* ElSemi: Fix interpolator. */ + DELTAT->adpcml = DELTAT->prev_acc * (int)((1<now_step); + DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step); + DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume; + + /* output for work of output channels (outd[OPNxxxx])*/ + *(DELTAT->pan) += DELTAT->adpcml; +} + + + +/* ADPCM B (Delta-T control type) */ +void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT) +{ + +/* +some examples: +value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: + 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register + a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register + C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register + E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register + + 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 + 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 + +*/ + + if ( (DELTAT->portstate & 0xe0)==0xa0 ) + { + YM_DELTAT_synthesis_from_external_memory(DELTAT); + return; + } + + if ( (DELTAT->portstate & 0xe0)==0x80 ) + { + /* ADPCM synthesis from CPU-managed memory (from reg $08) */ + YM_DELTAT_synthesis_from_CPU_memory(DELTAT); /* change output based on data in ADPCM data reg ($08) */ + return; + } + +//todo: ADPCM analysis +// if ( (DELTAT->portstate & 0xe0)==0xc0 ) +// if ( (DELTAT->portstate & 0xe0)==0xe0 ) + + return; +} + diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ymdeltat.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ymdeltat.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/ymdeltat.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/ymdeltat.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,90 +1,90 @@ -#pragma once - -#ifndef __YMDELTAT_H__ -#define __YMDELTAT_H__ - -#include "mamedef.h" - -#define YM_DELTAT_SHIFT (16) - -#define YM_DELTAT_EMULATION_MODE_NORMAL 0 -#define YM_DELTAT_EMULATION_MODE_YM2610 1 - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef void (*STATUS_CHANGE_HANDLER)(void *chip, UINT8 status_bits); - - -/* DELTA-T (adpcm type B) struct */ -typedef struct deltat_adpcm_state { /* AT: rearranged and tigntened structure */ - UINT8 *memory; - INT32 *output_pointer;/* pointer of output pointers */ - INT32 *pan; /* pan : &output_pointer[pan] */ - double freqbase; -#if 0 - double write_time; /* Y8950: 10 cycles of main clock; YM2608: 20 cycles of main clock */ - double read_time; /* Y8950: 8 cycles of main clock; YM2608: 18 cycles of main clock */ -#endif - UINT32 memory_size; - int output_range; - UINT32 now_addr; /* current address */ - UINT32 now_step; /* currect step */ - UINT32 step; /* step */ - UINT32 start; /* start address */ - UINT32 limit; /* limit address */ - UINT32 end; /* end address */ - UINT32 delta; /* delta scale */ - INT32 volume; /* current volume */ - INT32 acc; /* shift Measurement value*/ - INT32 adpcmd; /* next Forecast */ - INT32 adpcml; /* current value */ - INT32 prev_acc; /* leveling value */ - UINT8 now_data; /* current rom data */ - UINT8 CPU_data; /* current data from reg 08 */ - UINT8 portstate; /* port status */ - UINT8 control2; /* control reg: SAMPLE, DA/AD, RAM TYPE (x8bit / x1bit), ROM/RAM */ - UINT8 portshift; /* address bits shift-left: - ** 8 for YM2610, - ** 5 for Y8950 and YM2608 */ - - UINT8 DRAMportshift; /* address bits shift-right: - ** 0 for ROM and x8bit DRAMs, - ** 3 for x1 DRAMs */ - - UINT8 memread; /* needed for reading/writing external memory */ - - /* handlers and parameters for the status flags support */ - STATUS_CHANGE_HANDLER status_set_handler; - STATUS_CHANGE_HANDLER status_reset_handler; - - /* note that different chips have these flags on different - ** bits of the status register - */ - void * status_change_which_chip; /* this chip id */ - UINT8 status_change_EOS_bit; /* 1 on End Of Sample (record/playback/cycle time of AD/DA converting has passed)*/ - UINT8 status_change_BRDY_bit; /* 1 after recording 2 datas (2x4bits) or after reading/writing 1 data */ - UINT8 status_change_ZERO_bit; /* 1 if silence lasts for more than 290 miliseconds on ADPCM recording */ - - /* neither Y8950 nor YM2608 can generate IRQ when PCMBSY bit changes, so instead of above, - ** the statusflag gets ORed with PCM_BSY (below) (on each read of statusflag of Y8950 and YM2608) - */ - UINT8 PCM_BSY; /* 1 when ADPCM is playing; Y8950/YM2608 only */ - - UINT8 reg[16]; /* adpcm registers */ - UINT8 emulation_mode; /* which chip we're emulating */ -}YM_DELTAT; - -/*void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT);*/ - -UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT); -void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v); -void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode); -void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT); - -/*void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs); +#pragma once + +#ifndef __YMDELTAT_H__ +#define __YMDELTAT_H__ + +#include "mamedef.h" + +#define YM_DELTAT_SHIFT (16) + +#define YM_DELTAT_EMULATION_MODE_NORMAL 0 +#define YM_DELTAT_EMULATION_MODE_YM2610 1 + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef void (*STATUS_CHANGE_HANDLER)(void *chip, UINT8 status_bits); + + +/* DELTA-T (adpcm type B) struct */ +typedef struct deltat_adpcm_state { /* AT: rearranged and tigntened structure */ + UINT8 *memory; + INT32 *output_pointer;/* pointer of output pointers */ + INT32 *pan; /* pan : &output_pointer[pan] */ + double freqbase; +#if 0 + double write_time; /* Y8950: 10 cycles of main clock; YM2608: 20 cycles of main clock */ + double read_time; /* Y8950: 8 cycles of main clock; YM2608: 18 cycles of main clock */ +#endif + UINT32 memory_size; + int output_range; + UINT32 now_addr; /* current address */ + UINT32 now_step; /* currect step */ + UINT32 step; /* step */ + UINT32 start; /* start address */ + UINT32 limit; /* limit address */ + UINT32 end; /* end address */ + UINT32 delta; /* delta scale */ + INT32 volume; /* current volume */ + INT32 acc; /* shift Measurement value*/ + INT32 adpcmd; /* next Forecast */ + INT32 adpcml; /* current value */ + INT32 prev_acc; /* leveling value */ + UINT8 now_data; /* current rom data */ + UINT8 CPU_data; /* current data from reg 08 */ + UINT8 portstate; /* port status */ + UINT8 control2; /* control reg: SAMPLE, DA/AD, RAM TYPE (x8bit / x1bit), ROM/RAM */ + UINT8 portshift; /* address bits shift-left: + ** 8 for YM2610, + ** 5 for Y8950 and YM2608 */ + + UINT8 DRAMportshift; /* address bits shift-right: + ** 0 for ROM and x8bit DRAMs, + ** 3 for x1 DRAMs */ + + UINT8 memread; /* needed for reading/writing external memory */ + + /* handlers and parameters for the status flags support */ + STATUS_CHANGE_HANDLER status_set_handler; + STATUS_CHANGE_HANDLER status_reset_handler; + + /* note that different chips have these flags on different + ** bits of the status register + */ + void * status_change_which_chip; /* this chip id */ + UINT8 status_change_EOS_bit; /* 1 on End Of Sample (record/playback/cycle time of AD/DA converting has passed)*/ + UINT8 status_change_BRDY_bit; /* 1 after recording 2 datas (2x4bits) or after reading/writing 1 data */ + UINT8 status_change_ZERO_bit; /* 1 if silence lasts for more than 290 miliseconds on ADPCM recording */ + + /* neither Y8950 nor YM2608 can generate IRQ when PCMBSY bit changes, so instead of above, + ** the statusflag gets ORed with PCM_BSY (below) (on each read of statusflag of Y8950 and YM2608) + */ + UINT8 PCM_BSY; /* 1 when ADPCM is playing; Y8950/YM2608 only */ + + UINT8 reg[16]; /* adpcm registers */ + UINT8 emulation_mode; /* which chip we're emulating */ +}YM_DELTAT; + +/*void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT);*/ + +UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT); +void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v); +void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode); +void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT); + +/*void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs); void YM_DELTAT_savestate(const device_config *device,YM_DELTAT *DELTAT);*/ #ifdef __cplusplus diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Z80_Cpu.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Z80_Cpu.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Z80_Cpu.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Z80_Cpu.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,122 +1,122 @@ -// Z80 CPU emulator - -// $package -#ifndef Z80_CPU_H -#define Z80_CPU_H - -#include "blargg_endian.h" - -class Z80_Cpu { -public: - typedef int time_t; - typedef int addr_t; - typedef BOOST::uint8_t byte; - - // Clears registers and maps all pages to unmapped - void reset( void* unmapped_write, void const* unmapped_read ); - - // TODO: split mapping out of CPU - - // Maps memory. Start and size must be multiple of page_size. - enum { page_bits = 10 }; - enum { page_size = 1 << page_bits }; - void map_mem( addr_t addr, int size, void* write, void const* read ); - void map_mem( addr_t addr, int size, void* read_write ); - - // Maps address to pointer to that byte - byte * write( addr_t addr ); - byte const* read( addr_t addr ); - - // Time of beginning of next instruction - time_t time() const { return cpu_state->time + cpu_state->base; } - - // Alter current time - void set_time( time_t t ) { cpu_state->time = t - cpu_state->base; } - void adjust_time( int delta ) { cpu_state->time += delta; } - - #if BLARGG_BIG_ENDIAN - struct regs_t { byte b,c, d,e, h,l, flags,a; }; - #else - struct regs_t { byte c,b, e,d, l,h, a,flags; }; - #endif - BLARGG_STATIC_ASSERT( sizeof (regs_t) == 8 ); - - struct pairs_t { BOOST::uint16_t bc, de, hl, fa; }; - - // Registers are not updated until run() returns - struct registers_t { - BOOST::uint16_t pc; - BOOST::uint16_t sp; - BOOST::uint16_t ix; - BOOST::uint16_t iy; - union { - regs_t b; // b.b, b.c, b.d, b.e, b.h, b.l, b.flags, b.a - pairs_t w; // w.bc, w.de, w.hl. w.fa - }; - union { - regs_t b; - pairs_t w; - } alt; - byte iff1; - byte iff2; - byte r; - byte i; - byte im; - }; - //registers_t r; (below for efficiency) - - // can read this far past end of memory - enum { cpu_padding = 0x100 }; - - // Can read this many bytes past end of a page - enum { page_padding = 4 }; - - void set_end_time( time_t t ); -public: - Z80_Cpu(); - - enum { page_count = 0x10000 / page_size }; - byte szpc [0x200]; - time_t end_time_; - struct cpu_state_t { - byte const* read [page_count + 1]; - byte * write [page_count + 1]; - time_t base; - time_t time; - }; - cpu_state_t* cpu_state; // points to cpu_state_ or a local copy within run() - cpu_state_t cpu_state_; - void set_page( int i, void* write, void const* read ); -public: - registers_t r; -}; - -#if BLARGG_NONPORTABLE - #define Z80_CPU_OFFSET( addr ) (addr) -#else - #define Z80_CPU_OFFSET( addr ) ((addr) & (Z80_Cpu::page_size - 1)) -#endif - -inline Z80_Cpu::byte* Z80_Cpu::write( addr_t addr ) -{ - return cpu_state->write [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr ); -} - -inline Z80_Cpu::byte const* Z80_Cpu::read( addr_t addr ) -{ - return cpu_state->read [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr ); -} - -inline void Z80_Cpu::map_mem( addr_t addr, int size, void* p ) -{ - map_mem( addr, size, p, p ); -} - -inline void Z80_Cpu::set_end_time( time_t t ) -{ - time_t delta = cpu_state->base - t; - cpu_state->base = t; - cpu_state->time += delta; -} - -#endif +// Z80 CPU emulator + +// $package +#ifndef Z80_CPU_H +#define Z80_CPU_H + +#include "blargg_endian.h" + +class Z80_Cpu { +public: + typedef int time_t; + typedef int addr_t; + typedef BOOST::uint8_t byte; + + // Clears registers and maps all pages to unmapped + void reset( void* unmapped_write, void const* unmapped_read ); + + // TODO: split mapping out of CPU + + // Maps memory. Start and size must be multiple of page_size. + enum { page_bits = 10 }; + enum { page_size = 1 << page_bits }; + void map_mem( addr_t addr, int size, void* write, void const* read ); + void map_mem( addr_t addr, int size, void* read_write ); + + // Maps address to pointer to that byte + byte * write( addr_t addr ); + byte const* read( addr_t addr ); + + // Time of beginning of next instruction + time_t time() const { return cpu_state->time + cpu_state->base; } + + // Alter current time + void set_time( time_t t ) { cpu_state->time = t - cpu_state->base; } + void adjust_time( int delta ) { cpu_state->time += delta; } + + #if BLARGG_BIG_ENDIAN + struct regs_t { byte b,c, d,e, h,l, flags,a; }; + #else + struct regs_t { byte c,b, e,d, l,h, a,flags; }; + #endif + BLARGG_STATIC_ASSERT( sizeof (regs_t) == 8 ); + + struct pairs_t { BOOST::uint16_t bc, de, hl, fa; }; + + // Registers are not updated until run() returns + struct registers_t { + BOOST::uint16_t pc; + BOOST::uint16_t sp; + BOOST::uint16_t ix; + BOOST::uint16_t iy; + union { + regs_t b; // b.b, b.c, b.d, b.e, b.h, b.l, b.flags, b.a + pairs_t w; // w.bc, w.de, w.hl. w.fa + }; + union { + regs_t b; + pairs_t w; + } alt; + byte iff1; + byte iff2; + byte r; + byte i; + byte im; + }; + //registers_t r; (below for efficiency) + + // can read this far past end of memory + enum { cpu_padding = 0x100 }; + + // Can read this many bytes past end of a page + enum { page_padding = 4 }; + + void set_end_time( time_t t ); +public: + Z80_Cpu(); + + enum { page_count = 0x10000 / page_size }; + byte szpc [0x200]; + time_t end_time_; + struct cpu_state_t { + byte const* read [page_count + 1]; + byte * write [page_count + 1]; + time_t base; + time_t time; + }; + cpu_state_t* cpu_state; // points to cpu_state_ or a local copy within run() + cpu_state_t cpu_state_; + void set_page( int i, void* write, void const* read ); +public: + registers_t r; +}; + +#if BLARGG_NONPORTABLE + #define Z80_CPU_OFFSET( addr ) (addr) +#else + #define Z80_CPU_OFFSET( addr ) ((addr) & (Z80_Cpu::page_size - 1)) +#endif + +inline Z80_Cpu::byte* Z80_Cpu::write( addr_t addr ) +{ + return cpu_state->write [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr ); +} + +inline Z80_Cpu::byte const* Z80_Cpu::read( addr_t addr ) +{ + return cpu_state->read [(unsigned) addr >> page_bits] + Z80_CPU_OFFSET( addr ); +} + +inline void Z80_Cpu::map_mem( addr_t addr, int size, void* p ) +{ + map_mem( addr, size, p, p ); +} + +inline void Z80_Cpu::set_end_time( time_t t ) +{ + time_t delta = cpu_state->base - t; + cpu_state->base = t; + cpu_state->time += delta; +} + +#endif diff -Nru kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Z80_Cpu_run.h kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Z80_Cpu_run.h --- kodi-audiodecoder-gme-2.0.3/lib/Game_Music_Emu/gme/Z80_Cpu_run.h 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/Game_Music_Emu/gme/Z80_Cpu_run.h 2013-05-31 22:59:22.000000000 +0000 @@ -1,1701 +1,1701 @@ -// $package. http://www.slack.net/~ant/ - -// Last validated with zexall 2009.12.05. -// Doesn't implement the R register or immediate interrupt after EI. -// Address wrap-around isn't completely correct, but is prevented from crashing emulator. -// 16-bit memory accesses are made directly to mapped memory, instead of using macro. - -#if 0 -/* Define these macros in the source file before #including this file. -- Parameters might be expressions, so they are best evaluated only once, -though they NEVER have side-effects, so multiple evaluation is OK. -- Output parameters might be a multiple-assignment expression like "a=x", -so they must NOT be parenthesized. -- Except where noted, time() and related functions will NOT work -correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and -CACHE_TIME() the normal time changing functions can be used. -- Macros "returning" void may use a {} statement block. */ - - // 0 <= addr <= 0xFFFF + 0x100 - // Optional; default uses whatever was set with map_mem() - int READ_CODE( addr_t ); - - // 0 <= addr <= 0xFFFF + 0x100 - // Optional; default uses whatever was set with map_mem() - int READ_MEM( addr_t ); - void WRITE_MEM( addr_t, int data ); - - // 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware) - void OUT_PORT( int port, int data ); - int IN_PORT int port ); - - // Reference to Z80_Cpu object used for emulation - #define CPU cpu - -// The following can be used within macros: - - // Current time - time_t TIME(); - - // Allows use of time functions - void FLUSH_TIME(); - - // Must be used before end of macro if FLUSH_TIME() was used earlier - void CACHE_TIME(); - -// Configuration (optional; commented behavior if defined) - - // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect - #define FLAT_MEM my_mem_array - - // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution - #define IDLE_ADDR 0x1234 - - // Expanded just before beginning of code, to help debugger - #define CPU_BEGIN void my_run_cpu() { - -#endif - -/* Copyright (C) 2006-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#ifdef CPU_BEGIN - CPU_BEGIN -#endif - -#define R CPU.r - -// flags, named with hex value for clarity -int const S80 = 0x80; -int const Z40 = 0x40; -int const F20 = 0x20; -int const H10 = 0x10; -int const F08 = 0x08; -int const V04 = 0x04; -int const P04 = 0x04; -int const N02 = 0x02; -int const C01 = 0x01; - -#define SZ28P( n ) CPU.szpc [n] -#define SZ28PC( n ) CPU.szpc [n] -#define SZ28C( n ) (CPU.szpc [n] & ~P04) -#define SZ28( n ) SZ28C( n ) - -#define SET_R( n ) (void) (R.r = n) -#define GET_R() (R.r) - -// Time -#define TIME() (s_time + s.base) -#define FLUSH_TIME() {s.time = s_time;} -#define CACHE_TIME() {s_time = s.time;} - -// Memory -#define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )] -#ifndef READ_CODE - #define READ_CODE( addr ) RW_MEM( addr, read ) -#endif - -#ifdef FLAT_MEM - #define RW_PAGE( addr, rw ) FLAT_MEM - #define RW_OFFSET( addr ) (addr) - #define INSTR( off, addr ) READ_CODE( addr ) -#else - #define RW_PAGE( addr, rw ) s.rw [(unsigned) (addr) >> Z80_Cpu::page_bits] - #define RW_OFFSET( addr ) Z80_CPU_OFFSET( addr ) - #define INSTR( off, addr ) instr [off] -#endif - -#ifndef READ_MEM - #define READ_MEM( addr ) RW_MEM( addr, read ) -#endif - -#ifndef WRITE_MEM - #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data) -#endif - -#define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) ) -#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data ) - -// Truncation -#define BYTE( n ) ((BOOST::uint8_t ) (n)) /* (unsigned) n & 0xFF */ -#define SBYTE( n ) ((BOOST::int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ -#define WORD( n ) ((BOOST::uint16_t) (n)) /* (unsigned) n & 0xFFFF */ - -// Misc -#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e -#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f -#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g -#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h - -#if BLARGG_BIG_ENDIAN - #define R8( n, offset ) ((r.r8_ - offset) [n]) -#elif BLARGG_LITTLE_ENDIAN - #define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1]) -#else - #error "Byte order of CPU must be known" -#endif - -#define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)]) - -#define EX( x, y ) \ - {\ - int temp = x;\ - x = y;\ - y = temp;\ - } - -#define EXX( name ) \ - EX( R.alt.name, r.name ) - -bool warning = false; -{ - Z80_Cpu::cpu_state_t s; - #ifdef FLAT_MEM - s.base = CPU.cpu_state_.base; - #else - s = CPU.cpu_state_; - #endif - CPU.cpu_state = &s; - - - union r_t { - Z80_Cpu::regs_t b; - Z80_Cpu::pairs_t w; - byte r8_ [8]; // indexed - BOOST::uint16_t r16_ [4]; - } r; - r.b = R.b; - - Z80_Cpu::time_t s_time = CPU.cpu_state_.time; - int pc = R.pc; - int sp = R.sp; - int ix = R.ix; // TODO: keep in memory for direct access? - int iy = R.iy; - int flags = R.b.flags; - - //goto loop; // confuses optimizer - s_time += 7; - pc -= 2; - -call_not_taken: - s_time -= 7; -jp_not_taken: - pc += 2; -loop: - - check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around - check( (unsigned) sp < 0x10000 ); - check( (unsigned) flags < 0x100 ); - check( (unsigned) ix < 0x10000 ); - check( (unsigned) iy < 0x10000 ); - - byte const* instr = RW_PAGE( pc, read ); - - int opcode; - - if ( RW_OFFSET( ~0 ) == ~0 ) - { - opcode = instr [RW_OFFSET( pc )]; - pc++; - instr += RW_OFFSET( pc ); - } - else - { - instr += RW_OFFSET( pc ); - opcode = *instr++; - pc++; - } - - static byte const clock_table [256 * 2] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 - 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 - 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2 - 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 - 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B - 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C - 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D - 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E - 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F - - // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, - 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, - 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, - 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, - 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, - 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, - }; - - if ( s_time >= 0 ) - goto out_of_time; - s_time += clock_table [opcode]; - - #ifdef Z80_CPU_LOG_H - //log_opcode( opcode, READ_CODE( pc ) ); - z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ), - READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) ); - z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy ); - #endif - -#define GET_ADDR() GET_LE16( &INSTR( 0, pc ) ) - - int data; - data = INSTR( 0, pc ); - - switch ( opcode ) - { -// Common - - case 0x00: // NOP - CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. - goto loop; - - case 0x08:{// EX AF,AF' - EXX( b.a ); - EX( R.alt.b.flags, flags ); - goto loop; - } - - case 0xD3: // OUT (imm),A - pc++; - OUT_PORT( (data + r.b.a * 0x100), r.b.a ); - goto loop; - - case 0x2E: // LD L,imm - pc++; - r.b.l = data; - goto loop; - - case 0x3E: // LD A,imm - pc++; - r.b.a = data; - goto loop; - - case 0x3A:{// LD A,(addr) - int addr = GET_ADDR(); - pc += 2; - r.b.a = READ_MEM( addr ); - goto loop; - } - -// Conditional - -#define ZERO (flags & Z40) -#define CARRY (flags & C01) -#define EVEN (flags & P04) -#define MINUS (flags & S80) - -// JR -// TODO: more efficient way to handle negative branch that wraps PC around -#define JR_( cond, clocks ) {\ - pc++;\ - if ( !(cond) )\ - goto loop;\ - int offset = SBYTE( data );\ - pc = WORD( pc + offset );\ - s_time += clocks;\ - goto loop;\ -} - -#define JR( cond ) JR_( cond, 5 ) - - case 0x20: JR( !ZERO ) // JR NZ,disp - case 0x28: JR( ZERO ) // JR Z,disp - case 0x30: JR( !CARRY ) // JR NC,disp - case 0x38: JR( CARRY ) // JR C,disp - case 0x18: JR_( true,0) // JR disp - - case 0x10:{// DJNZ disp - int temp = r.b.b - 1; - r.b.b = temp; - JR( temp ) - } - -// JP -#define JP( cond ) \ - if ( !(cond) )\ - goto jp_not_taken;\ - pc = GET_ADDR();\ - goto loop; - - case 0xC2: JP( !ZERO ) // JP NZ,addr - case 0xCA: JP( ZERO ) // JP Z,addr - case 0xD2: JP( !CARRY ) // JP NC,addr - case 0xDA: JP( CARRY ) // JP C,addr - case 0xE2: JP( !EVEN ) // JP PO,addr - case 0xEA: JP( EVEN ) // JP PE,addr - case 0xF2: JP( !MINUS ) // JP P,addr - case 0xFA: JP( MINUS ) // JP M,addr - - case 0xC3: // JP addr - pc = GET_ADDR(); - goto loop; - - case 0xE9: // JP HL - pc = r.w.hl; - goto loop; - -// RET -#define RET( cond ) \ - if ( cond )\ - goto ret_taken;\ - s_time -= 6;\ - goto loop; - - case 0xC0: RET( !ZERO ) // RET NZ - case 0xC8: RET( ZERO ) // RET Z - case 0xD0: RET( !CARRY ) // RET NC - case 0xD8: RET( CARRY ) // RET C - case 0xE0: RET( !EVEN ) // RET PO - case 0xE8: RET( EVEN ) // RET PE - case 0xF0: RET( !MINUS ) // RET P - case 0xF8: RET( MINUS ) // RET M - - case 0xC9: // RET - ret_taken: - pc = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto loop; - -// CALL -#define CALL( cond ) \ - if ( cond )\ - goto call_taken;\ - goto call_not_taken; - - case 0xC4: CALL( !ZERO ) // CALL NZ,addr - case 0xCC: CALL( ZERO ) // CALL Z,addr - case 0xD4: CALL( !CARRY ) // CALL NC,addr - case 0xDC: CALL( CARRY ) // CALL C,addr - case 0xE4: CALL( !EVEN ) // CALL PO,addr - case 0xEC: CALL( EVEN ) // CALL PE,addr - case 0xF4: CALL( !MINUS ) // CALL P,addr - case 0xFC: CALL( MINUS ) // CALL M,addr - - case 0xCD:{// CALL addr - call_taken: - int addr = pc + 2; - pc = GET_ADDR(); - sp = WORD( sp - 2 ); - WRITE_WORD( sp, addr ); - goto loop; - } - - case 0xFF: // RST - #ifdef IDLE_ADDR - if ( pc == IDLE_ADDR + 1 ) - goto hit_idle_addr; - #else - if ( pc > 0x10000 ) - { - pc = WORD( pc - 1 ); - s_time -= 11; - goto loop; - } - #endif - CASE7( C7, CF, D7, DF, E7, EF, F7 ): - data = pc; - pc = opcode & 0x38; - #ifdef RST_BASE - pc += RST_BASE; - #endif - goto push_data; - -// PUSH/POP - case 0xF5: // PUSH AF - data = r.b.a * 0x100u + flags; - goto push_data; - - case 0xC5: // PUSH BC - case 0xD5: // PUSH DE - case 0xE5: // PUSH HL - data = R16( opcode, 4, 0xC5 ); - push_data: - sp = WORD( sp - 2 ); - WRITE_WORD( sp, data ); - goto loop; - - case 0xF1: // POP AF - flags = READ_MEM( sp ); - r.b.a = READ_MEM( (sp + 1) ); - sp = WORD( sp + 2 ); - goto loop; - - case 0xC1: // POP BC - case 0xD1: // POP DE - case 0xE1: // POP HL - R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto loop; - -// ADC/ADD/SBC/SUB - case 0x96: // SUB (HL) - case 0x86: // ADD (HL) - flags &= ~C01; - case 0x9E: // SBC (HL) - case 0x8E: // ADC (HL) - data = READ_MEM( r.w.hl ); - goto adc_data; - - case 0xD6: // SUB A,imm - case 0xC6: // ADD imm - flags &= ~C01; - case 0xDE: // SBC A,imm - case 0xCE: // ADC imm - pc++; - goto adc_data; - - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r - flags &= ~C01; - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r - data = R8( opcode & 7, 0 ); - adc_data: { - int result = data + (flags & C01); - data ^= r.b.a; - flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes - if ( flags ) - result = -result; - result += r.b.a; - data ^= result; - flags +=(data & H10) + - ((data + 0x80) >> 6 & V04) + - SZ28C( result & 0x1FF ); - r.b.a = result; - goto loop; - } - -// CP - case 0xBE: // CP (HL) - data = READ_MEM( r.w.hl ); - goto cp_data; - - case 0xFE: // CP imm - pc++; - goto cp_data; - - CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r - data = R8( opcode, 0xB8 ); - cp_data: { - int result = r.b.a - data; - flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01); - data ^= r.b.a; - flags +=(((result ^ r.b.a) & data) >> 5 & V04) + - (((data & H10) ^ result) & (S80 | H10)); - if ( BYTE( result ) ) - goto loop; - flags += Z40; - goto loop; - } - -// ADD HL,r.w - - case 0x39: // ADD HL,SP - data = sp; - goto add_hl_data; - - case 0x09: // ADD HL,BC - case 0x19: // ADD HL,DE - case 0x29: // ADD HL,HL - data = R16( opcode, 4, 0x09 ); - add_hl_data: { - int sum = r.w.hl + data; - data ^= r.w.hl; - r.w.hl = sum; - flags = (flags & (S80 | Z40 | V04)) + - (sum >> 16) + - (sum >> 8 & (F20 | F08)) + - ((data ^ sum) >> 8 & H10); - goto loop; - } - - case 0x27:{// DAA - int a = r.b.a; - if ( a > 0x99 ) - flags |= C01; - - int adjust = 0x60 * (flags & C01); - - if ( flags & H10 || (a & 0x0F) > 9 ) - adjust += 0x06; - - if ( flags & N02 ) - adjust = -adjust; - a += adjust; - - flags = (flags & (C01 | N02)) + - ((r.b.a ^ a) & H10) + - SZ28P( BYTE( a ) ); - r.b.a = a; - goto loop; - } - -// INC/DEC - case 0x34: // INC (HL) - data = READ_MEM( r.w.hl ) + 1; - WRITE_MEM( r.w.hl, data ); - goto inc_set_flags; - - CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r - data = ++R8( opcode >> 3, 0 ); - inc_set_flags: - flags = (flags & C01) + - (((data & 0x0F) - 1) & H10) + - SZ28( BYTE( data ) ); - if ( data != 0x80 ) - goto loop; - flags += V04; - goto loop; - - case 0x35: // DEC (HL) - data = READ_MEM( r.w.hl ) - 1; - WRITE_MEM( r.w.hl, data ); - goto dec_set_flags; - - CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r - data = --R8( opcode >> 3, 0 ); - dec_set_flags: - flags = (flags & C01) + N02 + - (((data & 0x0F) + 1) & H10) + - SZ28( BYTE( data ) ); - if ( data != 0x7F ) - goto loop; - flags += V04; - goto loop; - - case 0x03: // INC BC - case 0x13: // INC DE - case 0x23: // INC HL - R16( opcode, 4, 0x03 )++; - goto loop; - - case 0x33: // INC SP - sp = WORD( sp + 1 ); - goto loop; - - case 0x0B: // DEC BC - case 0x1B: // DEC DE - case 0x2B: // DEC HL - R16( opcode, 4, 0x0B )--; - goto loop; - - case 0x3B: // DEC SP - sp = WORD( sp - 1 ); - goto loop; - -// AND - case 0xA6: // AND (HL) - data = READ_MEM( r.w.hl ); - goto and_data; - - case 0xE6: // AND imm - pc++; - goto and_data; - - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r - data = R8( opcode, 0xA0 ); - and_data: - r.b.a &= data; - flags = SZ28P( r.b.a ) + H10; - goto loop; - -// OR - case 0xB6: // OR (HL) - data = READ_MEM( r.w.hl ); - goto or_data; - - case 0xF6: // OR imm - pc++; - goto or_data; - - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r - data = R8( opcode, 0xB0 ); - or_data: - r.b.a |= data; - flags = SZ28P( r.b.a ); - goto loop; - -// XOR - case 0xAE: // XOR (HL) - data = READ_MEM( r.w.hl ); - goto xor_data; - - case 0xEE: // XOR imm - pc++; - goto xor_data; - - CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r - data = R8( opcode, 0xA8 ); - xor_data: - r.b.a ^= data; - flags = SZ28P( r.b.a ); - goto loop; - -// LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r - WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) ); - goto loop; - - CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r - CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r - CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r - CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r - CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r - CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r - CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r - R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); - goto loop; - - CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm - R8( opcode >> 3, 0 ) = data; - pc++; - goto loop; - - case 0x36: // LD (HL),imm - pc++; - WRITE_MEM( r.w.hl, data ); - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) - R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl ); - goto loop; - - case 0x01: // LD r.w,imm - case 0x11: - case 0x21: - R16( opcode, 4, 0x01 ) = GET_ADDR(); - pc += 2; - goto loop; - - case 0x31: // LD sp,imm - sp = GET_ADDR(); - pc += 2; - goto loop; - - case 0x2A:{// LD HL,(addr) - int addr = GET_ADDR(); - pc += 2; - r.w.hl = READ_WORD( addr ); - goto loop; - } - - case 0x32:{// LD (addr),A - int addr = GET_ADDR(); - pc += 2; - WRITE_MEM( addr, r.b.a ); - goto loop; - } - - case 0x22:{// LD (addr),HL - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, r.w.hl ); - goto loop; - } - - case 0x02: // LD (BC),A - case 0x12: // LD (DE),A - WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a ); - goto loop; - - case 0x0A: // LD A,(BC) - case 0x1A: // LD A,(DE) - r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) ); - goto loop; - - case 0xF9: // LD SP,HL - sp = r.w.hl; - goto loop; - -// Rotate - - case 0x07:{// RLCA - int temp = r.b.a; - temp = (temp << 1) + (temp >> 7); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08 | C01)); - r.b.a = temp; - goto loop; - } - - case 0x0F:{// RRCA - int temp = r.b.a; - flags = (flags & (S80 | Z40 | P04)) + - (temp & C01); - temp = (temp << 7) + (temp >> 1); - flags += temp & (F20 | F08); - r.b.a = temp; - goto loop; - } - - case 0x17:{// RLA - int temp = (r.b.a << 1) + (flags & C01); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08)) + - (temp >> 8); - r.b.a = temp; - goto loop; - } - - case 0x1F:{// RRA - int temp = (flags << 7) + (r.b.a >> 1); - flags = (flags & (S80 | Z40 | P04)) + - (temp & (F20 | F08)) + - (r.b.a & C01); - r.b.a = temp; - goto loop; - } - -// Misc - case 0x2F:{// CPL - int temp = ~r.b.a; - flags = (flags & (S80 | Z40 | P04 | C01)) + - (temp & (F20 | F08)) + - (H10 | N02); - r.b.a = temp; - goto loop; - } - - case 0x3F:{// CCF - flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) + - (flags << 4 & H10) + - (r.b.a & (F20 | F08)); - goto loop; - } - - case 0x37: // SCF - flags = (flags & (S80 | Z40 | P04)) | C01 + - (r.b.a & (F20 | F08)); - goto loop; - - case 0xDB: // IN A,(imm) - pc++; - r.b.a = IN_PORT( (data + r.b.a * 0x100) ); - goto loop; - - case 0xE3:{// EX (SP),HL - int temp = READ_WORD( sp ); - WRITE_WORD( sp, r.w.hl ); - r.w.hl = temp; - goto loop; - } - - case 0xEB: // EX DE,HL - EX( r.w.hl, r.w.de ); - goto loop; - - case 0xD9: // EXX DE,HL - EXX( w.bc ); - EXX( w.de ); - EXX( w.hl ); - goto loop; - - case 0xF3: // DI - R.iff1 = 0; - R.iff2 = 0; - goto loop; - - case 0xFB: // EI - R.iff1 = 1; - R.iff2 = 1; - // TODO: delayed effect - goto loop; - - case 0x76: // HALT - goto halt; - -//////////////////////////////////////// CB prefix - { - case 0xCB: - pc++; - switch ( data ) - { - - // Rotate left - - #define RLC( read, write ) {\ - int result = read;\ - result = BYTE( result << 1 ) + (result >> 7);\ - flags = SZ28P( result ) + (result & C01);\ - write;\ - goto loop;\ - } - - case 0x06: // RLC (HL) - s_time += 7; - data = r.w.hl; - rlc_data_addr: - RLC( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r - byte& reg = R8( data, 0 ); - RLC( reg, reg = result ) - } - - #define RL( read, write ) {\ - int result = (read << 1) + (flags & C01);\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x16: // RL (HL) - s_time += 7; - data = r.w.hl; - rl_data_addr: - RL( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r - byte& reg = R8( data, 0x10 ); - RL( reg, reg = result ) - } - - #define SLA( read, low_bit, write ) {\ - int result = (read << 1) + low_bit;\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x26: // SLA (HL) - s_time += 7; - data = r.w.hl; - sla_data_addr: - SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) ) - - CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r - byte& reg = R8( data, 0x20 ); - SLA( reg, 0, reg = result ) - } - - case 0x36: // SLL (HL) - s_time += 7; - data = r.w.hl; - sll_data_addr: - SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) ) - - CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r - byte& reg = R8( data, 0x30 ); - SLA( reg, 1, reg = result ) - } - - // Rotate right - - #define RRC( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result = BYTE( result << 7 ) + (result >> 1);\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x0E: // RRC (HL) - s_time += 7; - data = r.w.hl; - rrc_data_addr: - RRC( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r - byte& reg = R8( data, 0x08 ); - RRC( reg, reg = result ) - } - - #define RR( read, write ) {\ - int result = read;\ - int temp = result & C01;\ - result = BYTE( flags << 7 ) + (result >> 1);\ - flags = SZ28P( result ) + temp;\ - write;\ - goto loop;\ - } - - case 0x1E: // RR (HL) - s_time += 7; - data = r.w.hl; - rr_data_addr: - RR( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r - byte& reg = R8( data, 0x18 ); - RR( reg, reg = result ) - } - - #define SRA( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result = (result & 0x80) + (result >> 1);\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x2E: // SRA (HL) - data = r.w.hl; - s_time += 7; - sra_data_addr: - SRA( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r - byte& reg = R8( data, 0x28 ); - SRA( reg, reg = result ) - } - - #define SRL( read, write ) {\ - int result = read;\ - flags = result & C01;\ - result >>= 1;\ - flags += SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x3E: // SRL (HL) - s_time += 7; - data = r.w.hl; - srl_data_addr: - SRL( READ_MEM( data ), WRITE_MEM( data, result ) ) - - CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r - byte& reg = R8( data, 0x38 ); - SRL( reg, reg = result ) - } - - // BIT - { - int temp; - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) - s_time += 4; - temp = READ_MEM( r.w.hl ); - flags &= C01; - goto bit_temp; - CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r - CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r - CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r - CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r - CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r - CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r - CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r - temp = R8( data & 7, 0 ); - flags = (flags & C01) + (temp & (F20 | F08)); - bit_temp: - temp = temp & (1 << (data >> 3 & 7)); - flags += (temp & S80) + H10; - flags += (unsigned) --temp >> 8 & (Z40 | P04); - goto loop; - } - - // SET/RES - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) - s_time += 7; - int temp = READ_MEM( r.w.hl ); - int bit = 1 << (data >> 3 & 7); - temp |= bit; // SET - if ( !(data & 0x40) ) - temp ^= bit; // RES - WRITE_MEM( r.w.hl, temp ); - goto loop; - } - - CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r - CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r - CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r - CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r - CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r - CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r - CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r - CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r - R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); - goto loop; - - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r - CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r - CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r - R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); - goto loop; - } - assert( false ); - } - -#undef GET_ADDR -#define GET_ADDR() GET_LE16( &INSTR( 1, pc ) ) - -//////////////////////////////////////// ED prefix - { - case 0xED: - pc++; - s_time += (clock_table + 256) [data] >> 4; - switch ( data ) - { - { - int temp; - case 0x72: // SBC HL,SP - case 0x7A: // ADC HL,SP - temp = sp; - if ( 0 ) - case 0x42: // SBC HL,BC - case 0x52: // SBC HL,DE - case 0x62: // SBC HL,HL - case 0x4A: // ADC HL,BC - case 0x5A: // ADC HL,DE - case 0x6A: // ADC HL,HL - temp = R16( data >> 3 & 6, 1, 0 ); - int sum = temp + (flags & C01); - flags = ~data >> 2 & N02; - if ( flags ) - sum = -sum; - sum += r.w.hl; - temp ^= r.w.hl; - temp ^= sum; - flags +=(sum >> 16 & C01) + - (temp >> 8 & H10) + - (sum >> 8 & (S80 | F20 | F08)) + - ((temp + 0x8000) >> 14 & V04); - r.w.hl = sum; - if ( WORD( sum ) ) - goto loop; - flags += Z40; - goto loop; - } - - CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) - int temp = IN_PORT( r.w.bc ); - R8( data >> 3, 8 ) = temp; - flags = (flags & C01) + SZ28P( temp ); - goto loop; - } - - case 0x71: // OUT (C),0 - r.b.flags = 0; - CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r - OUT_PORT( r.w.bc, R8( data >> 3, 8 ) ); - goto loop; - - { - int temp; - case 0x73: // LD (ADDR),SP - temp = sp; - if ( 0 ) - case 0x43: // LD (ADDR),BC - case 0x53: // LD (ADDR),DE - temp = R16( data, 4, 0x43 ); - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, temp ); - goto loop; - } - - case 0x4B: // LD BC,(ADDR) - case 0x5B:{// LD DE,(ADDR) - int addr = GET_ADDR(); - pc += 2; - R16( data, 4, 0x4B ) = READ_WORD( addr ); - goto loop; - } - - case 0x7B:{// LD SP,(ADDR) - int addr = GET_ADDR(); - pc += 2; - sp = READ_WORD( addr ); - goto loop; - } - - case 0x67:{// RRD - int temp = READ_MEM( r.w.hl ); - WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) ); - temp = (r.b.a & 0xF0) + (temp & 0x0F); - flags = (flags & C01) + SZ28P( temp ); - r.b.a = temp; - goto loop; - } - - case 0x6F:{// RLD - int temp = READ_MEM( r.w.hl ); - WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) ); - temp = (r.b.a & 0xF0) + (temp >> 4); - flags = (flags & C01) + SZ28P( temp ); - r.b.a = temp; - goto loop; - } - - CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG - opcode = 0x10; // flag to do SBC instead of ADC - flags &= ~C01; - data = r.b.a; - r.b.a = 0; - goto adc_data; - - { - int inc; - case 0xA9: // CPD - case 0xB9: // CPDR - inc = -1; - if ( 0 ) - case 0xA1: // CPI - case 0xB1: // CPIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - int result = r.b.a - temp; - flags = (flags & C01) + N02 + - ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10)); - - if ( !BYTE( result ) ) - flags += Z40; - result -= (flags & H10) >> 4; - flags += result & F08; - flags += result << 4 & F20; - if ( !--r.w.bc ) - goto loop; - - flags += V04; - if ( flags & Z40 || data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xA8: // LDD - case 0xB8: // LDDR - inc = -1; - if ( 0 ) - case 0xA0: // LDI - case 0xB0: // LDIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - addr = r.w.de; - r.w.de = addr + inc; - WRITE_MEM( addr, temp ); - - temp += r.b.a; - flags = (flags & (S80 | Z40 | C01)) + - (temp & F08) + (temp << 4 & F20); - if ( !--r.w.bc ) - goto loop; - - flags += V04; - if ( data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xAB: // OUTD - case 0xBB: // OTDR - inc = -1; - if ( 0 ) - case 0xA3: // OUTI - case 0xB3: // OTIR - inc = +1; - int addr = r.w.hl; - r.w.hl = addr + inc; - int temp = READ_MEM( addr ); - - int b = --r.b.b; - flags = (temp >> 6 & N02) + SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - OUT_PORT( r.w.bc, temp ); - goto loop; - } - - { - int inc; - case 0xAA: // IND - case 0xBA: // INDR - inc = -1; - if ( 0 ) - case 0xA2: // INI - case 0xB2: // INIR - inc = +1; - - int addr = r.w.hl; - r.w.hl = addr + inc; - - int temp = IN_PORT( r.w.bc ); - - int b = --r.b.b; - flags = (temp >> 6 & N02) + SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - WRITE_MEM( addr, temp ); - goto loop; - } - - case 0x47: // LD I,A - R.i = r.b.a; - goto loop; - - case 0x4F: // LD R,A - SET_R( r.b.a ); - dprintf( "LD R,A not supported\n" ); - warning = true; - goto loop; - - case 0x57: // LD A,I - r.b.a = R.i; - goto ld_ai_common; - - case 0x5F: // LD A,R - r.b.a = GET_R(); - dprintf( "LD A,R not supported\n" ); - warning = true; - ld_ai_common: - flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04); - goto loop; - - CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN - R.iff1 = R.iff2; - goto ret_taken; - - case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 - R.im = 0; - goto loop; - - case 0x56: case 0x76: // IM 1 - R.im = 1; - goto loop; - - case 0x5E: case 0x7E: // IM 2 - R.im = 2; - goto loop; - - default: - dprintf( "Opcode $ED $%02X not supported\n", data ); - warning = true; - goto loop; - } - assert( false ); - } - -//////////////////////////////////////// DD/FD prefix - { - int ixy; - case 0xDD: - ixy = ix; - goto ix_prefix; - case 0xFD: - ixy = iy; - ix_prefix: - pc++; - int data2 = READ_CODE( pc ); - s_time += (clock_table + 256) [data] & 0x0F; - switch ( data ) - { - // TODO: more efficient way of avoid negative address - // TODO: avoid using this as argument to READ_MEM() since it is evaluated twice - #define IXY_DISP( ixy, disp ) WORD( (ixy ) + (disp)) - - #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; - - // ADD/ADC/SUB/SBC - - case 0x96: // SUB (IXY+disp) - case 0x86: // ADD (IXY+disp) - flags &= ~C01; - case 0x9E: // SBC (IXY+disp) - case 0x8E: // ADC (IXY+disp) - pc++; - opcode = data; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto adc_data; - - case 0x94: // SUB HXY - case 0x84: // ADD HXY - flags &= ~C01; - case 0x9C: // SBC HXY - case 0x8C: // ADC HXY - opcode = data; - data = ixy >> 8; - goto adc_data; - - case 0x95: // SUB LXY - case 0x85: // ADD LXY - flags &= ~C01; - case 0x9D: // SBC LXY - case 0x8D: // ADC LXY - opcode = data; - data = BYTE( ixy ); - goto adc_data; - - { - int temp; - case 0x39: // ADD IXY,SP - temp = sp; - goto add_ixy_data; - - case 0x29: // ADD IXY,HL - temp = ixy; - goto add_ixy_data; - - case 0x09: // ADD IXY,BC - case 0x19: // ADD IXY,DE - temp = R16( data, 4, 0x09 ); - add_ixy_data: { - int sum = ixy + temp; - temp ^= ixy; - ixy = WORD( sum ); - flags = (flags & (S80 | Z40 | V04)) + - (sum >> 16) + - (sum >> 8 & (F20 | F08)) + - ((temp ^ sum) >> 8 & H10); - goto set_ixy; - } - } - - // AND - case 0xA6: // AND (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto and_data; - - case 0xA4: // AND HXY - data = ixy >> 8; - goto and_data; - - case 0xA5: // AND LXY - data = BYTE( ixy ); - goto and_data; - - // OR - case 0xB6: // OR (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto or_data; - - case 0xB4: // OR HXY - data = ixy >> 8; - goto or_data; - - case 0xB5: // OR LXY - data = BYTE( ixy ); - goto or_data; - - // XOR - case 0xAE: // XOR (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto xor_data; - - case 0xAC: // XOR HXY - data = ixy >> 8; - goto xor_data; - - case 0xAD: // XOR LXY - data = BYTE( ixy ); - goto xor_data; - - // CP - case 0xBE: // CP (IXY+disp) - pc++; - data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto cp_data; - - case 0xBC: // CP HXY - data = ixy >> 8; - goto cp_data; - - case 0xBD: // CP LXY - data = BYTE( ixy ); - goto cp_data; - - // LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r - data = R8( data, 0x70 ); - if ( 0 ) - case 0x36: // LD (IXY+disp),imm - pc++, data = READ_CODE( pc ); - pc++; - WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data ); - goto loop; - - CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY - R8( data >> 3, 8 ) = ixy >> 8; - goto loop; - - case 0x64: // LD HXY,HXY - case 0x6D: // LD LXY,LXY - goto loop; - - CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY - R8( data >> 3, 8 ) = ixy; - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) - pc++; - R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); - goto loop; - - case 0x26: // LD HXY,imm - pc++; - goto ld_hxy_data; - - case 0x65: // LD HXY,LXY - data2 = BYTE( ixy ); - goto ld_hxy_data; - - CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r - data2 = R8( data, 0x60 ); - ld_hxy_data: - ixy = BYTE( ixy ) + (data2 << 8); - goto set_ixy; - - case 0x2E: // LD LXY,imm - pc++; - goto ld_lxy_data; - - case 0x6C: // LD LXY,HXY - data2 = ixy >> 8; - goto ld_lxy_data; - - CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r - data2 = R8( data, 0x68 ); - ld_lxy_data: - ixy = (ixy & 0xFF00) + data2; - set_ixy: - if ( opcode == 0xDD ) - { - ix = ixy; - goto loop; - } - iy = ixy; - goto loop; - - case 0xF9: // LD SP,IXY - sp = ixy; - goto loop; - - case 0x22:{// LD (ADDR),IXY - int addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, ixy ); - goto loop; - } - - case 0x21: // LD IXY,imm - ixy = GET_ADDR(); - pc += 2; - goto set_ixy; - - case 0x2A:{// LD IXY,(addr) - int addr = GET_ADDR(); - ixy = READ_WORD( addr ); - pc += 2; - goto set_ixy; - } - - // DD/FD CB prefix - case 0xCB: { - data = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data2 = READ_CODE( pc ); - pc++; - switch ( data2 ) - { - case 0x06: goto rlc_data_addr; // RLC (IXY) - case 0x16: goto rl_data_addr; // RL (IXY) - case 0x26: goto sla_data_addr; // SLA (IXY) - case 0x36: goto sll_data_addr; // SLL (IXY) - case 0x0E: goto rrc_data_addr; // RRC (IXY) - case 0x1E: goto rr_data_addr; // RR (IXY) - case 0x2E: goto sra_data_addr; // SRA (IXY) - case 0x3E: goto srl_data_addr; // SRL (IXY) - - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) - int temp = READ_MEM( data ); - temp = temp & (1 << (data2 >> 3 & 7)); - flags = (flags & C01) + H10 + (temp & S80); - flags += (unsigned) --temp >> 8 & (Z40 | P04); - goto loop; - } - - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) - int temp = READ_MEM( data ); - int bit = 1 << (data2 >> 3 & 7); - temp |= bit; // SET - if ( !(data2 & 0x40) ) - temp ^= bit; // RES - WRITE_MEM( data, temp ); - goto loop; - } - - default: - dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); - warning = true; - goto loop; - } - assert( false ); - } - - // INC/DEC - case 0x23: // INC IXY - ixy = WORD( ixy + 1 ); - goto set_ixy; - - case 0x2B: // DEC IXY - ixy = WORD( ixy - 1 ); - goto set_ixy; - - case 0x34: // INC (IXY+disp) - ixy = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data = READ_MEM( ixy ) + 1; - WRITE_MEM( ixy, data ); - goto inc_set_flags; - - case 0x35: // DEC (IXY+disp) - ixy = IXY_DISP( ixy, SBYTE( data2 ) ); - pc++; - data = READ_MEM( ixy ) - 1; - WRITE_MEM( ixy, data ); - goto dec_set_flags; - - case 0x24: // INC HXY - ixy = WORD( ixy + 0x100 ); - data = ixy >> 8; - goto inc_xy_common; - - case 0x2C: // INC LXY - data = BYTE( ixy + 1 ); - ixy = (ixy & 0xFF00) + data; - inc_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto inc_set_flags; - } - iy = ixy; - goto inc_set_flags; - - case 0x25: // DEC HXY - ixy = WORD( ixy - 0x100 ); - data = ixy >> 8; - goto dec_xy_common; - - case 0x2D: // DEC LXY - data = BYTE( ixy - 1 ); - ixy = (ixy & 0xFF00) + data; - dec_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto dec_set_flags; - } - iy = ixy; - goto dec_set_flags; - - // PUSH/POP - case 0xE5: // PUSH IXY - data = ixy; - goto push_data; - - case 0xE1:{// POP IXY - ixy = READ_WORD( sp ); - sp = WORD( sp + 2 ); - goto set_ixy; - } - - // Misc - - case 0xE9: // JP (IXY) - pc = ixy; - goto loop; - - case 0xE3:{// EX (SP),IXY - int temp = READ_WORD( sp ); - WRITE_WORD( sp, ixy ); - ixy = temp; - goto set_ixy; - } - - default: - dprintf( "Unnecessary DD/FD prefix encountered\n" ); - warning = true; - pc--; - goto loop; - } - assert( false ); - } - - } - dprintf( "Unhandled main opcode: $%02X\n", opcode ); - assert( false ); - -#ifdef IDLE_ADDR -hit_idle_addr: - s_time -= 11; - goto out_of_time; -#endif -halt: - s_time &= 3; // increment by multiple of 4 -out_of_time: - pc--; - - r.b.flags = flags; - R.ix = ix; - R.iy = iy; - R.sp = sp; - R.pc = pc; - R.b = r.b; - - CPU.cpu_state_.base = s.base; - CPU.cpu_state_.time = s_time; - CPU.cpu_state = &CPU.cpu_state_; -} +// $package. http://www.slack.net/~ant/ + +// Last validated with zexall 2009.12.05. +// Doesn't implement the R register or immediate interrupt after EI. +// Address wrap-around isn't completely correct, but is prevented from crashing emulator. +// 16-bit memory accesses are made directly to mapped memory, instead of using macro. + +#if 0 +/* Define these macros in the source file before #including this file. +- Parameters might be expressions, so they are best evaluated only once, +though they NEVER have side-effects, so multiple evaluation is OK. +- Output parameters might be a multiple-assignment expression like "a=x", +so they must NOT be parenthesized. +- Except where noted, time() and related functions will NOT work +correctly inside a macro. TIME() is always correct, and between FLUSH_TIME() and +CACHE_TIME() the normal time changing functions can be used. +- Macros "returning" void may use a {} statement block. */ + + // 0 <= addr <= 0xFFFF + 0x100 + // Optional; default uses whatever was set with map_mem() + int READ_CODE( addr_t ); + + // 0 <= addr <= 0xFFFF + 0x100 + // Optional; default uses whatever was set with map_mem() + int READ_MEM( addr_t ); + void WRITE_MEM( addr_t, int data ); + + // 0 <= port <= 0xFFFF (apparently upper 8 bits are output by hardware) + void OUT_PORT( int port, int data ); + int IN_PORT int port ); + + // Reference to Z80_Cpu object used for emulation + #define CPU cpu + +// The following can be used within macros: + + // Current time + time_t TIME(); + + // Allows use of time functions + void FLUSH_TIME(); + + // Must be used before end of macro if FLUSH_TIME() was used earlier + void CACHE_TIME(); + +// Configuration (optional; commented behavior if defined) + + // Optimizes as if map_mem( 0, 0x10000, FLAT_MEM, FLAT_MEM ) is always in effect + #define FLAT_MEM my_mem_array + + // If RST 7 ($FF) is encountered and PC = IDLE_ADDR, stops execution + #define IDLE_ADDR 0x1234 + + // Expanded just before beginning of code, to help debugger + #define CPU_BEGIN void my_run_cpu() { + +#endif + +/* Copyright (C) 2006-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifdef CPU_BEGIN + CPU_BEGIN +#endif + +#define R CPU.r + +// flags, named with hex value for clarity +int const S80 = 0x80; +int const Z40 = 0x40; +int const F20 = 0x20; +int const H10 = 0x10; +int const F08 = 0x08; +int const V04 = 0x04; +int const P04 = 0x04; +int const N02 = 0x02; +int const C01 = 0x01; + +#define SZ28P( n ) CPU.szpc [n] +#define SZ28PC( n ) CPU.szpc [n] +#define SZ28C( n ) (CPU.szpc [n] & ~P04) +#define SZ28( n ) SZ28C( n ) + +#define SET_R( n ) (void) (R.r = n) +#define GET_R() (R.r) + +// Time +#define TIME() (s_time + s.base) +#define FLUSH_TIME() {s.time = s_time;} +#define CACHE_TIME() {s_time = s.time;} + +// Memory +#define RW_MEM( addr, rw ) RW_PAGE( addr, rw ) [RW_OFFSET( addr )] +#ifndef READ_CODE + #define READ_CODE( addr ) RW_MEM( addr, read ) +#endif + +#ifdef FLAT_MEM + #define RW_PAGE( addr, rw ) FLAT_MEM + #define RW_OFFSET( addr ) (addr) + #define INSTR( off, addr ) READ_CODE( addr ) +#else + #define RW_PAGE( addr, rw ) s.rw [(unsigned) (addr) >> Z80_Cpu::page_bits] + #define RW_OFFSET( addr ) Z80_CPU_OFFSET( addr ) + #define INSTR( off, addr ) instr [off] +#endif + +#ifndef READ_MEM + #define READ_MEM( addr ) RW_MEM( addr, read ) +#endif + +#ifndef WRITE_MEM + #define WRITE_MEM( addr, data ) (RW_MEM( addr, write ) = data) +#endif + +#define READ_WORD( addr ) GET_LE16( &RW_MEM( addr, read ) ) +#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data ) + +// Truncation +#define BYTE( n ) ((BOOST::uint8_t ) (n)) /* (unsigned) n & 0xFF */ +#define SBYTE( n ) ((BOOST::int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ +#define WORD( n ) ((BOOST::uint16_t) (n)) /* (unsigned) n & 0xFFFF */ + +// Misc +#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e +#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f +#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g +#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h + +#if BLARGG_BIG_ENDIAN + #define R8( n, offset ) ((r.r8_ - offset) [n]) +#elif BLARGG_LITTLE_ENDIAN + #define R8( n, offset ) ((r.r8_ - offset) [(n) ^ 1]) +#else + #error "Byte order of CPU must be known" +#endif + +#define R16( n, shift, offset ) (r.r16_ [((unsigned) (n) >> shift) - (offset >> shift)]) + +#define EX( x, y ) \ + {\ + int temp = x;\ + x = y;\ + y = temp;\ + } + +#define EXX( name ) \ + EX( R.alt.name, r.name ) + +bool warning = false; +{ + Z80_Cpu::cpu_state_t s; + #ifdef FLAT_MEM + s.base = CPU.cpu_state_.base; + #else + s = CPU.cpu_state_; + #endif + CPU.cpu_state = &s; + + + union r_t { + Z80_Cpu::regs_t b; + Z80_Cpu::pairs_t w; + byte r8_ [8]; // indexed + BOOST::uint16_t r16_ [4]; + } r; + r.b = R.b; + + Z80_Cpu::time_t s_time = CPU.cpu_state_.time; + int pc = R.pc; + int sp = R.sp; + int ix = R.ix; // TODO: keep in memory for direct access? + int iy = R.iy; + int flags = R.b.flags; + + //goto loop; // confuses optimizer + s_time += 7; + pc -= 2; + +call_not_taken: + s_time -= 7; +jp_not_taken: + pc += 2; +loop: + + check( (unsigned) pc < 0x10000 + 1 ); // +1 so emulator can catch wrap-around + check( (unsigned) sp < 0x10000 ); + check( (unsigned) flags < 0x100 ); + check( (unsigned) ix < 0x10000 ); + check( (unsigned) iy < 0x10000 ); + + byte const* instr = RW_PAGE( pc, read ); + + int opcode; + + if ( RW_OFFSET( ~0 ) == ~0 ) + { + opcode = instr [RW_OFFSET( pc )]; + pc++; + instr += RW_OFFSET( pc ); + } + else + { + instr += RW_OFFSET( pc ); + opcode = *instr++; + pc++; + } + + static byte const clock_table [256 * 2] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 + 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 + 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, // 2 + 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, // 3 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 + 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B + 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C + 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D + 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E + 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F + + // high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, + 0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, + 0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, + 0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, + 0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, + 0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + }; + + if ( s_time >= 0 ) + goto out_of_time; + s_time += clock_table [opcode]; + + #ifdef Z80_CPU_LOG_H + //log_opcode( opcode, READ_CODE( pc ) ); + z80_cpu_log( "log.txt", pc - 1, opcode, READ_CODE( pc ), + READ_CODE( pc + 1 ), READ_CODE( pc + 2 ) ); + z80_log_regs( r.b.a, r.w.bc, r.w.de, r.w.hl, sp, ix, iy ); + #endif + +#define GET_ADDR() GET_LE16( &INSTR( 0, pc ) ) + + int data; + data = INSTR( 0, pc ); + + switch ( opcode ) + { +// Common + + case 0x00: // NOP + CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. + goto loop; + + case 0x08:{// EX AF,AF' + EXX( b.a ); + EX( R.alt.b.flags, flags ); + goto loop; + } + + case 0xD3: // OUT (imm),A + pc++; + OUT_PORT( (data + r.b.a * 0x100), r.b.a ); + goto loop; + + case 0x2E: // LD L,imm + pc++; + r.b.l = data; + goto loop; + + case 0x3E: // LD A,imm + pc++; + r.b.a = data; + goto loop; + + case 0x3A:{// LD A,(addr) + int addr = GET_ADDR(); + pc += 2; + r.b.a = READ_MEM( addr ); + goto loop; + } + +// Conditional + +#define ZERO (flags & Z40) +#define CARRY (flags & C01) +#define EVEN (flags & P04) +#define MINUS (flags & S80) + +// JR +// TODO: more efficient way to handle negative branch that wraps PC around +#define JR_( cond, clocks ) {\ + pc++;\ + if ( !(cond) )\ + goto loop;\ + int offset = SBYTE( data );\ + pc = WORD( pc + offset );\ + s_time += clocks;\ + goto loop;\ +} + +#define JR( cond ) JR_( cond, 5 ) + + case 0x20: JR( !ZERO ) // JR NZ,disp + case 0x28: JR( ZERO ) // JR Z,disp + case 0x30: JR( !CARRY ) // JR NC,disp + case 0x38: JR( CARRY ) // JR C,disp + case 0x18: JR_( true,0) // JR disp + + case 0x10:{// DJNZ disp + int temp = r.b.b - 1; + r.b.b = temp; + JR( temp ) + } + +// JP +#define JP( cond ) \ + if ( !(cond) )\ + goto jp_not_taken;\ + pc = GET_ADDR();\ + goto loop; + + case 0xC2: JP( !ZERO ) // JP NZ,addr + case 0xCA: JP( ZERO ) // JP Z,addr + case 0xD2: JP( !CARRY ) // JP NC,addr + case 0xDA: JP( CARRY ) // JP C,addr + case 0xE2: JP( !EVEN ) // JP PO,addr + case 0xEA: JP( EVEN ) // JP PE,addr + case 0xF2: JP( !MINUS ) // JP P,addr + case 0xFA: JP( MINUS ) // JP M,addr + + case 0xC3: // JP addr + pc = GET_ADDR(); + goto loop; + + case 0xE9: // JP HL + pc = r.w.hl; + goto loop; + +// RET +#define RET( cond ) \ + if ( cond )\ + goto ret_taken;\ + s_time -= 6;\ + goto loop; + + case 0xC0: RET( !ZERO ) // RET NZ + case 0xC8: RET( ZERO ) // RET Z + case 0xD0: RET( !CARRY ) // RET NC + case 0xD8: RET( CARRY ) // RET C + case 0xE0: RET( !EVEN ) // RET PO + case 0xE8: RET( EVEN ) // RET PE + case 0xF0: RET( !MINUS ) // RET P + case 0xF8: RET( MINUS ) // RET M + + case 0xC9: // RET + ret_taken: + pc = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto loop; + +// CALL +#define CALL( cond ) \ + if ( cond )\ + goto call_taken;\ + goto call_not_taken; + + case 0xC4: CALL( !ZERO ) // CALL NZ,addr + case 0xCC: CALL( ZERO ) // CALL Z,addr + case 0xD4: CALL( !CARRY ) // CALL NC,addr + case 0xDC: CALL( CARRY ) // CALL C,addr + case 0xE4: CALL( !EVEN ) // CALL PO,addr + case 0xEC: CALL( EVEN ) // CALL PE,addr + case 0xF4: CALL( !MINUS ) // CALL P,addr + case 0xFC: CALL( MINUS ) // CALL M,addr + + case 0xCD:{// CALL addr + call_taken: + int addr = pc + 2; + pc = GET_ADDR(); + sp = WORD( sp - 2 ); + WRITE_WORD( sp, addr ); + goto loop; + } + + case 0xFF: // RST + #ifdef IDLE_ADDR + if ( pc == IDLE_ADDR + 1 ) + goto hit_idle_addr; + #else + if ( pc > 0x10000 ) + { + pc = WORD( pc - 1 ); + s_time -= 11; + goto loop; + } + #endif + CASE7( C7, CF, D7, DF, E7, EF, F7 ): + data = pc; + pc = opcode & 0x38; + #ifdef RST_BASE + pc += RST_BASE; + #endif + goto push_data; + +// PUSH/POP + case 0xF5: // PUSH AF + data = r.b.a * 0x100u + flags; + goto push_data; + + case 0xC5: // PUSH BC + case 0xD5: // PUSH DE + case 0xE5: // PUSH HL + data = R16( opcode, 4, 0xC5 ); + push_data: + sp = WORD( sp - 2 ); + WRITE_WORD( sp, data ); + goto loop; + + case 0xF1: // POP AF + flags = READ_MEM( sp ); + r.b.a = READ_MEM( (sp + 1) ); + sp = WORD( sp + 2 ); + goto loop; + + case 0xC1: // POP BC + case 0xD1: // POP DE + case 0xE1: // POP HL + R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto loop; + +// ADC/ADD/SBC/SUB + case 0x96: // SUB (HL) + case 0x86: // ADD (HL) + flags &= ~C01; + case 0x9E: // SBC (HL) + case 0x8E: // ADC (HL) + data = READ_MEM( r.w.hl ); + goto adc_data; + + case 0xD6: // SUB A,imm + case 0xC6: // ADD imm + flags &= ~C01; + case 0xDE: // SBC A,imm + case 0xCE: // ADC imm + pc++; + goto adc_data; + + CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r + CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r + flags &= ~C01; + CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r + CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r + data = R8( opcode & 7, 0 ); + adc_data: { + int result = data + (flags & C01); + data ^= r.b.a; + flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes + if ( flags ) + result = -result; + result += r.b.a; + data ^= result; + flags +=(data & H10) + + ((data + 0x80) >> 6 & V04) + + SZ28C( result & 0x1FF ); + r.b.a = result; + goto loop; + } + +// CP + case 0xBE: // CP (HL) + data = READ_MEM( r.w.hl ); + goto cp_data; + + case 0xFE: // CP imm + pc++; + goto cp_data; + + CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r + data = R8( opcode, 0xB8 ); + cp_data: { + int result = r.b.a - data; + flags = N02 + (data & (F20 | F08)) + (result >> 8 & C01); + data ^= r.b.a; + flags +=(((result ^ r.b.a) & data) >> 5 & V04) + + (((data & H10) ^ result) & (S80 | H10)); + if ( BYTE( result ) ) + goto loop; + flags += Z40; + goto loop; + } + +// ADD HL,r.w + + case 0x39: // ADD HL,SP + data = sp; + goto add_hl_data; + + case 0x09: // ADD HL,BC + case 0x19: // ADD HL,DE + case 0x29: // ADD HL,HL + data = R16( opcode, 4, 0x09 ); + add_hl_data: { + int sum = r.w.hl + data; + data ^= r.w.hl; + r.w.hl = sum; + flags = (flags & (S80 | Z40 | V04)) + + (sum >> 16) + + (sum >> 8 & (F20 | F08)) + + ((data ^ sum) >> 8 & H10); + goto loop; + } + + case 0x27:{// DAA + int a = r.b.a; + if ( a > 0x99 ) + flags |= C01; + + int adjust = 0x60 * (flags & C01); + + if ( flags & H10 || (a & 0x0F) > 9 ) + adjust += 0x06; + + if ( flags & N02 ) + adjust = -adjust; + a += adjust; + + flags = (flags & (C01 | N02)) + + ((r.b.a ^ a) & H10) + + SZ28P( BYTE( a ) ); + r.b.a = a; + goto loop; + } + +// INC/DEC + case 0x34: // INC (HL) + data = READ_MEM( r.w.hl ) + 1; + WRITE_MEM( r.w.hl, data ); + goto inc_set_flags; + + CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r + data = ++R8( opcode >> 3, 0 ); + inc_set_flags: + flags = (flags & C01) + + (((data & 0x0F) - 1) & H10) + + SZ28( BYTE( data ) ); + if ( data != 0x80 ) + goto loop; + flags += V04; + goto loop; + + case 0x35: // DEC (HL) + data = READ_MEM( r.w.hl ) - 1; + WRITE_MEM( r.w.hl, data ); + goto dec_set_flags; + + CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r + data = --R8( opcode >> 3, 0 ); + dec_set_flags: + flags = (flags & C01) + N02 + + (((data & 0x0F) + 1) & H10) + + SZ28( BYTE( data ) ); + if ( data != 0x7F ) + goto loop; + flags += V04; + goto loop; + + case 0x03: // INC BC + case 0x13: // INC DE + case 0x23: // INC HL + R16( opcode, 4, 0x03 )++; + goto loop; + + case 0x33: // INC SP + sp = WORD( sp + 1 ); + goto loop; + + case 0x0B: // DEC BC + case 0x1B: // DEC DE + case 0x2B: // DEC HL + R16( opcode, 4, 0x0B )--; + goto loop; + + case 0x3B: // DEC SP + sp = WORD( sp - 1 ); + goto loop; + +// AND + case 0xA6: // AND (HL) + data = READ_MEM( r.w.hl ); + goto and_data; + + case 0xE6: // AND imm + pc++; + goto and_data; + + CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r + data = R8( opcode, 0xA0 ); + and_data: + r.b.a &= data; + flags = SZ28P( r.b.a ) + H10; + goto loop; + +// OR + case 0xB6: // OR (HL) + data = READ_MEM( r.w.hl ); + goto or_data; + + case 0xF6: // OR imm + pc++; + goto or_data; + + CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r + data = R8( opcode, 0xB0 ); + or_data: + r.b.a |= data; + flags = SZ28P( r.b.a ); + goto loop; + +// XOR + case 0xAE: // XOR (HL) + data = READ_MEM( r.w.hl ); + goto xor_data; + + case 0xEE: // XOR imm + pc++; + goto xor_data; + + CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r + data = R8( opcode, 0xA8 ); + xor_data: + r.b.a ^= data; + flags = SZ28P( r.b.a ); + goto loop; + +// LD + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r + WRITE_MEM( r.w.hl, R8( opcode, 0x70 ) ); + goto loop; + + CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r + CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r + CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r + CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r + CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r + CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r + CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r + R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); + goto loop; + + CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm + R8( opcode >> 3, 0 ) = data; + pc++; + goto loop; + + case 0x36: // LD (HL),imm + pc++; + WRITE_MEM( r.w.hl, data ); + goto loop; + + CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) + R8( opcode >> 3, 8 ) = READ_MEM( r.w.hl ); + goto loop; + + case 0x01: // LD r.w,imm + case 0x11: + case 0x21: + R16( opcode, 4, 0x01 ) = GET_ADDR(); + pc += 2; + goto loop; + + case 0x31: // LD sp,imm + sp = GET_ADDR(); + pc += 2; + goto loop; + + case 0x2A:{// LD HL,(addr) + int addr = GET_ADDR(); + pc += 2; + r.w.hl = READ_WORD( addr ); + goto loop; + } + + case 0x32:{// LD (addr),A + int addr = GET_ADDR(); + pc += 2; + WRITE_MEM( addr, r.b.a ); + goto loop; + } + + case 0x22:{// LD (addr),HL + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, r.w.hl ); + goto loop; + } + + case 0x02: // LD (BC),A + case 0x12: // LD (DE),A + WRITE_MEM( R16( opcode, 4, 0x02 ), r.b.a ); + goto loop; + + case 0x0A: // LD A,(BC) + case 0x1A: // LD A,(DE) + r.b.a = READ_MEM( R16( opcode, 4, 0x0A ) ); + goto loop; + + case 0xF9: // LD SP,HL + sp = r.w.hl; + goto loop; + +// Rotate + + case 0x07:{// RLCA + int temp = r.b.a; + temp = (temp << 1) + (temp >> 7); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08 | C01)); + r.b.a = temp; + goto loop; + } + + case 0x0F:{// RRCA + int temp = r.b.a; + flags = (flags & (S80 | Z40 | P04)) + + (temp & C01); + temp = (temp << 7) + (temp >> 1); + flags += temp & (F20 | F08); + r.b.a = temp; + goto loop; + } + + case 0x17:{// RLA + int temp = (r.b.a << 1) + (flags & C01); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08)) + + (temp >> 8); + r.b.a = temp; + goto loop; + } + + case 0x1F:{// RRA + int temp = (flags << 7) + (r.b.a >> 1); + flags = (flags & (S80 | Z40 | P04)) + + (temp & (F20 | F08)) + + (r.b.a & C01); + r.b.a = temp; + goto loop; + } + +// Misc + case 0x2F:{// CPL + int temp = ~r.b.a; + flags = (flags & (S80 | Z40 | P04 | C01)) + + (temp & (F20 | F08)) + + (H10 | N02); + r.b.a = temp; + goto loop; + } + + case 0x3F:{// CCF + flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) + + (flags << 4 & H10) + + (r.b.a & (F20 | F08)); + goto loop; + } + + case 0x37: // SCF + flags = (flags & (S80 | Z40 | P04)) | C01 + + (r.b.a & (F20 | F08)); + goto loop; + + case 0xDB: // IN A,(imm) + pc++; + r.b.a = IN_PORT( (data + r.b.a * 0x100) ); + goto loop; + + case 0xE3:{// EX (SP),HL + int temp = READ_WORD( sp ); + WRITE_WORD( sp, r.w.hl ); + r.w.hl = temp; + goto loop; + } + + case 0xEB: // EX DE,HL + EX( r.w.hl, r.w.de ); + goto loop; + + case 0xD9: // EXX DE,HL + EXX( w.bc ); + EXX( w.de ); + EXX( w.hl ); + goto loop; + + case 0xF3: // DI + R.iff1 = 0; + R.iff2 = 0; + goto loop; + + case 0xFB: // EI + R.iff1 = 1; + R.iff2 = 1; + // TODO: delayed effect + goto loop; + + case 0x76: // HALT + goto halt; + +//////////////////////////////////////// CB prefix + { + case 0xCB: + pc++; + switch ( data ) + { + + // Rotate left + + #define RLC( read, write ) {\ + int result = read;\ + result = BYTE( result << 1 ) + (result >> 7);\ + flags = SZ28P( result ) + (result & C01);\ + write;\ + goto loop;\ + } + + case 0x06: // RLC (HL) + s_time += 7; + data = r.w.hl; + rlc_data_addr: + RLC( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r + byte& reg = R8( data, 0 ); + RLC( reg, reg = result ) + } + + #define RL( read, write ) {\ + int result = (read << 1) + (flags & C01);\ + flags = SZ28PC( result );\ + write;\ + goto loop;\ + } + + case 0x16: // RL (HL) + s_time += 7; + data = r.w.hl; + rl_data_addr: + RL( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r + byte& reg = R8( data, 0x10 ); + RL( reg, reg = result ) + } + + #define SLA( read, low_bit, write ) {\ + int result = (read << 1) + low_bit;\ + flags = SZ28PC( result );\ + write;\ + goto loop;\ + } + + case 0x26: // SLA (HL) + s_time += 7; + data = r.w.hl; + sla_data_addr: + SLA( READ_MEM( data ), 0, WRITE_MEM( data, result ) ) + + CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r + byte& reg = R8( data, 0x20 ); + SLA( reg, 0, reg = result ) + } + + case 0x36: // SLL (HL) + s_time += 7; + data = r.w.hl; + sll_data_addr: + SLA( READ_MEM( data ), 1, WRITE_MEM( data, result ) ) + + CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r + byte& reg = R8( data, 0x30 ); + SLA( reg, 1, reg = result ) + } + + // Rotate right + + #define RRC( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result = BYTE( result << 7 ) + (result >> 1);\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x0E: // RRC (HL) + s_time += 7; + data = r.w.hl; + rrc_data_addr: + RRC( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r + byte& reg = R8( data, 0x08 ); + RRC( reg, reg = result ) + } + + #define RR( read, write ) {\ + int result = read;\ + int temp = result & C01;\ + result = BYTE( flags << 7 ) + (result >> 1);\ + flags = SZ28P( result ) + temp;\ + write;\ + goto loop;\ + } + + case 0x1E: // RR (HL) + s_time += 7; + data = r.w.hl; + rr_data_addr: + RR( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r + byte& reg = R8( data, 0x18 ); + RR( reg, reg = result ) + } + + #define SRA( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result = (result & 0x80) + (result >> 1);\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x2E: // SRA (HL) + data = r.w.hl; + s_time += 7; + sra_data_addr: + SRA( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r + byte& reg = R8( data, 0x28 ); + SRA( reg, reg = result ) + } + + #define SRL( read, write ) {\ + int result = read;\ + flags = result & C01;\ + result >>= 1;\ + flags += SZ28P( result );\ + write;\ + goto loop;\ + } + + case 0x3E: // SRL (HL) + s_time += 7; + data = r.w.hl; + srl_data_addr: + SRL( READ_MEM( data ), WRITE_MEM( data, result ) ) + + CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r + byte& reg = R8( data, 0x38 ); + SRL( reg, reg = result ) + } + + // BIT + { + int temp; + CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) + s_time += 4; + temp = READ_MEM( r.w.hl ); + flags &= C01; + goto bit_temp; + CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r + CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r + CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r + CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r + CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r + CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r + CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r + temp = R8( data & 7, 0 ); + flags = (flags & C01) + (temp & (F20 | F08)); + bit_temp: + temp = temp & (1 << (data >> 3 & 7)); + flags += (temp & S80) + H10; + flags += (unsigned) --temp >> 8 & (Z40 | P04); + goto loop; + } + + // SET/RES + CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) + CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) + s_time += 7; + int temp = READ_MEM( r.w.hl ); + int bit = 1 << (data >> 3 & 7); + temp |= bit; // SET + if ( !(data & 0x40) ) + temp ^= bit; // RES + WRITE_MEM( r.w.hl, temp ); + goto loop; + } + + CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r + CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r + CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r + CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r + CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r + CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r + CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r + CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r + R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); + goto loop; + + CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r + CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r + CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r + CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r + CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r + CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r + CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r + CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r + R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); + goto loop; + } + assert( false ); + } + +#undef GET_ADDR +#define GET_ADDR() GET_LE16( &INSTR( 1, pc ) ) + +//////////////////////////////////////// ED prefix + { + case 0xED: + pc++; + s_time += (clock_table + 256) [data] >> 4; + switch ( data ) + { + { + int temp; + case 0x72: // SBC HL,SP + case 0x7A: // ADC HL,SP + temp = sp; + if ( 0 ) + case 0x42: // SBC HL,BC + case 0x52: // SBC HL,DE + case 0x62: // SBC HL,HL + case 0x4A: // ADC HL,BC + case 0x5A: // ADC HL,DE + case 0x6A: // ADC HL,HL + temp = R16( data >> 3 & 6, 1, 0 ); + int sum = temp + (flags & C01); + flags = ~data >> 2 & N02; + if ( flags ) + sum = -sum; + sum += r.w.hl; + temp ^= r.w.hl; + temp ^= sum; + flags +=(sum >> 16 & C01) + + (temp >> 8 & H10) + + (sum >> 8 & (S80 | F20 | F08)) + + ((temp + 0x8000) >> 14 & V04); + r.w.hl = sum; + if ( WORD( sum ) ) + goto loop; + flags += Z40; + goto loop; + } + + CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) + int temp = IN_PORT( r.w.bc ); + R8( data >> 3, 8 ) = temp; + flags = (flags & C01) + SZ28P( temp ); + goto loop; + } + + case 0x71: // OUT (C),0 + r.b.flags = 0; + CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r + OUT_PORT( r.w.bc, R8( data >> 3, 8 ) ); + goto loop; + + { + int temp; + case 0x73: // LD (ADDR),SP + temp = sp; + if ( 0 ) + case 0x43: // LD (ADDR),BC + case 0x53: // LD (ADDR),DE + temp = R16( data, 4, 0x43 ); + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, temp ); + goto loop; + } + + case 0x4B: // LD BC,(ADDR) + case 0x5B:{// LD DE,(ADDR) + int addr = GET_ADDR(); + pc += 2; + R16( data, 4, 0x4B ) = READ_WORD( addr ); + goto loop; + } + + case 0x7B:{// LD SP,(ADDR) + int addr = GET_ADDR(); + pc += 2; + sp = READ_WORD( addr ); + goto loop; + } + + case 0x67:{// RRD + int temp = READ_MEM( r.w.hl ); + WRITE_MEM( r.w.hl, ((r.b.a << 4) + (temp >> 4)) ); + temp = (r.b.a & 0xF0) + (temp & 0x0F); + flags = (flags & C01) + SZ28P( temp ); + r.b.a = temp; + goto loop; + } + + case 0x6F:{// RLD + int temp = READ_MEM( r.w.hl ); + WRITE_MEM( r.w.hl, ((temp << 4) + (r.b.a & 0x0F)) ); + temp = (r.b.a & 0xF0) + (temp >> 4); + flags = (flags & C01) + SZ28P( temp ); + r.b.a = temp; + goto loop; + } + + CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG + opcode = 0x10; // flag to do SBC instead of ADC + flags &= ~C01; + data = r.b.a; + r.b.a = 0; + goto adc_data; + + { + int inc; + case 0xA9: // CPD + case 0xB9: // CPDR + inc = -1; + if ( 0 ) + case 0xA1: // CPI + case 0xB1: // CPIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + int result = r.b.a - temp; + flags = (flags & C01) + N02 + + ((((temp ^ r.b.a) & H10) ^ result) & (S80 | H10)); + + if ( !BYTE( result ) ) + flags += Z40; + result -= (flags & H10) >> 4; + flags += result & F08; + flags += result << 4 & F20; + if ( !--r.w.bc ) + goto loop; + + flags += V04; + if ( flags & Z40 || data < 0xB0 ) + goto loop; + + pc -= 2; + s_time += 5; + goto loop; + } + + { + int inc; + case 0xA8: // LDD + case 0xB8: // LDDR + inc = -1; + if ( 0 ) + case 0xA0: // LDI + case 0xB0: // LDIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + addr = r.w.de; + r.w.de = addr + inc; + WRITE_MEM( addr, temp ); + + temp += r.b.a; + flags = (flags & (S80 | Z40 | C01)) + + (temp & F08) + (temp << 4 & F20); + if ( !--r.w.bc ) + goto loop; + + flags += V04; + if ( data < 0xB0 ) + goto loop; + + pc -= 2; + s_time += 5; + goto loop; + } + + { + int inc; + case 0xAB: // OUTD + case 0xBB: // OTDR + inc = -1; + if ( 0 ) + case 0xA3: // OUTI + case 0xB3: // OTIR + inc = +1; + int addr = r.w.hl; + r.w.hl = addr + inc; + int temp = READ_MEM( addr ); + + int b = --r.b.b; + flags = (temp >> 6 & N02) + SZ28( b ); + if ( b && data >= 0xB0 ) + { + pc -= 2; + s_time += 5; + } + + OUT_PORT( r.w.bc, temp ); + goto loop; + } + + { + int inc; + case 0xAA: // IND + case 0xBA: // INDR + inc = -1; + if ( 0 ) + case 0xA2: // INI + case 0xB2: // INIR + inc = +1; + + int addr = r.w.hl; + r.w.hl = addr + inc; + + int temp = IN_PORT( r.w.bc ); + + int b = --r.b.b; + flags = (temp >> 6 & N02) + SZ28( b ); + if ( b && data >= 0xB0 ) + { + pc -= 2; + s_time += 5; + } + + WRITE_MEM( addr, temp ); + goto loop; + } + + case 0x47: // LD I,A + R.i = r.b.a; + goto loop; + + case 0x4F: // LD R,A + SET_R( r.b.a ); + dprintf( "LD R,A not supported\n" ); + warning = true; + goto loop; + + case 0x57: // LD A,I + r.b.a = R.i; + goto ld_ai_common; + + case 0x5F: // LD A,R + r.b.a = GET_R(); + dprintf( "LD A,R not supported\n" ); + warning = true; + ld_ai_common: + flags = (flags & C01) + SZ28( r.b.a ) + (R.iff2 << 2 & V04); + goto loop; + + CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN + R.iff1 = R.iff2; + goto ret_taken; + + case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 + R.im = 0; + goto loop; + + case 0x56: case 0x76: // IM 1 + R.im = 1; + goto loop; + + case 0x5E: case 0x7E: // IM 2 + R.im = 2; + goto loop; + + default: + dprintf( "Opcode $ED $%02X not supported\n", data ); + warning = true; + goto loop; + } + assert( false ); + } + +//////////////////////////////////////// DD/FD prefix + { + int ixy; + case 0xDD: + ixy = ix; + goto ix_prefix; + case 0xFD: + ixy = iy; + ix_prefix: + pc++; + int data2 = READ_CODE( pc ); + s_time += (clock_table + 256) [data] & 0x0F; + switch ( data ) + { + // TODO: more efficient way of avoid negative address + // TODO: avoid using this as argument to READ_MEM() since it is evaluated twice + #define IXY_DISP( ixy, disp ) WORD( (ixy ) + (disp)) + + #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; + + // ADD/ADC/SUB/SBC + + case 0x96: // SUB (IXY+disp) + case 0x86: // ADD (IXY+disp) + flags &= ~C01; + case 0x9E: // SBC (IXY+disp) + case 0x8E: // ADC (IXY+disp) + pc++; + opcode = data; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto adc_data; + + case 0x94: // SUB HXY + case 0x84: // ADD HXY + flags &= ~C01; + case 0x9C: // SBC HXY + case 0x8C: // ADC HXY + opcode = data; + data = ixy >> 8; + goto adc_data; + + case 0x95: // SUB LXY + case 0x85: // ADD LXY + flags &= ~C01; + case 0x9D: // SBC LXY + case 0x8D: // ADC LXY + opcode = data; + data = BYTE( ixy ); + goto adc_data; + + { + int temp; + case 0x39: // ADD IXY,SP + temp = sp; + goto add_ixy_data; + + case 0x29: // ADD IXY,HL + temp = ixy; + goto add_ixy_data; + + case 0x09: // ADD IXY,BC + case 0x19: // ADD IXY,DE + temp = R16( data, 4, 0x09 ); + add_ixy_data: { + int sum = ixy + temp; + temp ^= ixy; + ixy = WORD( sum ); + flags = (flags & (S80 | Z40 | V04)) + + (sum >> 16) + + (sum >> 8 & (F20 | F08)) + + ((temp ^ sum) >> 8 & H10); + goto set_ixy; + } + } + + // AND + case 0xA6: // AND (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto and_data; + + case 0xA4: // AND HXY + data = ixy >> 8; + goto and_data; + + case 0xA5: // AND LXY + data = BYTE( ixy ); + goto and_data; + + // OR + case 0xB6: // OR (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto or_data; + + case 0xB4: // OR HXY + data = ixy >> 8; + goto or_data; + + case 0xB5: // OR LXY + data = BYTE( ixy ); + goto or_data; + + // XOR + case 0xAE: // XOR (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto xor_data; + + case 0xAC: // XOR HXY + data = ixy >> 8; + goto xor_data; + + case 0xAD: // XOR LXY + data = BYTE( ixy ); + goto xor_data; + + // CP + case 0xBE: // CP (IXY+disp) + pc++; + data = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto cp_data; + + case 0xBC: // CP HXY + data = ixy >> 8; + goto cp_data; + + case 0xBD: // CP LXY + data = BYTE( ixy ); + goto cp_data; + + // LD + CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r + data = R8( data, 0x70 ); + if ( 0 ) + case 0x36: // LD (IXY+disp),imm + pc++, data = READ_CODE( pc ); + pc++; + WRITE_MEM( IXY_DISP( ixy, SBYTE( data2 ) ), data ); + goto loop; + + CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY + R8( data >> 3, 8 ) = ixy >> 8; + goto loop; + + case 0x64: // LD HXY,HXY + case 0x6D: // LD LXY,LXY + goto loop; + + CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY + R8( data >> 3, 8 ) = ixy; + goto loop; + + CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) + pc++; + R8( data >> 3, 8 ) = READ_MEM( IXY_DISP( ixy, SBYTE( data2 ) ) ); + goto loop; + + case 0x26: // LD HXY,imm + pc++; + goto ld_hxy_data; + + case 0x65: // LD HXY,LXY + data2 = BYTE( ixy ); + goto ld_hxy_data; + + CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r + data2 = R8( data, 0x60 ); + ld_hxy_data: + ixy = BYTE( ixy ) + (data2 << 8); + goto set_ixy; + + case 0x2E: // LD LXY,imm + pc++; + goto ld_lxy_data; + + case 0x6C: // LD LXY,HXY + data2 = ixy >> 8; + goto ld_lxy_data; + + CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r + data2 = R8( data, 0x68 ); + ld_lxy_data: + ixy = (ixy & 0xFF00) + data2; + set_ixy: + if ( opcode == 0xDD ) + { + ix = ixy; + goto loop; + } + iy = ixy; + goto loop; + + case 0xF9: // LD SP,IXY + sp = ixy; + goto loop; + + case 0x22:{// LD (ADDR),IXY + int addr = GET_ADDR(); + pc += 2; + WRITE_WORD( addr, ixy ); + goto loop; + } + + case 0x21: // LD IXY,imm + ixy = GET_ADDR(); + pc += 2; + goto set_ixy; + + case 0x2A:{// LD IXY,(addr) + int addr = GET_ADDR(); + ixy = READ_WORD( addr ); + pc += 2; + goto set_ixy; + } + + // DD/FD CB prefix + case 0xCB: { + data = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data2 = READ_CODE( pc ); + pc++; + switch ( data2 ) + { + case 0x06: goto rlc_data_addr; // RLC (IXY) + case 0x16: goto rl_data_addr; // RL (IXY) + case 0x26: goto sla_data_addr; // SLA (IXY) + case 0x36: goto sll_data_addr; // SLL (IXY) + case 0x0E: goto rrc_data_addr; // RRC (IXY) + case 0x1E: goto rr_data_addr; // RR (IXY) + case 0x2E: goto sra_data_addr; // SRA (IXY) + case 0x3E: goto srl_data_addr; // SRL (IXY) + + CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) + int temp = READ_MEM( data ); + temp = temp & (1 << (data2 >> 3 & 7)); + flags = (flags & C01) + H10 + (temp & S80); + flags += (unsigned) --temp >> 8 & (Z40 | P04); + goto loop; + } + + CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) + CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) + int temp = READ_MEM( data ); + int bit = 1 << (data2 >> 3 & 7); + temp |= bit; // SET + if ( !(data2 & 0x40) ) + temp ^= bit; // RES + WRITE_MEM( data, temp ); + goto loop; + } + + default: + dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); + warning = true; + goto loop; + } + assert( false ); + } + + // INC/DEC + case 0x23: // INC IXY + ixy = WORD( ixy + 1 ); + goto set_ixy; + + case 0x2B: // DEC IXY + ixy = WORD( ixy - 1 ); + goto set_ixy; + + case 0x34: // INC (IXY+disp) + ixy = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data = READ_MEM( ixy ) + 1; + WRITE_MEM( ixy, data ); + goto inc_set_flags; + + case 0x35: // DEC (IXY+disp) + ixy = IXY_DISP( ixy, SBYTE( data2 ) ); + pc++; + data = READ_MEM( ixy ) - 1; + WRITE_MEM( ixy, data ); + goto dec_set_flags; + + case 0x24: // INC HXY + ixy = WORD( ixy + 0x100 ); + data = ixy >> 8; + goto inc_xy_common; + + case 0x2C: // INC LXY + data = BYTE( ixy + 1 ); + ixy = (ixy & 0xFF00) + data; + inc_xy_common: + if ( opcode == 0xDD ) + { + ix = ixy; + goto inc_set_flags; + } + iy = ixy; + goto inc_set_flags; + + case 0x25: // DEC HXY + ixy = WORD( ixy - 0x100 ); + data = ixy >> 8; + goto dec_xy_common; + + case 0x2D: // DEC LXY + data = BYTE( ixy - 1 ); + ixy = (ixy & 0xFF00) + data; + dec_xy_common: + if ( opcode == 0xDD ) + { + ix = ixy; + goto dec_set_flags; + } + iy = ixy; + goto dec_set_flags; + + // PUSH/POP + case 0xE5: // PUSH IXY + data = ixy; + goto push_data; + + case 0xE1:{// POP IXY + ixy = READ_WORD( sp ); + sp = WORD( sp + 2 ); + goto set_ixy; + } + + // Misc + + case 0xE9: // JP (IXY) + pc = ixy; + goto loop; + + case 0xE3:{// EX (SP),IXY + int temp = READ_WORD( sp ); + WRITE_WORD( sp, ixy ); + ixy = temp; + goto set_ixy; + } + + default: + dprintf( "Unnecessary DD/FD prefix encountered\n" ); + warning = true; + pc--; + goto loop; + } + assert( false ); + } + + } + dprintf( "Unhandled main opcode: $%02X\n", opcode ); + assert( false ); + +#ifdef IDLE_ADDR +hit_idle_addr: + s_time -= 11; + goto out_of_time; +#endif +halt: + s_time &= 3; // increment by multiple of 4 +out_of_time: + pc--; + + r.b.flags = flags; + R.ix = ix; + R.iy = iy; + R.sp = sp; + R.pc = pc; + R.b = r.b; + + CPU.cpu_state_.base = s.base; + CPU.cpu_state_.time = s_time; + CPU.cpu_state = &CPU.cpu_state_; +} diff -Nru kodi-audiodecoder-gme-2.0.3/lib/kodi-File_Extractor-note.txt kodi-audiodecoder-gme-19.0.3/lib/kodi-File_Extractor-note.txt --- kodi-audiodecoder-gme-2.0.3/lib/kodi-File_Extractor-note.txt 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/kodi-File_Extractor-note.txt 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,7 @@ +File_Extractor source from https://github.com/kode54/File_Extractor +Sync to ? + +Note: Contains bigger changes to use on Kodi + +- https://bitbucket.org/kode54/file_extractor +- https://git.lopez-snowhill.net/chris/file_extractor diff -Nru kodi-audiodecoder-gme-2.0.3/lib/kodi-Game_Music_Emu-note.txt kodi-audiodecoder-gme-19.0.3/lib/kodi-Game_Music_Emu-note.txt --- kodi-audiodecoder-gme-2.0.3/lib/kodi-Game_Music_Emu-note.txt 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/lib/kodi-Game_Music_Emu-note.txt 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,8 @@ +Game_Music_Emu source from https://github.com/kode54/Game_Music_Emu +Sync to fd803c8 (25 Oct. 2018) + +Note: Not included part "VGM info now reads UTF-8 tags" (f811076), in conflict with File_Extractor. + +Another source: +- https://git.lopez-snowhill.net/chris/game_music_emu +- https://bitbucket.org/kode54/game_music_emu \ No newline at end of file diff -Nru kodi-audiodecoder-gme-2.0.3/LICENSE.md kodi-audiodecoder-gme-19.0.3/LICENSE.md --- kodi-audiodecoder-gme-2.0.3/LICENSE.md 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/LICENSE.md 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,264 @@ +The GNU General Public License, Version 2, June 1991 (GPLv2) +============================================================ + +> Copyright (C) 1989, 1991 Free Software Foundation, Inc. +> 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + + +Preamble +-------- + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to most +of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom to +distribute copies of free software (and charge for this service if you wish), +that you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs; and that you know you can +do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny +you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a +fee, you must give the recipients all the rights that you have. You must make +sure that they, too, receive or can get the source code. And you must show them +these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer +you this license which gives you legal permission to copy, distribute and/or +modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients to +know that what they have is not the original, so that any problems introduced by +others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish +to avoid the danger that redistributors of a free program will individually +obtain patent licenses, in effect making the program proprietary. To prevent +this, we have made it clear that any patent must be licensed for everyone's free +use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + + +Terms And Conditions For Copying, Distribution And Modification +--------------------------------------------------------------- + +**0.** This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms of +this General Public License. The "Program", below, refers to any such program or +work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included without +limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by +this License; they are outside its scope. The act of running the Program is not +restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by +running the Program). Whether that is true depends on what the Program does. + +**1.** You may copy and distribute verbatim copies of the Program's source code +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the Program +a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at +your option offer warranty protection in exchange for a fee. + +**2.** You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such +modifications or work under the terms of Section 1 above, provided that you also +meet all of these conditions: + +* **a)** You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + +* **b)** You must cause any work that you distribute or publish, that in whole + or in part contains or is derived from the Program or any part thereof, to + be licensed as a whole at no charge to all third parties under the terms of + this License. + +* **c)** If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may redistribute + the program under these conditions, and telling the user how to view a copy + of this License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on the Program is + not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, and +its terms, do not apply to those sections when you distribute them as separate +works. But when you distribute the same sections as part of a whole which is a +work based on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the entire whole, +and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based on the +Program. + +In addition, mere aggregation of another work not based on the Program with the +Program (or with a work based on the Program) on a volume of a storage or +distribution medium does not bring the other work under the scope of this +License. + +**3.** You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 and 2 +above provided that you also do one of the following: + +* **a)** Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above on + a medium customarily used for software interchange; or, + +* **b)** Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + +* **c)** Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only for + noncommercial distribution and only if you received the program in object + code or executable form with such an offer, in accord with Subsection b + above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all the +source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +If distribution of executable or object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the source code +from the same place counts as distribution of the source code, even though third +parties are not compelled to copy the source along with the object code. + +**4.** You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, or +rights, from you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +**5.** You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you do +not accept this License. Therefore, by modifying or distributing the Program (or +any work based on the Program), you indicate your acceptance of this License to +do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +**6.** Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these terms and +conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties to this License. + +**7.** If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution of +the Program by all those who receive copies directly or indirectly through you, +then the only way you could satisfy both it and this License would be to refrain +entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and the +section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In such +case, this License incorporates the limitation as if written in the body of this +License. + +**9.** The Free Software Foundation may publish revised and/or new versions of +the General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Program does not specify a version number of this License, you may choose any +version ever published by the Free Software Foundation. + +**10.** If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software generally. + + +No Warranty +----------- + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER +OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff -Nru kodi-audiodecoder-gme-2.0.3/README.md kodi-audiodecoder-gme-19.0.3/README.md --- kodi-audiodecoder-gme-2.0.3/README.md 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/README.md 2013-05-31 22:59:22.000000000 +0000 @@ -1,15 +1,17 @@ # audiodecoder.gme addon for Kodi -This is a [Kodi](http://kodi.tv) audio decoder addon for various game music files. +This is a [Kodi](https://kodi.tv) audio decoder addon for various game music files. -[![Build Status](https://travis-ci.org/xbmc/audiodecoder.gme.svg?branch=master)](https://travis-ci.org/xbmc/audiodecoder.gme) -[![Build Status](https://dev.azure.com/teamkodi/binary-addons/_apis/build/status/xbmc.audiodecoder.gme?branchName=Leia)](https://dev.azure.com/teamkodi/binary-addons/_build/latest?definitionId=5&branchName=Leia) - +[![License: GPL-2.0-or-later](https://img.shields.io/badge/License-GPL%20v2+-blue.svg)](LICENSE.md) +[![Build and run tests](https://github.com/xbmc/audiodecoder.gme/actions/workflows/build.yml/badge.svg?branch=Matrix)](https://github.com/xbmc/audiodecoder.gme/actions/workflows/build.yml) +[![Build Status](https://dev.azure.com/teamkodi/binary-addons/_apis/build/status/xbmc.audiodecoder.gme?branchName=Matrix)](https://dev.azure.com/teamkodi/binary-addons/_build/latest?definitionId=5&branchName=Matrix) +[![Build Status](https://jenkins.kodi.tv/view/Addons/job/xbmc/job/audiodecoder.gme/job/Matrix/badge/icon)](https://jenkins.kodi.tv/blue/organizations/jenkins/xbmc%2Faudiodecoder.gme/branches/) + ## Build instructions When building the addon you have to use the correct branch depending on which version of Kodi you're building against. -For example, if you're building the `master` branch of Kodi you should checkout the `master` branch of this repository. +If you want to build the addon to be compatible with the latest kodi `Matrix` commit, you need to checkout the branch with the current kodi codename. Also make sure you follow this README from the branch in question. ### Linux @@ -17,8 +19,8 @@ The following instructions assume you will have built Kodi already in the `kodi-build` directory suggested by the README. -1. `git clone --branch Leia https://github.com/xbmc/xbmc.git` -2. `git clone https://github.com/xbmc/audiodecoder.gme.git` +1. `git clone --branch Matrix https://github.com/xbmc/xbmc.git` +2. `git clone --branch Matrix https://github.com/xbmc/audiodecoder.gme.git` 3. `cd audiodecoder.gme && mkdir build && cd build` 4. `cmake -DADDONS_TO_BUILD=audiodecoder.gme -DADDON_SRC_PREFIX=../.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=../../xbmc/kodi-build/addons -DPACKAGE_ZIP=1 ../../xbmc/cmake/addons` 5. `make` diff -Nru kodi-audiodecoder-gme-2.0.3/src/GMECodec.cpp kodi-audiodecoder-gme-19.0.3/src/GMECodec.cpp --- kodi-audiodecoder-gme-2.0.3/src/GMECodec.cpp 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/src/GMECodec.cpp 2013-05-31 22:59:22.000000000 +0000 @@ -1,149 +1,155 @@ /* - * Copyright (C) 2014-2020 Arne Morten Kvarving - * Copyright (C) 2016-2020 Team Kodi - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Kodi; see the file COPYING. If not, see - * . + * Copyright (C) 2014-2022 Arne Morten Kvarving + * Copyright (C) 2016-2022 Team Kodi (https://kodi.tv) * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. */ -#include -#include -#include "gme.h" +#include "GMECodec.h" -struct GMEContext { - gme_t* gme = nullptr; - int len; -}; +#include -class ATTRIBUTE_HIDDEN CGMECodec : public kodi::addon::CInstanceAudioDecoder +CGMECodec::CGMECodec(KODI_HANDLE instance, const std::string& version) + : CInstanceAudioDecoder(instance, version) { -public: - CGMECodec(KODI_HANDLE instance) : - CInstanceAudioDecoder(instance) - { - } - - virtual ~CGMECodec() - { - if (ctx.gme) - gme_delete(ctx.gme); - } +} - bool Init(const std::string& filename, unsigned int filecache, - int& channels, int& samplerate, - int& bitspersample, int64_t& totaltime, - int& bitrate, AEDataFormat& format, - std::vector& channellist) override - { - int track=0; - std::string toLoad(filename); - if (toLoad.rfind("stream") != std::string::npos) - { - size_t iStart=toLoad.rfind('-') + 1; - track = atoi(toLoad.substr(iStart, toLoad.size()-iStart-10).c_str())-1; - // The directory we are in, is the file - // that contains the bitstream to play, - // so extract it - size_t slash = toLoad.rfind('\\'); - if (slash == std::string::npos) - slash = toLoad.rfind('/'); - toLoad = toLoad.substr(0, slash); - } - - - gme_open_file(toLoad.c_str(), &ctx.gme, 48000); - if (!ctx.gme) - return false; - - channels = 2; - samplerate = 48000; - bitspersample = 16; - bitrate = 0.0; - format = AE_FMT_S16NE; - gme_info_t* out; - gme_track_info(ctx.gme, &out, track); - totaltime = ctx.len = out->play_length; - channellist = { AE_CH_FL, AE_CH_FR }; - gme_start_track(ctx.gme, track); +CGMECodec::~CGMECodec() +{ + if (ctx.gme) + gme_delete(ctx.gme); +} + +bool CGMECodec::Init(const std::string& filename, + unsigned int filecache, + int& channels, + int& samplerate, + int& bitspersample, + int64_t& totaltime, + int& bitrate, + AudioEngineDataFormat& format, + std::vector& channellist) +{ + int track = 0; + std::string toLoad(filename); + if (toLoad.rfind("stream") != std::string::npos) + { + size_t iStart = toLoad.rfind('-') + 1; + track = atoi(toLoad.substr(iStart, toLoad.size() - iStart - 10).c_str()) - 1; + // The directory we are in, is the file + // that contains the bitstream to play, + // so extract it + size_t slash = toLoad.rfind('\\'); + if (slash == std::string::npos) + slash = toLoad.rfind('/'); + toLoad = toLoad.substr(0, slash); + } + + gme_open_file(toLoad.c_str(), &ctx.gme, 48000); + if (!ctx.gme) + return false; + + channels = 2; + samplerate = 48000; + bitspersample = 16; + bitrate = 0.0; + format = AUDIOENGINE_FMT_S16NE; + gme_info_t* out; + gme_track_info(ctx.gme, &out, track); + totaltime = ctx.len = out->play_length; + channellist = {AUDIOENGINE_CH_FL, AUDIOENGINE_CH_FR}; + gme_start_track(ctx.gme, track); - return true; - } + return true; +} - int ReadPCM(uint8_t* buffer, int size, int& actualsize) override - { - if (gme_tell(ctx.gme) >= ctx.len) - return -1; - actualsize = size; - gme_play(ctx.gme, size/2, (short*)buffer); - return 0; - } +int CGMECodec::ReadPCM(uint8_t* buffer, int size, int& actualsize) +{ + if (gme_tell(ctx.gme) >= ctx.len) + return -1; + actualsize = size; + gme_play(ctx.gme, size / 2, (short*)buffer); + return 0; +} - int64_t Seek(int64_t time) override - { - gme_seek(ctx.gme, time); - return gme_tell(ctx.gme); - } +int64_t CGMECodec::Seek(int64_t time) +{ + gme_seek(ctx.gme, time); + return gme_tell(ctx.gme); +} - bool ReadTag(const std::string& filename, std::string& title, - std::string& artist, int& length) override - { - gme_t* gme=nullptr; - gme_open_file(filename.c_str(), &gme, 48000); - if (!gme) - return false; - - gme_info_t* out; - gme_track_info(gme, &out, 0); - length = out->play_length/1000; - title = out->song; - if (title.empty()) - title = out->game; - artist = out->author; - gme_delete(gme); - return true; +bool CGMECodec::ReadTag(const std::string& filename, kodi::addon::AudioDecoderInfoTag& tag) +{ + int track = 0; + std::string toLoad(filename); + if (toLoad.rfind("stream") != std::string::npos) + { + size_t iStart = toLoad.rfind('-') + 1; + track = atoi(toLoad.substr(iStart, toLoad.size() - iStart - 10).c_str()); + // The directory we are in, is the file + // that contains the bitstream to play, + // so extract it + size_t slash = toLoad.rfind('\\'); + if (slash == std::string::npos) + slash = toLoad.rfind('/'); + toLoad = toLoad.substr(0, slash); } - int TrackCount(const std::string& fileName) override - { - gme_t* gme=nullptr; - gme_open_file(fileName.c_str(), &gme, 48000); - if (!gme) - return 1; + gme_t* gme = nullptr; + gme_open_file(toLoad.c_str(), &gme, 48000); + if (!gme) + return false; + + gme_info_t* out; + gme_track_info(gme, &out, track > 0 ? track - 1 : 0); + tag.SetTrack(track); + tag.SetSamplerate(48000); + tag.SetChannels(2); + tag.SetDuration(out->play_length / 1000); + if (out->song) + tag.SetTitle(out->song); + if (out->game && tag.GetTitle().empty()) + tag.SetTitle(out->game); + if (out->author) + tag.SetArtist(out->author); + if (out->game) + tag.SetAlbum(out->game); + if (out->comment) + tag.SetComment(out->comment); + gme_delete(gme); + return true; +} - int result = gme_track_count(gme); - gme_delete(gme); +int CGMECodec::TrackCount(const std::string& fileName) +{ + gme_t* gme = nullptr; + gme_open_file(fileName.c_str(), &gme, 48000); + if (!gme) + return 1; - return result; - } + int result = gme_track_count(gme); + gme_delete(gme); -private: - GMEContext ctx; -}; + return result; +} +//------------------------------------------------------------------------------ class ATTRIBUTE_HIDDEN CMyAddon : public kodi::addon::CAddonBase { public: CMyAddon() = default; - ADDON_STATUS CreateInstance(int instanceType, std::string instanceID, KODI_HANDLE instance, KODI_HANDLE& addonInstance) override + ADDON_STATUS CreateInstance(int instanceType, + const std::string& instanceID, + KODI_HANDLE instance, + const std::string& version, + KODI_HANDLE& addonInstance) override { - addonInstance = new CGMECodec(instance); + addonInstance = new CGMECodec(instance, version); return ADDON_STATUS_OK; } virtual ~CMyAddon() = default; }; - -ADDONCREATOR(CMyAddon); +ADDONCREATOR(CMyAddon) diff -Nru kodi-audiodecoder-gme-2.0.3/src/GMECodec.h kodi-audiodecoder-gme-19.0.3/src/GMECodec.h --- kodi-audiodecoder-gme-2.0.3/src/GMECodec.h 1970-01-01 00:00:00.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/src/GMECodec.h 2013-05-31 22:59:22.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014-2022 Arne Morten Kvarving + * Copyright (C) 2016-2022 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#pragma once + +#include "gme.h" + +#include + +struct GMEContext +{ + gme_t* gme = nullptr; + int len; +}; + +class ATTRIBUTE_HIDDEN CGMECodec : public kodi::addon::CInstanceAudioDecoder +{ +public: + CGMECodec(KODI_HANDLE instance, const std::string& version); + virtual ~CGMECodec(); + + bool Init(const std::string& filename, + unsigned int filecache, + int& channels, + int& samplerate, + int& bitspersample, + int64_t& totaltime, + int& bitrate, + AudioEngineDataFormat& format, + std::vector& channellist) override; + int ReadPCM(uint8_t* buffer, int size, int& actualsize) override; + int64_t Seek(int64_t time) override; + bool ReadTag(const std::string& filename, kodi::addon::AudioDecoderInfoTag& tag) override; + int TrackCount(const std::string& fileName) override; + +private: + GMEContext ctx; +}; diff -Nru kodi-audiodecoder-gme-2.0.3/.travis.yml kodi-audiodecoder-gme-19.0.3/.travis.yml --- kodi-audiodecoder-gme-2.0.3/.travis.yml 2020-02-05 18:17:13.000000000 +0000 +++ kodi-audiodecoder-gme-19.0.3/.travis.yml 2013-05-31 22:59:22.000000000 +0000 @@ -3,8 +3,8 @@ # # Define the build matrix # -# Travis defaults to building on Ubuntu Precise when building on -# Linux. We need Trusty in order to get up to date versions of +# Travis defaults to building on Ubuntu Trusty when building on +# Linux. We need Xenial in order to get up to date versions of # cmake and g++. # env: @@ -21,19 +21,33 @@ dist: xenial sudo: required compiler: clang + - os: linux + dist: bionic + sudo: required + compiler: gcc + env: DEBIAN_BUILD=true - os: osx - osx_image: xcode9.4 + osx_image: xcode10.2 + +before_install: + - if [[ $DEBIAN_BUILD == true ]]; then sudo add-apt-repository -y ppa:team-xbmc/ppa; fi + - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get update; fi + - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get install fakeroot; fi # # The addon source is automatically checked out in $TRAVIS_BUILD_DIR, # we'll put the Kodi source on the same level # before_script: - - cd $TRAVIS_BUILD_DIR/.. - - git clone --branch Leia --depth=1 https://github.com/xbmc/xbmc.git - - cd ${app_id} && mkdir build && cd build - - mkdir -p definition/${app_id} - - echo ${app_id} $TRAVIS_BUILD_DIR $TRAVIS_COMMIT > definition/${app_id}/${app_id}.txt - - cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DADDONS_DEFINITION_DIR=$TRAVIS_BUILD_DIR/build/definition -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/cmake/addons + - if [[ $DEBIAN_BUILD != true ]]; then cd $TRAVIS_BUILD_DIR/..; fi + - if [[ $DEBIAN_BUILD != true ]]; then git clone --branch Matrix --depth=1 https://github.com/xbmc/xbmc.git; fi + - if [[ $DEBIAN_BUILD != true ]]; then cd ${app_id} && mkdir build && cd build; fi + - if [[ $DEBIAN_BUILD != true ]]; then mkdir -p definition/${app_id}; fi + - if [[ $DEBIAN_BUILD != true ]]; then echo ${app_id} $TRAVIS_BUILD_DIR $TRAVIS_COMMIT > definition/${app_id}/${app_id}.txt; fi + - if [[ $DEBIAN_BUILD != true ]]; then cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DADDONS_DEFINITION_DIR=$TRAVIS_BUILD_DIR/build/definition -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/cmake/addons; fi + - if [[ $DEBIAN_BUILD == true ]]; then wget https://raw.githubusercontent.com/xbmc/xbmc/Matrix/xbmc/addons/kodi-dev-kit/tools/debian-addon-package-test.sh && chmod +x ./debian-addon-package-test.sh; fi + - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get build-dep $TRAVIS_BUILD_DIR; fi -script: make +script: + - if [[ $DEBIAN_BUILD != true ]]; then make; fi + - if [[ $DEBIAN_BUILD == true ]]; then ./debian-addon-package-test.sh $TRAVIS_BUILD_DIR; fi