diff --git a/android/app/build.gradle b/android/app/build.gradle index 5c7b1e31f..91db8e5e0 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,8 +15,8 @@ android { } minSdkVersion 21 targetSdkVersion 26 - versionCode 174 - versionName "0.6pre13" + versionCode 175 + versionName "0.6pre14" externalNativeBuild { cmake { arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3fa5d55db..2a283791a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ diff --git a/demos/arcade/WSG_Loop_Tune_NamcoWSG.fur b/demos/arcade/WSG_Loop_Tune_NamcoWSG.fur new file mode 100644 index 000000000..9319c7b3f Binary files /dev/null and b/demos/arcade/WSG_Loop_Tune_NamcoWSG.fur differ diff --git a/demos/gameboy/On_Hold.fur b/demos/gameboy/On_Hold.fur new file mode 100644 index 000000000..e77c639b6 Binary files /dev/null and b/demos/gameboy/On_Hold.fur differ diff --git a/demos/multichip/PinBot-C30C140.fur b/demos/multichip/PinBot-C30C140.fur new file mode 100644 index 000000000..e20b2b7df Binary files /dev/null and b/demos/multichip/PinBot-C30C140.fur differ diff --git a/demos/x16/Exerion_II_Tune.fur b/demos/x16/Exerion_II_Tune.fur new file mode 100644 index 000000000..eabc1902d Binary files /dev/null and b/demos/x16/Exerion_II_Tune.fur differ diff --git a/doc/3-pattern/effects.md b/doc/3-pattern/effects.md index 10eda981a..b2622426c 100644 --- a/doc/3-pattern/effects.md +++ b/doc/3-pattern/effects.md @@ -148,19 +148,53 @@ additionally, [each chip has its own effects](../7-systems/README.md). the interpretation of duty, wave and extra macros depends on chip/instrument type: -ex | FM | OPM | OPZ | OPLL | AY-3-8910 | AY8930 | Lynx | C64 | SAA1099 | X1-010 | Namco 163 | FDS | Sound Unit | ES5506 | MSM6258 | QSound | SNES | MSM5232 | ----|--------|-----------|-----------|-------|------------|------------|----------|------------|----------|------------|------------|-----------|------------|-----------|----------|--------------|-----------|-----------| - D | NoiseF | NoiseFreq | | | NoiseFreq | NoiseFreq | Duty/Int | Duty | | | Wave Pos | | Duty | Filt Mode | FreqDiv | Echo Level | NoiseFreq | GroupCtrl | - W | | LFO Shape | LFO Shape | Patch | Waveform | Waveform | | Waveform | Waveform | Waveform | Waveform | Waveform | Waveform | | | | Waveform | | - 1 | | AMD | AMD | | | Duty | | FilterMode | Envelope | EnvMode | WaveLen | Mod Depth | Cutoff | Filter K1 | ClockDiv | EchoFeedback | Special | GroupAtk | - 2 | | PMD | PMD | | Envelope | Envelope | | Resonance | | Envelope | WaveUpdate | Mod Speed | Resonance | Filter K2 | | Echo Length | Gain | GroupDec | - 3 | LFOSpd | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Special | | AutoEnvNum | WaveLoad W | | Control | Env Count | | | | Noise | - A | ALG | ALG | ALG | | AutoEnvDen | AutoEnvDen | | | | AutoEnvDen | WaveLoad P | | | Control | | | | | - B | FB | FB | FB | | | Noise AND | | | | | WaveLoad L | | | | | | | | - C | FMS | FMS | FMS | | | Noise OR | | | | | WaveLoad T | | | | | | | | - D | AMS | AMS | AMS | | | | | | | | | | | | | | | | - 4 | OpMask | OpMask | | | | | | Test/Gate | | | | | PResetTime | EnvRampL | | | | | - 5 | | | AMD2 | | | | | | | | | | | EnvRampR | | | | | - 6 | | | PMD2 | | | | | | | | | | | EnvRampK1 | | | | | - 7 | | | LFO2Speed | | | | | | | | | | | EnvRampK2 | | | | | - 8 | | | LFO2Shape | | | | | | | | | | | Env Mode | | | | | +ex | FM | OPM | OPZ | OPLL | AY-3-8910 | AY8930 | Lynx | C64 | +---|--------|-----------|-----------|-------|------------|------------|----------|------------| + D | NoiseF | NoiseFreq | | | NoiseFreq | NoiseFreq | Duty/Int | Duty | + W | | LFO Shape | LFO Shape | Patch | Waveform | Waveform | | Waveform | + 1 | | AMD | AMD | | | Duty | | FilterMode | + 2 | | PMD | PMD | | Envelope | Envelope | | Resonance | + 3 | LFOSpd | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Special | + A | ALG | ALG | ALG | | AutoEnvDen | AutoEnvDen | | | + B | FB | FB | FB | | | Noise AND | | | + C | FMS | FMS | FMS | | | Noise OR | | | + D | AMS | AMS | AMS | | | | | | + 4 | OpMask | OpMask | | | | | | Test/Gate | + 5 | | | AMD2 | | | | | | + 6 | | | PMD2 | | | | | | + 7 | | | LFO2Speed | | | | | | + 8 | | | LFO2Shape | | | | | | + +ex | SAA1099 | X1-010 | Namco 163 | FDS | Sound Unit | ES5506 | MSM6258 | +---|----------|------------|------------|-----------|------------|-----------|----------| + D | | | Wave Pos | | Duty | Filt Mode | FreqDiv | + W | Waveform | Waveform | Waveform | Waveform | Waveform | | | + 1 | Envelope | EnvMode | WaveLen | Mod Depth | Cutoff | Filter K1 | ClockDiv | + 2 | | Envelope | WaveUpdate | Mod Speed | Resonance | Filter K2 | | + 3 | | AutoEnvNum | WaveLoad W | | Control | Env Count | | + A | | AutoEnvDen | WaveLoad P | | | Control | | + B | | | WaveLoad L | | | | | + C | | | WaveLoad T | | | | | + D | | | | | | | | + 4 | | | | | PResetTime | EnvRampL | | + 5 | | | | | | EnvRampR | | + 6 | | | | | | EnvRampK1 | | + 7 | | | | | | EnvRampK2 | | + 8 | | | | | | Env Mode | | + +ex | QSound | SNES | MSM5232 | +---|--------------|-----------|-----------| + D | Echo Level | NoiseFreq | GroupCtrl | + W | | Waveform | | + 1 | EchoFeedback | Special | GroupAtk | + 2 | Echo Length | Gain | GroupDec | + 3 | | | Noise | + A | | | | + B | | | | + C | | | | + D | | | | + 4 | | | | + 5 | | | | + 6 | | | | + 7 | | | | + 8 | | | | diff --git a/doc/7-systems/msm6258.md b/doc/7-systems/msm6258.md index 1b632aae2..9c2d638f0 100644 --- a/doc/7-systems/msm6258.md +++ b/doc/7-systems/msm6258.md @@ -26,4 +26,4 @@ MSM6258 is an extremely basic ADPCM sound codec. it has no variable frequency ra ## info -this chip uses the [MSM6258](../4-instrument/msm6258.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [MSM6258](../4-instrument/msm6258.md) instrument editor. diff --git a/doc/7-systems/msm6295.md b/doc/7-systems/msm6295.md index 580a4c127..3fbcea689 100644 --- a/doc/7-systems/msm6295.md +++ b/doc/7-systems/msm6295.md @@ -10,7 +10,7 @@ an upgrade from 6258 - it provides 4 ADPCM channels, at max 32 KHz (still no var ## info -this chip uses the [MSM6295](../4-instrument/msm6295.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [MSM6295](../4-instrument/msm6295.md) instrument editor. ## chip clock rates diff --git a/doc/7-systems/nes.md b/doc/7-systems/nes.md index b782009f3..cfd1823a6 100644 --- a/doc/7-systems/nes.md +++ b/doc/7-systems/nes.md @@ -59,7 +59,7 @@ also known as Famicom. it is a five-channel sound generator: first two channels ## info -this chip uses the [NES](../4-instrument/nes.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [NES](../4-instrument/nes.md) instrument editor. ## short noise frequencies (NTSC) diff --git a/doc/7-systems/pce.md b/doc/7-systems/pce.md index 24cbfcf05..ec6633c3e 100644 --- a/doc/7-systems/pce.md +++ b/doc/7-systems/pce.md @@ -23,4 +23,4 @@ furthermore, it has some PCM and LFO! ## info -this chip uses the [PC Engine](../4-instrument/pce.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [PC Engine](../4-instrument/pce.md) instrument editor. diff --git a/doc/7-systems/qsound.md b/doc/7-systems/qsound.md index 55b05b8dc..5534f18ae 100644 --- a/doc/7-systems/qsound.md +++ b/doc/7-systems/qsound.md @@ -21,4 +21,4 @@ there are also 3 ADPCM channels. ADPCM samples are fixed to 8012Hz. ## info -this chip uses the [QSound](../4-instrument/qsound.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [QSound](../4-instrument/qsound.md) instrument editor. diff --git a/doc/7-systems/ricoh.md b/doc/7-systems/ricoh.md index 1b9fc4a53..6f406ccd8 100644 --- a/doc/7-systems/ricoh.md +++ b/doc/7-systems/ricoh.md @@ -8,4 +8,4 @@ none so far. ## info -this chip uses the [RF5C68](../4-instrument/rf5c68.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [RF5C68](../4-instrument/rf5c68.md) instrument editor. diff --git a/doc/7-systems/segapcm.md b/doc/7-systems/segapcm.md index a42e84366..9e8b7783e 100644 --- a/doc/7-systems/segapcm.md +++ b/doc/7-systems/segapcm.md @@ -18,4 +18,4 @@ Furnace also has a five channel version of this chip, but it only exists for Def ## info -this chip uses the [SegaPCM](../4-instrument/segapcm.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [SegaPCM](../4-instrument/segapcm.md) instrument editor. diff --git a/doc/7-systems/soundunit.md b/doc/7-systems/soundunit.md index 9291ebc9d..3bf13a136 100644 --- a/doc/7-systems/soundunit.md +++ b/doc/7-systems/soundunit.md @@ -57,4 +57,4 @@ it has the following capabilities: ## info -this chip uses the [Sound Unit](../4-instrument/su.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [Sound Unit](../4-instrument/su.md) instrument editor. diff --git a/doc/7-systems/vrc6.md b/doc/7-systems/vrc6.md index 174a4d348..00dcbc7f3 100644 --- a/doc/7-systems/vrc6.md +++ b/doc/7-systems/vrc6.md @@ -20,4 +20,4 @@ these effects only are effective in the pulse channels. ## info -this chip uses the [VRC6](../4-instrument/vrc6.md), [VRC6 (saw)](../4-instrument/vrc6.md), and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [VRC6](../4-instrument/vrc6.md) and [VRC6 (saw)](../4-instrument/vrc6.md) instrument editors. diff --git a/doc/7-systems/wonderswan.md b/doc/7-systems/wonderswan.md index 24d71ecc0..edd189649 100644 --- a/doc/7-systems/wonderswan.md +++ b/doc/7-systems/wonderswan.md @@ -18,7 +18,9 @@ it has 4 wavetable channels. some of them have additional capabilities: - 0: disable. - 1-32: enable and set period. - `13xx`: **setup sweep amount.** channel 3 only. + - `00` to `7F` for 0 to 127. + - `80` to `FF` for -128 to -1. ## info -this chip uses the [WonderSwan](../4-instrument/wonderswan.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [WonderSwan](../4-instrument/wonderswan.md) instrument editor. diff --git a/doc/7-systems/x1-010.md b/doc/7-systems/x1-010.md index ae7d55bc5..3f181850d 100644 --- a/doc/7-systems/x1-010.md +++ b/doc/7-systems/x1-010.md @@ -49,4 +49,4 @@ in Furnace, you can enable the envelope shape split mode. when it is set, its wa ## info -this chip uses the [X1-010](../4-instrument/x1_010.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [X1-010](../4-instrument/x1_010.md) instrument editor. diff --git a/doc/7-systems/ym2608.md b/doc/7-systems/ym2608.md index c7306eec3..528541e91 100644 --- a/doc/7-systems/ym2608.md +++ b/doc/7-systems/ym2608.md @@ -108,6 +108,4 @@ all four operators are still combined according to the algorithm in use. for exa ## info -this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [Generic Sample](../4-instrument/sample.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md), and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. - - +this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md) and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. diff --git a/doc/7-systems/ym2610.md b/doc/7-systems/ym2610.md index 63b1358f5..8eb14a1b9 100644 --- a/doc/7-systems/ym2610.md +++ b/doc/7-systems/ym2610.md @@ -106,6 +106,4 @@ all four operators are still combined according to the algorithm in use. for exa ## info -this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [Generic Sample](../4-instrument/sample.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md), and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. - - +this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md) and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. diff --git a/doc/7-systems/ym2610b.md b/doc/7-systems/ym2610b.md index a62548cad..aa26b9c6f 100644 --- a/doc/7-systems/ym2610b.md +++ b/doc/7-systems/ym2610b.md @@ -105,6 +105,4 @@ all four operators are still combined according to the algorithm in use. for exa ## info -this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [Generic Sample](../4-instrument/sample.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md), and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. - - +this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md) and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. diff --git a/doc/7-systems/ym2612.md b/doc/7-systems/ym2612.md index 595c9c460..9dceb5814 100644 --- a/doc/7-systems/ym2612.md +++ b/doc/7-systems/ym2612.md @@ -86,5 +86,3 @@ thanks to the Z80 sound CPU, DualPCM can play two samples at once! this mode spl ## info this chip uses the [FM (OPN)](../4-instrument/fm-opn.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. - - diff --git a/doc/7-systems/ymz280b.md b/doc/7-systems/ymz280b.md index 170251a88..6edc34251 100644 --- a/doc/7-systems/ymz280b.md +++ b/doc/7-systems/ymz280b.md @@ -10,4 +10,4 @@ none so far. ## info -this chip uses the [YMZ280B](../4-instrument/ymz280b.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. +this chip uses the [YMZ280B](../4-instrument/ymz280b.md) instrument editor. diff --git a/doc/7-systems/zxbeep.md b/doc/7-systems/zxbeep.md index b721d8233..384b6e189 100644 --- a/doc/7-systems/zxbeep.md +++ b/doc/7-systems/zxbeep.md @@ -17,4 +17,4 @@ not really - very soon talented programmers found out ways to output much more t ## info -this chip uses the [Beeper](../4-instrument/beeper.md), [Generic Sample](../4-instrument/sample.md), and [Pokémon Mini/QuadTone](../4-instrument/pokemini.md) instrument editors. +this chip uses the [Beeper](../4-instrument/beeper.md) or [Pokémon Mini/QuadTone](../4-instrument/pokemini.md) instrument editor. diff --git a/papers/clipboard-format.md b/papers/clipboard-format.md index 095c543da..fd6b075ed 100644 --- a/papers/clipboard-format.md +++ b/papers/clipboard-format.md @@ -6,7 +6,7 @@ when copying pattern data from Furnace, it's stored in the clipboard as plain te org.tildearrow.furnace - Pattern Data (144) ``` -this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6pre13 is `174`. +this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6pre14 is `175`. the second line is a number between 0 and 18 (decimal) which indicates which column the clip starts from. - `0`: note. diff --git a/papers/format.md b/papers/format.md index 399db9b20..447785bf2 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 175: Furnace 0.6pre14 - 174: Furnace 0.6pre13 - 173: Furnace 0.6pre12 - 172: Furnace 0.6pre11 diff --git a/res/Info.plist b/res/Info.plist index 8277023ba..51055ed6a 100644 --- a/res/Info.plist +++ b/res/Info.plist @@ -15,17 +15,17 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - 0.6pre13 + 0.6pre14 CFBundleName Furnace CFBundlePackageType APPL CFBundleShortVersionString - 0.6pre13 + 0.6pre14 CFBundleSignature ???? CFBundleVersion - 0.6pre13 + 0.6pre14 NSHumanReadableCopyright NSHighResolutionCapable diff --git a/res/docpdf/make_paper.py b/res/docpdf/make_paper.py index e15f278db..168bab5d7 100644 --- a/res/docpdf/make_paper.py +++ b/res/docpdf/make_paper.py @@ -91,7 +91,7 @@ if __name__ == "__main__": # each file is its own section html +='
%s
' % ( my_file.replace(os.path.sep, "__"), - markdown.markdown(data, extensions=['nl2br', GithubFlavoredMarkdownExtension()]) + markdown.markdown(data, extensions=['nl2br', 'mdx_breakless_lists', GithubFlavoredMarkdownExtension()]) ) # build html @@ -119,7 +119,7 @@ if __name__ == "__main__": } body { font-family: 'Exo 2'; - line-height: 1.2; + line-height: 1.25; font-size: 11pt; color: #000; } @@ -132,7 +132,7 @@ if __name__ == "__main__": font-family: 'IBM Plex Mono'; } ul { - padding-left: 4pt; + padding-left: 10pt; margin-right: 4pt; list-style-type: none; } @@ -184,13 +184,13 @@ if __name__ == "__main__": } a[href^='#']:after { content: target-counter(attr(href),page); - font-weight: regular; + font-weight: normal; font-size: 0.5em; color: #555; } a[href^='http']:after { content: ' (' attr(href) ') '; - font-weight: regular; + font-weight: normal; color: #555; } #cover { @@ -209,10 +209,12 @@ if __name__ == "__main__": pre { font-size: .8em; } + li > p { + display: inline; + } table { display: block; width: 100%%; - width: max-content; max-width: 100%%; overflow: auto; border-collapse: collapse; @@ -222,14 +224,17 @@ if __name__ == "__main__": border-top: 1pt solid #aaa; } th, td { - padding: 3pt 6pt; + padding: 2pt 3pt; border: 1pt solid #ccc; } th { hyphens: none; padding: 2pt 4pt; text-transform: uppercase; - font-size: .8em + font-size: .8em; + } + td { + font-size: 11pt; } @page { size: a4; diff --git a/res/docpdf/requirements.txt b/res/docpdf/requirements.txt index 656a389bf..d06226b3c 100644 --- a/res/docpdf/requirements.txt +++ b/res/docpdf/requirements.txt @@ -5,6 +5,7 @@ fonttools==4.39.3 html5lib==1.1 Markdown==3.4.3 Pillow==9.4.0 +mdx-breakless-lists==1.0.1 py-gfm==2.0.0 pycparser==2.21 pydyf==0.5.0 diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index a1abc874f..fee404523 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3246,6 +3246,10 @@ void DivEngine::setMetronomeVol(float vol) { metroVol=vol; } +void DivEngine::setSamplePreviewVol(float vol) { + previewVol=vol; +} + void DivEngine::setConsoleMode(bool enable) { consoleMode=enable; } @@ -3450,6 +3454,7 @@ bool DivEngine::initAudioBackend() { clampSamples=getConfInt("clampSamples",0); lowLatency=getConfInt("lowLatency",0); metroVol=(float)(getConfInt("metroVol",100))/100.0f; + previewVol=(float)(getConfInt("sampleVol",50))/100.0f; midiOutClock=getConfInt("midiOutClock",0); midiOutTime=getConfInt("midiOutTime",0); midiOutTimeRate=getConfInt("midiOutTimeRate",0); @@ -3457,6 +3462,8 @@ bool DivEngine::initAudioBackend() { midiOutMode=getConfInt("midiOutMode",DIV_MIDI_MODE_NOTE); if (metroVol<0.0f) metroVol=0.0f; if (metroVol>2.0f) metroVol=2.0f; + if (previewVol<0.0f) previewVol=0.0f; + if (previewVol>1.0f) previewVol=1.0f; renderPoolThreads=getConfInt("renderPoolThreads",0); if (lowLatency) logI("using low latency mode."); diff --git a/src/engine/engine.h b/src/engine/engine.h index 3b1d8d2fd..ccaaf36e3 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -58,8 +58,8 @@ class DivWorkPool; #define DIV_UNSTABLE -#define DIV_VERSION "0.6pre13" -#define DIV_ENGINE_VERSION 174 +#define DIV_VERSION "0.6pre14" +#define DIV_ENGINE_VERSION 175 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 @@ -490,6 +490,7 @@ class DivEngine { float metroFreq, metroPos; float metroAmp; float metroVol; + float previewVol; size_t totalProcessed; @@ -729,6 +730,9 @@ class DivEngine { int getSamplePreviewPos(); double getSamplePreviewRate(); + // set sample preview volume (1.0 = 100%) + void setSamplePreviewVol(float vol); + // trigger sample preview void previewSample(int sample, int note=-1, int pStart=-1, int pEnd=-1); void stopSamplePreview(); @@ -1282,6 +1286,7 @@ class DivEngine { metroPos(0), metroAmp(0.0f), metroVol(1.0f), + previewVol(1.0f), totalProcessed(0), renderPoolThreads(0), renderPool(NULL), diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index ed9426674..1e77ad35a 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -152,11 +152,18 @@ void DivPlatformC140::tick(bool sysTick) { } if (is219) { if (chan[i].std.duty.had) { - chan[i].noise=chan[i].std.duty.val&1; - chan[i].invert=chan[i].std.duty.val&2; - chan[i].surround=chan[i].std.duty.val&4; - chan[i].freqChanged=true; - chan[i].writeCtrl=true; + unsigned char singleByte=( + (chan[i].noise?1:0)| + (chan[i].invert?2:0)| + (chan[i].surround?4:0) + ); + if (singleByte!=(chan[i].std.duty.val&7)) { + chan[i].noise=chan[i].std.duty.val&1; + chan[i].invert=chan[i].std.duty.val&2; + chan[i].surround=chan[i].std.duty.val&4; + chan[i].freqChanged=true; + chan[i].writeCtrl=true; + } } } if (chan[i].std.pitch.had) { @@ -209,7 +216,7 @@ void DivPlatformC140::tick(bool sysTick) { if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>65535) chan[i].freq=65535; if (is219) { - ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_C219)?1:0)|(chan[i].invert?0x40:0)|(chan[i].surround?8:0)|(chan[i].noise?4:0); + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable() || chan[i].noise)?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_C219)?1:0)|(chan[i].invert?0x40:0)|(chan[i].surround?8:0)|(chan[i].noise?4:0); } else { ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0); } @@ -228,11 +235,15 @@ void DivPlatformC140::tick(bool sysTick) { start=sampleOff[chan[i].sample]&0xffff; end=MIN(start+s->length8-1,65535); } + } else if (chan[i].noise && is219) { + bank=groupBank[i>>2]; + start=0; + end=1; } if (chan[i].audPos>0) { start=MIN(start+(MIN(chan[i].audPos,s->length8)>>1),65535); } - if (s->isLoopable()) { + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen && s->isLoopable()) { if (is219) { loop=MIN(start+(s->loopStart>>1),65535); end=MIN(start+(s->loopEnd>>1)-1,65535); @@ -240,6 +251,8 @@ void DivPlatformC140::tick(bool sysTick) { loop=MIN(start+s->loopStart,65535); end=MIN(start+s->loopEnd-1,65535); } + } else if (chan[i].noise && is219) { + loop=0; } rWrite(0x05+(i<<4),0); // force keyoff first if (is219) { diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index cb0ed05ed..c5d5c2c0e 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -30,6 +30,16 @@ const char** DivPlatformMSM6258::getRegisterSheet() { return NULL; } +static const int msmRates[4]={ + 4, 3, 2, 2 +}; + +int DivPlatformMSM6258::calcVGMRate() { + int ret=chipClock/((clockSel+1)*512*msmRates[rateSel&3]); + logD("MSM rate: %d",ret); + return ret; +} + void DivPlatformMSM6258::acquire(short** buf, size_t len) { for (size_t h=0; h=0 && samplesong.sampleLen) { + // turn on rWrite(0,2); + if (dumpWrites) addWrite(0xffff0000,sample); + int newRate=calcVGMRate(); + if (dumpWrites) addWrite(0xffff0001,newRate); } else { sample=-1; } @@ -220,10 +243,12 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { case DIV_CMD_SAMPLE_FREQ: rateSel=c.value&3; rWrite(12,rateSel); + updateSampleFreq=true; break; case DIV_CMD_SAMPLE_MODE: clockSel=c.value&1; rWrite(8,clockSel); + updateSampleFreq=true; break; case DIV_CMD_PANNING: { if (c.value==0 && c.value2==0) { @@ -317,8 +342,10 @@ void DivPlatformMSM6258::reset() { msmPan=3; rateSel=2; clockSel=0; + updateSampleFreq=true; if (dumpWrites) { addWrite(0xffffffff,0); + addWrite(0xffff0001,calcVGMRate()); } for (int i=0; i<1; i++) { chan[i]=DivPlatformMSM6258::Channel(); diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index 21ff2a9f2..ce73ca4bb 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -50,12 +50,15 @@ class DivPlatformMSM6258: public DivDispatch { unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel; signed char msmDividerCount, msmClockCount; + bool updateSampleFreq; short msmOut; int delay, updateOsc, sample, samplePos; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); + + int calcVGMRate(); public: void acquire(short** buf, size_t len); diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 6d5dd6a0c..859c95518 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -459,7 +459,7 @@ DivMacroInt* DivPlatformSoundUnit::getChanMacroInt(int ch) { } unsigned short DivPlatformSoundUnit::getPan(int ch) { - return parent->convertPanLinearToSplit(chan[ch].pan^0x80,8,255); + return parent->convertPanLinearToSplit(chan[ch].pan+127,8,255); } DivDispatchOscBuffer* DivPlatformSoundUnit::getOscBuffer(int ch) { diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index bca403af2..2cc00ffab 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -2205,7 +2205,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } else if (srcPortSet==0xffd) { // sample preview for (size_t j=0; jwriteC(8); w->writeC(0xff); break; + case DIV_SYSTEM_MSM6258: + w->writeC(0xb8); // stop + w->writeC(baseAddr2|0); + w->writeC(1); + break; case DIV_SYSTEM_MSM6295: w->writeC(0xb8); // disable all channels w->writeC(baseAddr2|0); @@ -1055,6 +1060,12 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(write.addr&0xff); w->writeC(write.val); break; + case DIV_SYSTEM_MSM6258: + w->writeC(0xb7); + w->writeC(baseAddr2|(write.addr&0x7f)); + w->writeC(write.val); + logV("MSM write to %.2x %.2x",write.addr,write.val); + break; case DIV_SYSTEM_MSM6295: w->writeC(0xb8); w->writeC(baseAddr2|(write.addr&0x7f)); @@ -1238,6 +1249,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p bool writeDACSamples=false; bool writeNESSamples=false; bool writePCESamples=false; + bool writeVOXSamples=false; DivDispatch* writeADPCM_OPNA[2]={NULL,NULL}; DivDispatch* writeADPCM_OPNB[2]={NULL,NULL}; DivDispatch* writeADPCM_Y8950[2]={NULL,NULL}; @@ -1746,6 +1758,21 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p writeRF5C68[0]=disCont[i].dispatch; } break; + case DIV_SYSTEM_MSM6258: + if (!hasOKIM6258) { + hasOKIM6258=disCont[i].dispatch->chipClock; + CHIP_VOL(23,0.65); + willExport[i]=true; + writeVOXSamples=true; + } else if (!(hasOKIM6258&0x40000000)) { + isSecond[i]=true; + CHIP_VOL_SECOND(23,0.65); + willExport[i]=true; + writeVOXSamples=true; + hasOKIM6258|=0x40000000; + howManyChips++; + } + break; case DIV_SYSTEM_MSM6295: if (!hasOKIM6295) { hasOKIM6295=disCont[i].dispatch->chipClock; @@ -1927,7 +1954,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p w->writeI(hasMultiPCM); w->writeI(hasuPD7759); w->writeI(hasOKIM6258); - w->writeC(0); // flags + w->writeC(hasOKIM6258?10:0); // flags w->writeC(0); // K flags w->writeC(c140Type); // C140 chip type w->writeC(0); // reserved @@ -2066,6 +2093,18 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p } } + if (writeVOXSamples && !directStream) for (int i=0; iwriteC(0x67); + w->writeC(0x66); + w->writeC(4); + w->writeI(sample->lengthVOX); + for (unsigned int j=0; jlengthVOX; j++) { + unsigned char actualData=(sample->dataVOX[j]>>4)|(sample->dataVOX[j]<<4); + w->writeC(actualData); + } + } + for (int i=0; i<2; i++) { // SegaPCM if (writeSegaPCM[i]!=NULL && writeSegaPCM[i]->getSampleMemUsage(0)>0) { @@ -2344,6 +2383,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p w->writeI(24000); // default streamID++; break; + case DIV_SYSTEM_MSM6258: + w->writeC(0x90); + w->writeC(streamID); + w->writeC(isSecond[i]?0x97:0x17); + w->writeC(0); // port + w->writeC(1); // data input + + w->writeC(0x91); + w->writeC(streamID); + w->writeC(4); + w->writeC(1); + w->writeC(0); + streamID++; + break; default: break; } diff --git a/src/gui/gui.h b/src/gui/gui.h index cf5000708..1cd703f57 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1503,6 +1503,7 @@ class FurnaceGUI { int separateFMColors; int insEditColorize; int metroVol; + int sampleVol; int pushNibble; int scrollChangesOrder; int oplStandardWaveNames; @@ -1683,6 +1684,7 @@ class FurnaceGUI { separateFMColors(0), insEditColorize(0), metroVol(100), + sampleVol(50), pushNibble(0), scrollChangesOrder(0), oplStandardWaveNames(0), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 9ffc4c27a..f4542d06d 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -5945,6 +5945,7 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_GA20 || ins->type==DIV_INS_K053260 || ins->type==DIV_INS_C140 || + ins->type==DIV_INS_C219 || ins->type==DIV_INS_TED) { macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 419ff91b4..37e21c0ae 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -967,7 +967,7 @@ void FurnaceGUI::drawSettings() { // SUBSECTION METRONOME CONFIG_SUBSECTION("Metronome"); ImGui::AlignTextToFramePadding(); - ImGui::Text("Metronome volume"); + ImGui::Text("Volume"); ImGui::SameLine(); if (ImGui::SliderInt("##MetroVol",&settings.metroVol,0,200,"%d%%")) { if (settings.metroVol<0) settings.metroVol=0; @@ -975,6 +975,17 @@ void FurnaceGUI::drawSettings() { e->setMetronomeVol(((float)settings.metroVol)/100.0f); } + // SUBSECTION SAMPLE PREVIEW + CONFIG_SUBSECTION("Sample preview"); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Volume"); + ImGui::SameLine(); + if (ImGui::SliderInt("##SampleVol",&settings.sampleVol,0,100,"%d%%")) { + if (settings.sampleVol<0) settings.sampleVol=0; + if (settings.sampleVol>100) settings.sampleVol=100; + e->setSamplePreviewVol(((float)settings.sampleVol)/100.0f); + } + END_SECTION; } CONFIG_SECTION("MIDI") { @@ -3246,6 +3257,7 @@ void FurnaceGUI::syncSettings() { settings.separateFMColors=e->getConfInt("separateFMColors",0); settings.insEditColorize=e->getConfInt("insEditColorize",0); settings.metroVol=e->getConfInt("metroVol",100); + settings.sampleVol=e->getConfInt("sampleVol",50); settings.pushNibble=e->getConfInt("pushNibble",0); settings.scrollChangesOrder=e->getConfInt("scrollChangesOrder",0); settings.oplStandardWaveNames=e->getConfInt("oplStandardWaveNames",0); @@ -3407,6 +3419,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.separateFMColors,0,1); clampSetting(settings.insEditColorize,0,1); clampSetting(settings.metroVol,0,200); + clampSetting(settings.sampleVol,0,100); clampSetting(settings.pushNibble,0,1); clampSetting(settings.scrollChangesOrder,0,2); clampSetting(settings.oplStandardWaveNames,0,1); @@ -3535,6 +3548,7 @@ void FurnaceGUI::syncSettings() { e->setMidiDirect(midiMap.directChannel); e->setMetronomeVol(((float)settings.metroVol)/100.0f); + e->setSamplePreviewVol(((float)settings.sampleVol)/100.0f); } void FurnaceGUI::commitSettings() { @@ -3656,6 +3670,7 @@ void FurnaceGUI::commitSettings() { e->setConf("separateFMColors",settings.separateFMColors); e->setConf("insEditColorize",settings.insEditColorize); e->setConf("metroVol",settings.metroVol); + e->setConf("sampleVol",settings.sampleVol); e->setConf("pushNibble",settings.pushNibble); e->setConf("scrollChangesOrder",settings.scrollChangesOrder); e->setConf("oplStandardWaveNames",settings.oplStandardWaveNames); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index b1abfca16..a247650cd 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -1338,6 +1338,64 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl altered=true; } ImGui::Unindent(); + + int chipClock=flags.getInt("customClock",0); + if (!chipClock) { + switch (clockSel) { + case 0: + chipClock=4000000; + break; + case 1: + chipClock=4096000; + break; + case 2: + chipClock=8000000; + break; + case 3: + chipClock=8192000; + break; + } + } + + ImGui::Text("Sample rate table:"); + if (ImGui::BeginTable("6258Rate",3)) { + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("divider \\ clock"); + ImGui::TableNextColumn(); + ImGui::Text("full"); + ImGui::TableNextColumn(); + ImGui::Text("half"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); + ImGui::Text("/512"); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/512); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/1024); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); + ImGui::Text("/768"); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/768); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/1536); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); + ImGui::Text("/1024"); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/1024); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/2048); + + ImGui::EndTable(); + } if (altered) { e->lockSave([&]() {