0.6pre1 - introduce the final changes

- implement E1xy/E2xy Defle bug when using same note twice
- add SNK Touchdown Fever preset
- update README.md and to-do list
- update credits

thank you for your patience!

see you in 0.6pre1.5 coming soon...
This commit is contained in:
tildearrow 2022-06-29 04:57:05 -05:00
parent 6a35258e9b
commit a8a38dce2b
14 changed files with 222 additions and 91 deletions

190
README.md
View File

@ -1,8 +1,8 @@
# Furnace Tracker
![screenshot](papers/screenshot1.png)
![screenshot](papers/screenshot2.png)
this is a multi-system chiptune tracker.
the biggest multi-system chiptune tracker ever made!
[downloads](#downloads) | [discussion/help](#quick-references) | [developer info](#developer-info) | [unofficial packages](#unofficial-packages) | [FAQ](#frequently-asked-questions)
@ -15,34 +15,91 @@ check out the [Releases](https://github.com/tildearrow/furnace/releases) page. a
## features
- supports the following systems:
- Sega Genesis
- Sega Master System
- over 50 sound chips - and counting:
- Yamaha FM chips:
- YM2151 (OPM)
- YM2203 (OPN)
- YM2413 (OPLL)
- YM2414 (OPZ) used in Yamaha TX81Z
- YM2608 (OPNA) used in PC-98
- YM2610 (OPNB) used in Neo Geo
- YM2610B (OPNB2)
- YM2612 (OPN2) used in Sega Genesis and FM Towns
- YM3526 (OPL) used in C64 Sound Expander
- YM3812 (OPL2)
- YMF262 (OPL3) with full 4-op support!
- Y8950 (OPL with ADPCM)
- square wave chips:
- AY-3-8910/YM2149(F) used in several computers and game consoles
- Commodore VIC used in the VIC-20
- Microchip AY8930
- TI SN76489 used in Sega Master System and BBC Micro
- PC Speaker
- Philips SAA1099 used in SAM Coupé
- sample chips:
- Amiga
- SegaPCM - all 16 channels
- Capcom QSound
- Yamaha YMZ280B (PCMD8)
- Ricoh RF5C68 used in Sega CD and FM Towns
- OKI MSM6258 and MSM6295
- wavetable chips:
- HuC6280 used in PC Engine
- Konami Bubble System WSG
- Konami SCC/SCC+
- Namco arcade chips (WSG/C15/C30)
- WonderSwan
- Seta/Allumer X1-010
- NES (Ricoh 2A03/2A07), with additional expansion sound support:
- Konami VRC6
- Konami VRC7
- MMC5
- Famicom Disk System
- Sunsoft 5B
- Namco 163
- Family Noraebang (OPLL)
- SID (6581/8580) used in Commodore 64
- Mikey used in Atari Lynx
- ZX Spectrum beeper (SFX-like engine)
- TIA used in Atari 2600
- Game Boy
- PC Engine
- NES
- Commodore 64
- Yamaha YM2151 (plus PCM)
- Neo Geo
- AY-3-8910 (ZX Spectrum, Atari ST, etc.)
- Microchip AY8930
- Philips SAA1099
- Amiga
- TIA (Atari 2600/7800)
- multiple sound chips in a single song!
- DefleMask compatibility - loads .dmf modules, .dmp instruments and .dmw wavetables
- clean-room design (guesswork and ABX tests only, no decompilation involved)
- bug/quirk implementation for increased playback accuracy
- VGM and audio file export
- accurate emulation cores whether possible (Nuked, MAME, SameBoy, Mednafen PCE, puNES, reSID, Stella, SAASound and ymfm)
- additional features on top:
- modern/fantasy:
- Commander X16 VERA
- tildearrow Sound Unit
- mix and match sound chips!
- over 200 ready to use presets from computers, game consoles and arcade boards...
- ...or create your own - up to 32 of them or a total of 128 channels!
- DefleMask compatibility
- loads .dmf modules from all versions (beta 1 to 1.1.3)
- saves .dmf modules - both modern and legacy
- Furnace doubles as a module downgrader
- loads .dmp instruments and .dmw wavetables as well
- clean-room design (guesswork and ABX tests only, no decompilation involved)
- bug/quirk implementation for increased playback accuracy through compatibility flags
- VGM export
- modular layout that you may adapt to your needs
- audio file export - entire song, per system or per channel
- quality emulation cores (Nuked, MAME, SameBoy, Mednafen PCE, NSFplay, puNES, reSID, Stella, SAASound, vgsound_emu and ymfm)
- wavetable synthesizer
- available on wavetable chips
- create complex sounds with ease - provide up to two wavetables, select and effect and let go!
- MIDI input support
- [Fractal Sound](https://gitlab.com/Natsumi/Fractal-Sound) support!
- the game-ready Sega Genesis/Mega Drive sound driver!
- compose your songs in Furnace using the Fractal Sound presets and then use them in your games with Fractal!
- additional features:
- FM macros!
- negative octaves
- arbitrary pitch samples
- sample loop points
- SSG envelopes in Neo Geo
- SSG envelopes and ADPCM-B in Neo Geo
- full duty/cutoff range in C64
- ability to change tempo mid-song with `Cxxx` effect (`xxx` between `000` and `3ff`)
- ability to change tempo mid-song
- multiple sub-songs in a module
- per-channel oscilloscope with waveform centering
- built-in sample editor
- chip mixing settings
- built-in visualizer in pattern view
- open-source under GPLv2 or later.
***
@ -59,7 +116,7 @@ some people have provided packages for Unix/Unix-like distributions. here's a li
- **Arch Linux**: [furnace-git is in the AUR.](https://aur.archlinux.org/packages/furnace-git) thank you Essem!
- **FreeBSD**: [a package in ports](https://www.freshports.org/audio/furnace/) is available courtesy of ehaupt.
- **Nix**: [package](https://search.nixos.org/packages?channel=unstable&show=furnace&from=0&size=50&sort=relevance&type=packages&query=furnace) thanks to OPNA2608.
- **OpenSUSE**: [a package](https://software.opensuse.org/package/furnace) is available, courtesy of fpesari.
- **openSUSE**: [a package](https://software.opensuse.org/package/furnace) is available, courtesy of fpesari.
***
# developer info
@ -73,11 +130,17 @@ if you can't download these artifacts (because GitHub requires you to be logged
## dependencies
- CMake
- SDL2
- zlib
- JACK (optional)
- JACK (optional, macOS/Linux only)
SDL2 and zlib are included as submodules.
if building under Windows or macOS, no additional dependencies are required.
otherwise, you may also need the following:
- libpulse
- libx11
- libasound
- libGL
some Linux distributions (e.g. Ubuntu or openSUSE) will require you to install the `-dev` versions of these.
## getting the source
@ -127,14 +190,20 @@ Available options:
| Name | Default | Description |
| :--: | :-----: | ----------- |
| `BUILD_GUI` | `ON` | Build the tracker (disable to build only a headless player) |
| `USE_RTMIDI` | `ON` | Build with MIDI support using RtMidi |
| `USE_SDL2` | `ON` | Build with SDL2 (required to build with GUI) |
| `USE_SNDFILE` | `ON` | Build with libsndfile (required in order to work with audio files) |
| `USE_BACKWARD` | `ON` | Use backward-cpp to print a backtrace on crash/abort |
| `WITH_JACK` | `ON` if system-installed JACK detected, otherwise `OFF` | Whether to build with JACK support. Auto-detects if JACK is available |
| `SYSTEM_FFTW` | `OFF` | Use a system-installed version of FFTW instead of the vendored one |
| `SYSTEM_FMT` | `OFF` | Use a system-installed version of fmt instead of the vendored one |
| `SYSTEM_LIBSNDFILE` | `OFF` | Use a system-installed version of libsndfile instead of the vendored one |
| `SYSTEM_RTMIDI` | `OFF` | Use a system-installed version of RtMidi instead of the vendored one |
| `SYSTEM_ZLIB` | `OFF` | Use a system-installed version of zlib instead of the vendored one |
| `SYSTEM_SDL2` | `OFF` | Use a system-installed version of SDL2 instead of the vendored one |
| `WARNINGS_ARE_ERRORS` | `OFF` (but consider enabling this & reporting any errors that arise from it!) | Whether warnings in furnace's C++ code should be treated as errors |
## usage
## console usage
```
./furnace
@ -156,36 +225,21 @@ this will play a compatible file and enable the commands view.
**note that these commands only actually work in Linux environments. on other command lines, such as Windows' Command Prompt, or MacOS Terminal, it may not work correctly.**
***
# notes
> how do I use Neo Geo SSG envelopes?
the following effects are provided:
- `22xy`: set envelope mode.
- `x` sets the envelope shape, which may be one of the following:
- `0: \___` decay
- `4: /___` attack once
- `8: \\\\` saw
- `9: \___` decay
- `A: \/\/` inverse obelisco
- `B: \¯¯¯` decay once
- `C: ////` inverse saw
- `D: /¯¯¯` attack
- `E: /\/\` obelisco
- `F: /___` attack once
- if `y` is 1 then the envelope will affect this channel.
- `23xx`: set envelope period low byte.
- `24xx`: set envelope period high byte.
- `25xx`: slide envelope period up.
- `26xx`: slide envelope period down.
a lower envelope period will make the envelope run faster.
***
# frequently asked questions
> woah! 50 sound chips?! I can't believe it!
yup, it's real.
> where's the manual?
see [papers/](papers/README.md). it's kind of incomplete, but at least the systems (sound chips) section is there.
> it doesn't open under macOS!
this is due to Apple's application signing policy. a workaround is to right click on the Furnace app icon and select Open.
> how do I use C64 absolute filter/duty?
on Instrument Editor in the C64 tab there are two options to toggle these.
@ -195,25 +249,27 @@ also provided are two effects:
- `4xxx`: set fine cutoff. `xxx` range is 000-7ff.
additionally, you can change the cutoff and/or duty as a macro inside an instrument by clicking the `absolute cutoff macro` and/or `absolute duty macro` checkbox at the bottom of the instrument. (for the filter, you also need to click the checkbox that says `volume macro is cutoff macro`.)
> Q: how do I use PCM on a PCM-capable system?
> how do I use PCM on a PCM-capable system?
A: Two possibilities: the recommended way is via creating the "Amiga/Sample" type instrument and assigning sample to it, or via old, Deflemask-compatible method, using `17xx` effect
two possibilities:
- the recommended way is by creating the "Sample" type instrument and assigning a sample to it.
- otherwise you may employ the DefleMask-compatible method, using `17xx` effect.
> Q: my song sounds very odd at a certain point
> my .dmf song sounds very odd at a certain point
A: file a bug report. use the Issues page. it's probably another playback inaccuracy.
file a bug report. use the Issues page. it's probably another playback inaccuracy.
> Q: my song sounds correct, but it doesn't in DefleMask
> my .dmf song sounds correct, but it doesn't in DefleMask
A: file a bug report **here**. it still is a playback inaccuracy.
file a bug report **here**. it still is a playback inaccuracy.
> Q: my C64 song sounds terrible after saving as .dmf!
> my song sounds terrible after saving as .dmf!
A: that's a limitation of the DefleMask format. save in Furnace song format instead (.fur).
the DefleMask format has several limitations. save in Furnace song format instead (.fur).
> Q: how do I solo channels?
> how do I solo channels?
A: right click on the channel name.
right click on the channel name.
***
# footnotes

View File

@ -1,8 +1,4 @@
# to-do for 0.6pre1
- implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change)
# to-do for 0.6pre2 (as this requires new data structures)
# to-do for 0.6pre1.5-0.6pre2
- rewrite the system name detection function anyway
- this involves the addition of a new "system" field in the song (which solves the problem)

View File

@ -304,7 +304,7 @@ size | description
1 | new ins affects envelope (Game Boy) (>=72) or reserved
1 | ExtCh channel state is shared (>=78) or reserved
1 | ignore DAC mode change outside of intended channel (>=83) or reserved
1 | E1xx and E2xx also take priority over Slide00 (>=83) or reserved
1 | E1xy and E2xy also take priority over Slide00 (>=83) or reserved
1 | new Sega PCM (with macros and proper vol/pan) (>=84) or reserved
1 | weird f-num/block-based chip pitch slides (>=85) or reserved
1 | SN duty macro always resets phase (>=86) or reserved
@ -315,7 +315,8 @@ size | description
1 | new volume scaling strategy (>=99) or reserved
1 | volume macro still applies after end (>=99) or reserved
1 | broken outVol (>=99) or reserved
9 | reserved
1 | E1xy and E2xy stop on same note (>=100) or reserved
8 | reserved
--- | **virtual tempo data**
2 | virtual tempo numerator of first song (>=96) or reserved
2 | virtual tempo denominator of first song (>=96) or reserved

BIN
papers/screenshot2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 KiB

View File

@ -15,17 +15,17 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>0.6pre0</string>
<string>0.6pre1</string>
<key>CFBundleName</key>
<string>Furnace</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.6pre0</string>
<string>0.6pre1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.6pre0</string>
<string>0.6pre1</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>NSHighResolutionCapable</key>

View File

@ -10,10 +10,13 @@
<description>
<p>
this is a work-in-progress chiptune tracker which interacts with DefleMask module files (.dmf).
the biggest chiptune tracker ever made!
</p>
<p>
it supports creating songs for Sega Genesis, Master System, Game Boy, PC Engine, NES, C64, YM2151/PCM and Neo Geo. featuring a clean-room design (zero reverse-engineered code and zero decompilation; using official DMF specs, guesswork and ABX tests only), bug/quirk implementation for increased playback accuracy, and accurate emulation cores whether possible (Nuked, MAME, SameBoy, Mednafen PCE, puNES, reSID and ymfm).
it allows you to create songs using a music tracker interface for several computer/game console/arcade sound chips.
</p>
<p>
it also offers DefleMask compatibility, allowing you to import your songs and even export them back for interoperability.
</p>
</description>

View File

@ -45,8 +45,8 @@
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
#define BUSY_END isBusy.unlock(); softLocked=false;
#define DIV_VERSION "dev99"
#define DIV_ENGINE_VERSION 99
#define DIV_VERSION "0.6pre1"
#define DIV_ENGINE_VERSION 100
// for imports
#define DIV_VERSION_MOD 0xff01
@ -88,7 +88,7 @@ struct DivChannelState {
int tremoloDepth, tremoloRate, tremoloPos;
unsigned char arp, arpStage, arpTicks, panL, panR;
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp;
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp;
int midiNote, curMidiNote, midiPitch;
size_t midiAge;
@ -136,6 +136,7 @@ struct DivChannelState {
inPorta(false),
scheduledSlideReset(false),
shorthandPorta(false),
wasShorthandPorta(false),
noteOnInhibit(false),
resetArp(false),
midiNote(-1),

View File

@ -171,6 +171,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.newVolumeScaling=false;
ds.volMacroLinger=false;
ds.brokenOutVol=true; // ???
ds.e1e2StopOnSameNote=true;
// 1.1 compat flags
if (ds.version>24) {
@ -1043,6 +1044,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
ds.volMacroLinger=false;
ds.brokenOutVol=true;
}
if (ds.version<100) {
ds.e1e2StopOnSameNote=false;
}
ds.isDMF=false;
reader.readS(); // reserved
@ -1439,7 +1443,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
reader.readC();
reader.readC();
}
for (int i=0; i<9; i++) {
if (ds.version>=100) {
ds.e1e2StopOnSameNote=reader.readC();
} else {
reader.readC();
}
for (int i=0; i<8; i++) {
reader.readC();
}
}
@ -2912,7 +2921,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeC(song.newVolumeScaling);
w->writeC(song.volMacroLinger);
w->writeC(song.brokenOutVol);
for (int i=0; i<9; i++) {
w->writeC(song.e1e2StopOnSameNote);
for (int i=0; i<8; i++) {
w->writeC(0);
}

View File

@ -456,6 +456,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].nowYouCanStop=false;
chan[i].stopOnOff=false;
chan[i].scheduledSlideReset=false;
chan[i].wasShorthandPorta=false;
chan[i].inPorta=false;
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
}
@ -475,6 +476,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].nowYouCanStop=false;
chan[i].stopOnOff=false;
chan[i].scheduledSlideReset=false;
chan[i].wasShorthandPorta=false;
chan[i].inPorta=false;
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
}
@ -494,6 +496,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].portaNote=chan[i].note;
chan[i].portaSpeed=effectVal;
chan[i].inPorta=true;
chan[i].wasShorthandPorta=false;
}
chan[i].portaStop=true;
if (chan[i].keyOn) chan[i].doNote=false;
@ -573,6 +576,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
if ((effectVal&15)!=0) {
chan[i].inPorta=true;
chan[i].shorthandPorta=true;
chan[i].wasShorthandPorta=true;
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
if (song.e1e2AlsoTakePriority) lastSlide=0x1337; // ...
} else {
@ -590,6 +594,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
if ((effectVal&15)!=0) {
chan[i].inPorta=true;
chan[i].shorthandPorta=true;
chan[i].wasShorthandPorta=true;
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
if (song.e1e2AlsoTakePriority) lastSlide=0x1337; // ...
} else {
@ -715,7 +720,14 @@ void DivEngine::processRow(int i, bool afterDelay) {
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
} else {
if (chan[i].inPorta && chan[i].keyOn && !chan[i].shorthandPorta) {
chan[i].portaNote=chan[i].note;
if (song.e1e2StopOnSameNote && chan[i].wasShorthandPorta) {
chan[i].portaSpeed=-1;
if (!song.brokenShortcutSlides) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
chan[i].wasShorthandPorta=false;
chan[i].inPorta=false;
} else {
chan[i].portaNote=chan[i].note;
}
} else if (!chan[i].noteOnInhibit) {
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note,chan[i].volume>>8));
keyHit[i]=true;

View File

@ -494,6 +494,7 @@ struct DivSong {
bool newVolumeScaling;
bool volMacroLinger;
bool brokenOutVol;
bool e1e2StopOnSameNote;
std::vector<DivInstrument*> ins;
std::vector<DivWavetable*> wave;
@ -591,7 +592,8 @@ struct DivSong {
noOPN2Vol(false),
newVolumeScaling(true),
volMacroLinger(true),
brokenOutVol(false) {
brokenOutVol(false),
e1e2StopOnSameNote(false) {
for (int i=0; i<32; i++) {
system[i]=DIV_SYSTEM_NULL;
systemVol[i]=64;

View File

@ -108,9 +108,10 @@ const char* aboutLine[]={
"Portable File Dialogs by Sam Hocevar",
"Native File Dialog by Frogtoss Games",
"RtMidi by Gary P. Scavone",
"FFTW by Matteo Frigo and Steven G. Johnson",
"backward-cpp by Google",
"adpcm by superctr",
"Nuked-OPL3/OPLL/OPM/OPN2 by Nuke.YKT",
"Nuked-OPL3/OPLL/OPM/OPN2/PSG by Nuke.YKT",
"ymfm by Aaron Giles",
"MAME SN76496 by Nicola Salmoria",
"MAME AY-3-8910 by Couriersud",
@ -131,7 +132,7 @@ const char* aboutLine[]={
"VICE VIC-20 sound core by Rami Rasanen and viznut",
"VERA sound core by Frank van den Hoef",
"K005289 emulator by cam900",
"Namco 163 emulator by cam900",
"Namco C163 emulator by cam900",
"Seta X1-010 emulator by cam900",
"Konami VRC6 emulator by cam900",
"Konami SCC emulator by cam900",

View File

@ -115,6 +115,10 @@ void FurnaceGUI::drawCompatFlags() {
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("does this make any sense by now?");
}
ImGui::Checkbox("E1xy/E2xy stop when repeating the same note",&e->song.e1e2StopOnSameNote);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("ugh, if only this wasn't a thing...");
}
ImGui::Checkbox("SN76489 duty macro always resets phase",&e->song.snDutyReset);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, duty macro will always reset phase, even if its value hasn't changed.");

View File

@ -1808,6 +1808,34 @@ void FurnaceGUI::initSystemPresets() {
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"SNK Touchdown Fever", {
DIV_SYSTEM_OPL, 64, 0, 2,
DIV_SYSTEM_Y8950, 64, 0, 2,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"SNK Touchdown Fever (drums mode on OPL)", {
DIV_SYSTEM_OPL_DRUMS, 64, 0, 2,
DIV_SYSTEM_Y8950, 64, 0, 2,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"SNK Touchdown Fever (drums mode on Y8950)", {
DIV_SYSTEM_OPL, 64, 0, 2,
DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"SNK Touchdown Fever (drums mode on OPL and Y8950)", {
DIV_SYSTEM_OPL_DRUMS, 64, 0, 2,
DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Alpha denshi Alpha-68K", {
DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz

View File

@ -140,20 +140,37 @@ TAParamResult pVersion(String) {
printf("- libsndfile by Erik de Castro Lopo and rest of libsndfile team (LGPLv2.1)\n");
printf("- SDL2 by Sam Lantinga (zlib license)\n");
printf("- zlib by Jean-loup Gailly and Mark Adler (zlib license)\n");
printf("- RtMidi by Gary P. Scavone (RtMidi license)\n");
printf("- backward-cpp by Google (MIT)\n");
printf("- Dear ImGui by Omar Cornut (MIT)\n");
printf("- Portable File Dialogs by Sam Hocevar (WTFPL)\n");
printf("- Native File Dialog (modified version) by Frogtoss Games (zlib license)\n");
printf("- FFTW by Matteo Frigo and Steven G. Johnson (GPLv2)\n");
printf("- Nuked-OPM by Nuke.YKT (LGPLv2.1)\n");
printf("- Nuked-OPN2 by Nuke.YKT (LGPLv2.1)\n");
printf("- Nuked-OPL3 by Nuke.YKT (LGPLv2.1)\n");
printf("- Nuked-OPLL by Nuke.YKT (GPLv2)\n");
printf("- Nuked-PSG (modified version) by Nuke.YKT (GPLv2)\n");
printf("- ymfm by Aaron Giles (BSD 3-clause)\n");
printf("- adpcm by superctr (public domain)\n");
printf("- MAME SN76496 emulation core by Nicola Salmoria (BSD 3-clause)\n");
printf("- MAME AY-3-8910 emulation core by Couriersud (BSD 3-clause)\n");
printf("- MAME SAA1099 emulation core by Juergen Buchmueller and Manuel Abadia (BSD 3-clause)\n");
printf("- SAASound (BSD 3-clause)\n");
printf("- MAME Namco WSG by Nicola Salmoria and Aaron Giles (BSD 3-clause)\n");
printf("- MAME RF5C68 core by Olivier Galibert and Aaron Giles (BSD 3-clause)\n");
printf("- MAME MSM6258 core by Barry Rodewald (BSD 3-clause)\n");
printf("- MAME YMZ280B core by Aaron Giles (BSD 3-clause)\n");
printf("- QSound core by superctr (BSD 3-clause)\n");
printf("- VICE VIC-20 by Rami Rasanen and viznut (GPLv2)\n");
printf("- VERA core by Frank van den Hoef (BSD 2-clause)\n");
printf("- SAASound by Dave Hooper and Simon Owen (BSD 3-clause)\n");
printf("- SameBoy by Lior Halphon (MIT)\n");
printf("- Mednafen PCE by Mednafen Team (GPLv2)\n");
printf("- Mednafen PCE and WonderSwan by Mednafen Team (GPLv2)\n");
printf("- puNES by FHorse (GPLv2)\n");
printf("- NSFPlay by Brad Smith and Brezza (unknown open-source license)\n");
printf("- reSID by Dag Lem (GPLv2)\n");
printf("- Stella by Stella Team (GPLv2)\n");
printf("- vgsound_emu by cam900 (BSD 3-clause)\n");
printf("- vgsound_emu (first version) by cam900 (BSD 3-clause)\n");
return TA_PARAM_QUIT;
}