Custom jucer project and app icon
BIN
Media/icon.png
Normal file
After Width: | Height: | Size: 95 KiB |
|
@ -1,20 +1,24 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<JUCERPROJECT id="wUKQiT" name="JuceOPLVSTi" projectType="audioplug" version="1.0.0"
|
<JUCERPROJECT id="wUKQiT" name="OPL" projectType="audioplug" version="1.0.0"
|
||||||
bundleIdentifier="com.plainweave.JuceOPLVSTi" buildVST="1" buildAU="1"
|
bundleIdentifier="com.discodsp.OPL" pluginName="OPL" pluginDesc="OPL"
|
||||||
pluginName="JuceOPLVSTi" pluginDesc="JuceOPLVSTi" pluginManufacturer="Plainweave Software"
|
pluginManufacturer="discoDSP" pluginManufacturerCode="DDSP" pluginCode="OPL"
|
||||||
pluginManufacturerCode="Pwve" pluginCode="JOPL" pluginChannelConfigs="{0, 1}"
|
pluginChannelConfigs="{0, 1}" pluginIsSynth="1" pluginWantsMidiIn="1"
|
||||||
pluginIsSynth="1" pluginWantsMidiIn="1" pluginProducesMidiOut="0"
|
pluginProducesMidiOut="0" pluginSilenceInIsSilenceOut="0" pluginEditorRequiresKeys="0"
|
||||||
pluginSilenceInIsSilenceOut="0" pluginEditorRequiresKeys="0"
|
pluginAUExportPrefix="oplAU" aaxIdentifier="com.discodsp.opl"
|
||||||
pluginAUExportPrefix="JuceOPLVSTiAU" aaxIdentifier="com.plainweave.JuceOPLVSTi"
|
pluginAAXCategory="2" jucerVersion="5.4.7" includeBinaryInAppConfig="1"
|
||||||
pluginAAXCategory="2" jucerVersion="5.3.2" buildVST3="0" buildRTAS="0"
|
pluginIsMidiEffectPlugin="0" companyWebsite="https://www.discodsp.com/"
|
||||||
buildAAX="0" includeBinaryInAppConfig="1" pluginIsMidiEffectPlugin="0"
|
splashScreenColour="Dark" companyCopyright="" pluginCharacteristicsValue="pluginIsSynth,pluginWantsMidiIn"
|
||||||
companyWebsite="https://bsutherland.github.io/JuceOPLVSTi/" buildAUv3="0"
|
pluginFormats="buildAU,buildStandalone,buildVST,buildVST3,enableIAA"
|
||||||
displaySplashScreen="1" reportAppUsage="1" splashScreenColour="Dark"
|
buildVST="1" buildVST3="1" buildAU="1" buildAUv3="0" buildRTAS="0"
|
||||||
buildStandalone="0" enableIAA="0" companyCopyright="" pluginFormats="buildVST,buildAU"
|
buildAAX="0" buildStandalone="1" enableIAA="1" companyName="discoDSP"
|
||||||
pluginCharacteristicsValue="pluginIsSynth,pluginWantsMidiIn">
|
companyEmail="contactus@discodsp.com" pluginRTASDisableBypass="0"
|
||||||
<MAINGROUP id="TOefyq" name="JuceOPLVSTi">
|
pluginRTASDisableMultiMono="0" pluginAAXDisableBypass="0" pluginAAXDisableMultiMono="0"
|
||||||
|
pluginAUMainType="'aumu'" pluginVST3Category="Instrument,Synth"
|
||||||
|
pluginVSTCategory="kPlugCategSynth">
|
||||||
|
<MAINGROUP id="TOefyq" name="OPL">
|
||||||
<GROUP id="{DCA755EB-7953-0641-E719-95C7850E5B2B}" name="Source">
|
<GROUP id="{DCA755EB-7953-0641-E719-95C7850E5B2B}" name="Source">
|
||||||
|
<FILE id="aNR5I9" name="icon.png" compile="0" resource="0" file="Media/icon.png"/>
|
||||||
<FILE id="AqQcu5" name="ChannelButtonLookAndFeel.cpp" compile="1" resource="0"
|
<FILE id="AqQcu5" name="ChannelButtonLookAndFeel.cpp" compile="1" resource="0"
|
||||||
file="Source/ChannelButtonLookAndFeel.cpp"/>
|
file="Source/ChannelButtonLookAndFeel.cpp"/>
|
||||||
<FILE id="yqL2ZN" name="ChannelButtonLookAndFeel.h" compile="0" resource="0"
|
<FILE id="yqL2ZN" name="ChannelButtonLookAndFeel.h" compile="0" resource="0"
|
||||||
|
@ -68,6 +72,7 @@
|
||||||
<MODULES id="juce_audio_formats" showAllCode="1" useLocalCopy="1"/>
|
<MODULES id="juce_audio_formats" showAllCode="1" useLocalCopy="1"/>
|
||||||
<MODULES id="juce_audio_plugin_client" showAllCode="1" useLocalCopy="1"/>
|
<MODULES id="juce_audio_plugin_client" showAllCode="1" useLocalCopy="1"/>
|
||||||
<MODULES id="juce_audio_processors" showAllCode="1" useLocalCopy="1"/>
|
<MODULES id="juce_audio_processors" showAllCode="1" useLocalCopy="1"/>
|
||||||
|
<MODULE id="juce_audio_utils" showAllCode="1" useLocalCopy="1" useGlobalPath="0"/>
|
||||||
<MODULES id="juce_core" showAllCode="1" useLocalCopy="1"/>
|
<MODULES id="juce_core" showAllCode="1" useLocalCopy="1"/>
|
||||||
<MODULES id="juce_cryptography" showAllCode="1" useLocalCopy="1"/>
|
<MODULES id="juce_cryptography" showAllCode="1" useLocalCopy="1"/>
|
||||||
<MODULES id="juce_data_structures" showAllCode="1" useLocalCopy="1"/>
|
<MODULES id="juce_data_structures" showAllCode="1" useLocalCopy="1"/>
|
||||||
|
@ -80,68 +85,61 @@
|
||||||
</MODULES>
|
</MODULES>
|
||||||
<JUCEOPTIONS JUCE_QUICKTIME="disabled"/>
|
<JUCEOPTIONS JUCE_QUICKTIME="disabled"/>
|
||||||
<EXPORTFORMATS>
|
<EXPORTFORMATS>
|
||||||
<VS2015 targetFolder="Builds/VisualStudio2015" vstFolder="C:\code\audio\VST3 SDK"
|
<XCODE_IPHONE targetFolder="Builds/iOS" iosDevelopmentTeamID="" iosScreenOrientation="landscape"
|
||||||
extraCompilerFlags="/wd4458" vst3Folder="">
|
iPadScreenOrientation="landscape" UIFileSharingEnabled="1" UIStatusBarHidden="1"
|
||||||
|
iosBackgroundAudio="1" iosBackgroundBle="1" UISupportsDocumentBrowser="1"
|
||||||
|
iosDeviceFamily="2" smallIcon="aNR5I9" bigIcon="aNR5I9">
|
||||||
<CONFIGURATIONS>
|
<CONFIGURATIONS>
|
||||||
<CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="32-bit"
|
<CONFIGURATION isDebug="1" name="Debug"/>
|
||||||
isDebug="1" optimisation="1" targetName="JuceOPLVSTi" debugInformationFormat="ProgramDatabase"
|
<CONFIGURATION isDebug="0" name="Release" linkTimeOptimisation="1"/>
|
||||||
enablePluginBinaryCopyStep="0"/>
|
|
||||||
<CONFIGURATION name="Release - 64-bit" winWarningLevel="4" generateManifest="1"
|
|
||||||
winArchitecture="x64" isDebug="0" optimisation="3" targetName="JuceOPLVSTi x64"
|
|
||||||
warningsAreErrors="1" headerPath="" debugInformationFormat="ProgramDatabase"
|
|
||||||
enablePluginBinaryCopyStep="0" linkTimeOptimisation="1"/>
|
|
||||||
<CONFIGURATION name="Release - 32-bit" winWarningLevel="4" generateManifest="1"
|
|
||||||
winArchitecture="32-bit" isDebug="0" optimisation="3" targetName="JuceOPLVSTi"
|
|
||||||
warningsAreErrors="1" headerPath="" debugInformationFormat="ProgramDatabase"
|
|
||||||
enablePluginBinaryCopyStep="0" linkTimeOptimisation="1"/>
|
|
||||||
</CONFIGURATIONS>
|
</CONFIGURATIONS>
|
||||||
<MODULEPATHS>
|
<MODULEPATHS>
|
||||||
<MODULEPATH id="juce_video" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_video" path="modules"/>
|
||||||
<MODULEPATH id="juce_opengl" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_opengl" path="modules"/>
|
||||||
<MODULEPATH id="juce_gui_extra" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_gui_extra" path="modules"/>
|
||||||
<MODULEPATH id="juce_gui_basics" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_gui_basics" path="modules"/>
|
||||||
<MODULEPATH id="juce_graphics" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_graphics" path="modules"/>
|
||||||
<MODULEPATH id="juce_events" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_events" path="modules"/>
|
||||||
<MODULEPATH id="juce_data_structures" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_data_structures" path="modules"/>
|
||||||
<MODULEPATH id="juce_cryptography" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_cryptography" path="modules"/>
|
||||||
<MODULEPATH id="juce_core" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_core" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_processors" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_processors" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_plugin_client" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_plugin_client" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_formats" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_formats" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_devices" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_devices" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_basics" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_basics" path="modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_utils" path="modules"/>
|
||||||
</MODULEPATHS>
|
</MODULEPATHS>
|
||||||
</VS2015>
|
</XCODE_IPHONE>
|
||||||
<VS2017 targetFolder="Builds/VisualStudio2017">
|
<XCODE_MAC targetFolder="Builds/MacOSX" iosDevelopmentTeamID=""
|
||||||
|
vstLegacyFolder="modules/vstsdk2.4" vst3Folder="modules/vstsdk3"
|
||||||
|
smallIcon="aNR5I9" bigIcon="aNR5I9">
|
||||||
<CONFIGURATIONS>
|
<CONFIGURATIONS>
|
||||||
<CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="x64"
|
<CONFIGURATION isDebug="1" name="Debug"/>
|
||||||
debugInformationFormat="ProgramDatabase" enablePluginBinaryCopyStep="0"
|
<CONFIGURATION isDebug="0" name="Release" linkTimeOptimisation="1"/>
|
||||||
linkTimeOptimisation="0" isDebug="1" optimisation="1" targetName="JuceOPLVSTi"/>
|
|
||||||
<CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="x64"
|
|
||||||
debugInformationFormat="ProgramDatabase" enablePluginBinaryCopyStep="0"
|
|
||||||
linkTimeOptimisation="1" isDebug="0" optimisation="3" targetName="JuceOPLVSTi x64"
|
|
||||||
warningsAreErrors="0"/>
|
|
||||||
</CONFIGURATIONS>
|
</CONFIGURATIONS>
|
||||||
<MODULEPATHS>
|
<MODULEPATHS>
|
||||||
<MODULEPATH id="juce_video" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_video" path="modules"/>
|
||||||
<MODULEPATH id="juce_opengl" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_opengl" path="modules"/>
|
||||||
<MODULEPATH id="juce_gui_extra" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_gui_extra" path="modules"/>
|
||||||
<MODULEPATH id="juce_gui_basics" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_gui_basics" path="modules"/>
|
||||||
<MODULEPATH id="juce_graphics" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_graphics" path="modules"/>
|
||||||
<MODULEPATH id="juce_events" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_events" path="modules"/>
|
||||||
<MODULEPATH id="juce_data_structures" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_data_structures" path="modules"/>
|
||||||
<MODULEPATH id="juce_cryptography" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_cryptography" path="modules"/>
|
||||||
<MODULEPATH id="juce_core" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_core" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_processors" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_utils" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_plugin_client" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_processors" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_formats" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_plugin_client" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_devices" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_formats" path="modules"/>
|
||||||
<MODULEPATH id="juce_audio_basics" path="..\JUCE\modules"/>
|
<MODULEPATH id="juce_audio_devices" path="modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_basics" path="modules"/>
|
||||||
</MODULEPATHS>
|
</MODULEPATHS>
|
||||||
</VS2017>
|
</XCODE_MAC>
|
||||||
</EXPORTFORMATS>
|
</EXPORTFORMATS>
|
||||||
<LIVE_SETTINGS>
|
<LIVE_SETTINGS>
|
||||||
<WINDOWS systemHeaderPath="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include"
|
<WINDOWS systemHeaderPath="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include"
|
||||||
liveWindowsTargetPlatformVersion="10.0.10586.0" defines=""/>
|
liveWindowsTargetPlatformVersion="10.0.10586.0" defines=""/>
|
||||||
|
<OSX/>
|
||||||
</LIVE_SETTINGS>
|
</LIVE_SETTINGS>
|
||||||
</JUCERPROJECT>
|
</JUCERPROJECT>
|
|
@ -1,23 +0,0 @@
|
||||||
@ECHO OFF
|
|
||||||
IF [%1]==[] GOTO usage
|
|
||||||
|
|
||||||
ECHO Building Windows Release
|
|
||||||
SET RELEASE_VERSION=%1
|
|
||||||
|
|
||||||
MSBUILD Builds\VisualStudio2015\JuceOPLVSTi.vcxproj /p:Configuration="Release - 32-bit" /p:Platform="x86"
|
|
||||||
MSBUILD Builds\VisualStudio2015\JuceOPLVSTi.vcxproj /p:Configuration="Release - 64-bit" /p:Platform="x64"
|
|
||||||
|
|
||||||
MKDIR %RELEASE_TEMP%
|
|
||||||
COPY "Builds\VisualStudio2015\Release - 32-bit\JuceOPLVSTi.dll" .
|
|
||||||
COPY "Builds\VisualStudio2015\x64\Release - 64-bit\JuceOPLVSTi x64.dll" .
|
|
||||||
|
|
||||||
REM We can zip using jar from the JDK!
|
|
||||||
REM http://stackoverflow.com/a/29879102/1480560
|
|
||||||
DEL JuceOPLVSTi_%RELEASE_VERSION%.zip
|
|
||||||
jar -cMf JuceOPLVSTi_%RELEASE_VERSION%.zip "JuceOPLVSTi x64.dll" JuceOPLVSTi.dll Instruments
|
|
||||||
DEL "JuceOPLVSTi x64.dll" JuceOPLVSTi.dll
|
|
||||||
GOTO :eof
|
|
||||||
|
|
||||||
:usage
|
|
||||||
ECHO Specify version on command line (eg 0-14-1)
|
|
||||||
|
|
182
dro2midi/README
|
@ -1,182 +0,0 @@
|
||||||
---------------------------------------------------------------
|
|
||||||
DRO2MIDI - version 1.6 (2013-11-29)
|
|
||||||
Written by malvineous@shikadi.net
|
|
||||||
Heavily based upon IMF2MIDI written by Guenter Nagler in 1996
|
|
||||||
http://www.shikadi.net/utils/
|
|
||||||
---------------------------------------------------------------
|
|
||||||
|
|
||||||
// What is it?
|
|
||||||
////////////////
|
|
||||||
|
|
||||||
DRO2MIDI converts Adlib music (in .dro, .imf or .raw format) into standard
|
|
||||||
MIDI files, so that it can be played or edited in most audio applications, or
|
|
||||||
so the notes can be extracted to be played on a real instrument.
|
|
||||||
|
|
||||||
// Features
|
|
||||||
/////////////
|
|
||||||
|
|
||||||
* Converts DOSBox .dro captures, id Software .imf songs and Rdos .raw captures
|
|
||||||
|
|
||||||
* Converts OPL frequency changes into MIDI pitchbends
|
|
||||||
|
|
||||||
* Tries to map Adlib instruments to MIDI instruments as best it can, but
|
|
||||||
these mappings can be easily added to and changed
|
|
||||||
|
|
||||||
* Instruments can also be mapped to MIDI percussion
|
|
||||||
|
|
||||||
* OPL rhythm-mode percussion is converted (v1.4 adds support for user-defined
|
|
||||||
mapping via new syntax in the mapping file)
|
|
||||||
|
|
||||||
* The OPL conversion constant can be changed (see -c option) to more
|
|
||||||
accurately convert notes without excessive pitchbend events
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
//////////
|
|
||||||
|
|
||||||
Linux: $ dro2midi file.dro file.mid
|
|
||||||
|
|
||||||
Windows: C:\>dro2midi file.dro file.mid
|
|
||||||
|
|
||||||
For a list of the command line options run dro2midi with no parameters or
|
|
||||||
see below for more details. For best results, all the .txt data files should
|
|
||||||
be in the current directory.
|
|
||||||
|
|
||||||
Instrument mappings between Adlib registers and MIDI instruments are stored in
|
|
||||||
inst.txt. This file contains a number of existing mappings, but additional
|
|
||||||
mappings can easily be added. During conversion, if an exact match cannot
|
|
||||||
be found the mapping with the closest Adlib parameters will be used instead.
|
|
||||||
A message will be printed when this happens, along with a line that can be
|
|
||||||
copied into inst.txt to provide an exact match. This approximation can have
|
|
||||||
the unfortunate side effect of providing some odd conversions, such as
|
|
||||||
converting a bass-line into a monotonic drum.
|
|
||||||
|
|
||||||
To get a perfect conversion you may wish to delete all but the first
|
|
||||||
"all-zero" instrument in inst.txt, which will cause all instruments to be
|
|
||||||
converted as a piano. You can then copy the definitions printed during
|
|
||||||
conversion one by one into inst.txt, to assign the best-sounding instrument
|
|
||||||
without worring about any default mappings taking over. Alternatively the -i
|
|
||||||
option can be used which will disable the closest-match algorithm, and only
|
|
||||||
exact matches will be used (again, anything that can't be exactly matched will
|
|
||||||
be mapped as a piano.)
|
|
||||||
|
|
||||||
// Command-line options
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
-p disables generation of MIDI pitchbends. This results in a single note-on
|
|
||||||
when the instrument sounds, but no further pitch change results until the
|
|
||||||
note is switched off again. This can also be used to prevent the large number
|
|
||||||
of small pitchbends generated when the conversion constant is slightly off (but
|
|
||||||
see the -c option, which now provides a better way around this.)
|
|
||||||
|
|
||||||
-a will, if pitchbends are disabled with -p, approximate any pitchbend by
|
|
||||||
playing the nearest note to the new pitch at the time. This results in a
|
|
||||||
"hammering" of notes during a pitchbend, which while humourous, is probably
|
|
||||||
of limited use.
|
|
||||||
|
|
||||||
-r disables the conversion of OPL rhythm mode instruments. As OPL rhythm mode
|
|
||||||
conversion is now quite flexible, this option should rarely be needed.
|
|
||||||
|
|
||||||
-i will disable the approximation algorithm which selects similar instruments
|
|
||||||
when an exact match cannot be found in the mapping file (insts.txt). This is
|
|
||||||
useful when trying to create a perfect map for a single song, as it makes it
|
|
||||||
easier to pick out which instruments are being mapped. This option should not
|
|
||||||
be used for the final conversion however, as any instruments that haven't been
|
|
||||||
precisely mapped will come out (by default) as a grand piano. (This default
|
|
||||||
mapping is simply the first entry in insts.txt.)
|
|
||||||
|
|
||||||
-c changes the conversion constant used when converting OPL notes into their
|
|
||||||
MIDI equivalents. This is the heart of what DRO2MIDI does. Unfortunately
|
|
||||||
depending on which set of documents are available, those writing OPL *players*
|
|
||||||
are told the conversion constant is either 49716, or 50000. Thus half the
|
|
||||||
games out there use one, and half use the other. The result of using the wrong
|
|
||||||
constant in the DRO2MIDI conversion is a tiny difference in pitch when the song
|
|
||||||
is played (about 1/17th of a cent.) Most people will be unable to hear the
|
|
||||||
difference between these two values, however if the wrong constant is used by
|
|
||||||
DRO2MIDI during the conversion into MIDI, the resulting file will contain
|
|
||||||
thousands of small pitchbend events, as it tries to approximate the exact OPL
|
|
||||||
note played. Using -c to try a different constant should solve this problem.
|
|
||||||
The default constant is 49716, and "-c alt" will change the constant to 50000.
|
|
||||||
It is possible to specify an arbitrary constant like "-c 49999" however this
|
|
||||||
should be unnecessary unless the same nonstandard constant was used wherever
|
|
||||||
the song was originally played. Note that no error checking is performed here,
|
|
||||||
so out of range values could easily crash the program (not that that's a major
|
|
||||||
problem though...) After conversion the number of pitchbend events is
|
|
||||||
displayed at the end of the output, so it will be obvious when the correct
|
|
||||||
constant is in use as this number will be significantly smaller than with
|
|
||||||
any other constant.
|
|
||||||
|
|
||||||
-v disables the volume detection. Normally DRO2MIDI will take the OPL
|
|
||||||
carrier's "Level" amount and translate it to a MIDI note velocity. This will
|
|
||||||
result in the output MIDI file more accurately matching the loud and quiet
|
|
||||||
parts of the OPL song. Some songs (e.g. Stunts) somehow manage to work with
|
|
||||||
these volume levels set to zero, which results in very quiet MIDI files (there
|
|
||||||
is an internal limit as to how quiet a note can sound to prevent it being lost
|
|
||||||
entirely.) If your output MIDI file is much too quiet, this option will cause
|
|
||||||
all notes to be played at maximum velocity.
|
|
||||||
|
|
||||||
-s instructs dro2midi to write all detected instruments to a .sbi file. This
|
|
||||||
is a 52 byte binary instrument format for OPL chips created by Creative Labs.
|
|
||||||
It is supported by applications written to work with the OPL, such as Ad Lib
|
|
||||||
Tracker 2.
|
|
||||||
|
|
||||||
// inst.txt
|
|
||||||
/////////////
|
|
||||||
|
|
||||||
The instrument mappings are stored in inst.txt, in a format like this:
|
|
||||||
|
|
||||||
NO 07-12/4F-00/F2-F2/60-72/08/00-00: patch=15 # Tubular bells
|
|
||||||
|
|
||||||
These lines are printed automatically when an unknown instrument is encounted.
|
|
||||||
All you will need to do is copy and paste the line into insts.txt and choose
|
|
||||||
a MIDI instrument for it. The file itself is read in from the current
|
|
||||||
directory during conversion, so if you run DRO2MIDI in another folder remember
|
|
||||||
to copy the file across too or your mappings won't be used.
|
|
||||||
|
|
||||||
The first two characters indicate what type of instrument it is. The
|
|
||||||
hexadecimal numbers that follow are the Adlib register values for that
|
|
||||||
instrument. "patch=15" assigns MIDI instrument #15 for this Adlib instrument.
|
|
||||||
For percussion, "drum=35" could be used instead. Anything after a # symbol is
|
|
||||||
treated as a comment. See the comments at the top of the file for more
|
|
||||||
detailed information.
|
|
||||||
|
|
||||||
The instrument names (and values to supply to the patch= parameter) are stored
|
|
||||||
in patch.txt, and the drum names (and numbers) in drum.txt. You may find
|
|
||||||
these files helpful to reference when selecting instruments for conversion.
|
|
||||||
(These two files are read in from the current directory during conversion to
|
|
||||||
allow the display of instrument names in status messages instead of just
|
|
||||||
numbers.)
|
|
||||||
|
|
||||||
Note that the parser for insts.txt file is quick and dirty, so it's easy to
|
|
||||||
get a syntax error - for example, an otherwise blank line with a single space
|
|
||||||
on it will cause an error (so if you get an error about a blank line, make
|
|
||||||
sure it really is blank!)
|
|
||||||
|
|
||||||
// License
|
|
||||||
////////////
|
|
||||||
|
|
||||||
DRO2MIDI was based on IMF2MIDI by Guenter Nagler. DRO2MIDI is released under
|
|
||||||
the GPL license, except where it is incompatible with IMF2MIDI's original
|
|
||||||
license, in which case IMF2MIDI's license takes precedence.
|
|
||||||
|
|
||||||
---- Begin IMF2MIDI license ----
|
|
||||||
|
|
||||||
IMF2MIDI (c) 1996 was created by Guenter Nagler.
|
|
||||||
|
|
||||||
IMF2MIDI is free and may be used as you wish with this one exception:
|
|
||||||
|
|
||||||
You may NOT charge any fee or derive any profit for distribution
|
|
||||||
of IMF2MIDI. Thus, you may NOT sell or bundle IMF2MIDI with any
|
|
||||||
product in a retail environment (shareware disk distribution, CD-ROM,
|
|
||||||
etc.) without permission of the author.
|
|
||||||
|
|
||||||
You may give IMF2MIDI to your friends, upload it to a BBS, or ftp it to
|
|
||||||
another internet site, as long as you don't charge anything for it.
|
|
||||||
|
|
||||||
---- End IMF2MIDI license ----
|
|
||||||
|
|
||||||
// Contact
|
|
||||||
////////////
|
|
||||||
|
|
||||||
Source code is available at http://www.shikadi.net/utils/
|
|
||||||
|
|
||||||
You can e-mail me at malvineous@shikadi.net
|
|
|
@ -1 +0,0 @@
|
||||||
cl midiio.cpp dro2midi.cpp /link /OUT:dro2midi.exe
|
|
|
@ -1,74 +0,0 @@
|
||||||
//
|
|
||||||
// gen_test_midi.cpp - by malvineous@shikadi.net
|
|
||||||
//
|
|
||||||
// Generate a MIDI file that plays one note from all 128 GM instruments (in
|
|
||||||
// order), followed by all the percussion notes.
|
|
||||||
//
|
|
||||||
// When this file is played through an OPL synthesiser capable of MIDI
|
|
||||||
// playback, then captured through DOSBox, it will provide a complete set of
|
|
||||||
// OPL patches that can easily be associated back to MIDI instruments.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "midiio.hpp"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define WRITE_BINARY "wb"
|
|
||||||
#define READ_TEXT "r"
|
|
||||||
|
|
||||||
int main(int argc, char**argv)
|
|
||||||
{
|
|
||||||
if (argc != 2) {
|
|
||||||
fprintf(stderr, "no output filename given\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
MidiWrite *write = new MidiWrite(argv[1]);
|
|
||||||
if (!write) {
|
|
||||||
fprintf(stderr, "out of memory\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!write->getf()) {
|
|
||||||
perror(argv[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float tempo = 120.0;
|
|
||||||
int resolution = 280;
|
|
||||||
write->head(/* version */ 0, /* track count updated later */0, resolution);
|
|
||||||
|
|
||||||
write->track();
|
|
||||||
write->tempo((long)(60000000.0 / tempo));
|
|
||||||
write->tact(4,4,24,8);
|
|
||||||
|
|
||||||
write->volume(1, 127);
|
|
||||||
write->volume(9, 127);
|
|
||||||
for (int i = 0; i < 128; i++) {
|
|
||||||
write->program(1, i);
|
|
||||||
write->noteon(1, 60, 127);
|
|
||||||
write->time(50);
|
|
||||||
write->noteoff(1, 60);
|
|
||||||
write->time(50);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
// Need to play a normal note for percussion to get DOSBox to start capturing
|
|
||||||
// OPL data! (Why hasn't my patch to fix that been incorporated yet?!)
|
|
||||||
write->noteon(1, 60, 127);
|
|
||||||
write->time(50);
|
|
||||||
write->noteoff(1, 60);
|
|
||||||
write->time(200);
|
|
||||||
for (int i = 35; i < 82; i++) {
|
|
||||||
write->noteon(9, i, 127);
|
|
||||||
write->time(50);
|
|
||||||
write->noteoff(9, i);
|
|
||||||
write->time(50);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
delete write;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Usage:
|
|
||||||
#
|
|
||||||
# ./make
|
|
||||||
#
|
|
||||||
# or if you have a cross compiler for i586-pc-mingw32 installed
|
|
||||||
#
|
|
||||||
# ./make i586-pc-mingw32 .exe
|
|
||||||
#
|
|
||||||
|
|
||||||
if [ "$1" != "" ]; then
|
|
||||||
PLATFORM="$1"-
|
|
||||||
TARGET="dro2midi$2"
|
|
||||||
else
|
|
||||||
PLATFORM=""
|
|
||||||
TARGET="dro2midi"
|
|
||||||
fi
|
|
||||||
|
|
||||||
${PLATFORM}g++ -o ${TARGET} dro2midi.cpp midiio.cpp &&
|
|
||||||
${PLATFORM}strip ${TARGET}
|
|
2161
dro2midi/midiio.cpp
|
@ -1,402 +0,0 @@
|
||||||
#ifndef __MIDIIO__
|
|
||||||
#define __MIDIIO__
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#ifndef MIDI_BUFSIZE
|
|
||||||
#define MIDI_BUFSIZE 1024
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// opening modes of a midi file
|
|
||||||
#define WRITE_BINARY "wb"
|
|
||||||
#define READ_BINARY "rb"
|
|
||||||
|
|
||||||
const unsigned long MThd = 0x4D546864ul;
|
|
||||||
const unsigned long MTrk = 0x4D54726Bul;
|
|
||||||
|
|
||||||
// different standard midi formats
|
|
||||||
#define VERSION_MULTICHANNEL 0
|
|
||||||
#define VERSION_SINGLECHANNEL 1
|
|
||||||
#define VERSION_MULTISONG 2
|
|
||||||
|
|
||||||
#define OPTION_NOCONTROLS 1 // no control details but general information
|
|
||||||
#define OPTION_NOEVENTS 2 // no track events at all
|
|
||||||
#define OPTION_NOMETAEVENTS 4 // no meta details but general information
|
|
||||||
#define OPTION_NOSYSEVENTS 8 // no sysex details but general information
|
|
||||||
#define OPTION_NONOTEEVENTS 16 // no note events (8x or 9x)
|
|
||||||
#define OPTION_NOPOLYEVENTS 32 // no poly aftertouch events (Ax)
|
|
||||||
#define OPTION_NOCONTROLEVENTS 64 // no control events at all (Bx)
|
|
||||||
#define OPTION_NOPROGRAMEVENTS 128 // no program change events (Cx)
|
|
||||||
#define OPTION_NOAFTERTOUCHEVENTS 256 // no aftertouch events (Dx)
|
|
||||||
#define OPTION_NOPITCHBENDEVENTS 512 // no pitchbend events (Ex)
|
|
||||||
#define OPTION_NOREALTIMEEVENTS 1024 // no realtime events (Fx)
|
|
||||||
|
|
||||||
// getchannel delivers a valid channel or:
|
|
||||||
#define NOCHANNEL (-1)
|
|
||||||
#define MULTICHANNEL (-2)
|
|
||||||
#define VALIDCHANNEL(ch) ((ch) >= 0 && (ch) <= 15)
|
|
||||||
#define gm_drumchannel 9
|
|
||||||
#define SAYCHANNEL(ch) ((ch) + 1) // 0..15 in midi format but spoken 1..16!
|
|
||||||
|
|
||||||
// for use of param what in function text()
|
|
||||||
#define meta_text 1
|
|
||||||
#define meta_copyright 2
|
|
||||||
#define meta_trackname 3
|
|
||||||
#define meta_instrument 4
|
|
||||||
#define meta_lyric 5
|
|
||||||
#define meta_marker 6
|
|
||||||
#define meta_cuepoint 7
|
|
||||||
#define meta_endtrack 0x2f
|
|
||||||
|
|
||||||
#define ctrl_highbank 0
|
|
||||||
#define ctrl_wheel 1
|
|
||||||
#define ctrl_breath 2
|
|
||||||
#define ctrl_foot 4
|
|
||||||
#define ctrl_portamentotime 5
|
|
||||||
#define ctrl_data 6
|
|
||||||
#define ctrl_volume 7
|
|
||||||
#define ctrl_balance 10
|
|
||||||
#define ctrl_expression 11
|
|
||||||
#define ctrl_lowbank 32
|
|
||||||
#define ctrl_hold 64
|
|
||||||
#define ctrl_reverb 91
|
|
||||||
#define ctrl_chorus 93
|
|
||||||
#define ctrl_datainc 96
|
|
||||||
#define ctrl_datadec 97
|
|
||||||
#define ctrl_lowrpn 100
|
|
||||||
#define ctrl_highrpn 101
|
|
||||||
#define ctrl_resetctrlrs 121
|
|
||||||
#define ctrl_allnotesoff 123
|
|
||||||
|
|
||||||
#define balance_left 0
|
|
||||||
#define balance_center 64
|
|
||||||
#define balance_right 127
|
|
||||||
|
|
||||||
#define volume_mute 0
|
|
||||||
#define volume_full 127
|
|
||||||
|
|
||||||
#define bpm(ticks) (60000000.0 / (ticks))
|
|
||||||
#define ticks(beats) ((unsigned long)(60000000.0 / (beats)))
|
|
||||||
|
|
||||||
#define tempo_60bpm (1000000L)
|
|
||||||
#define tempo_120bpm (500000L)
|
|
||||||
#define tempo_240bpm (250000L)
|
|
||||||
|
|
||||||
|
|
||||||
class MidiRead
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const char* copyright();
|
|
||||||
|
|
||||||
MidiRead(const char* filename, FILE* f = 0);
|
|
||||||
virtual ~MidiRead();
|
|
||||||
|
|
||||||
FILE* getf();
|
|
||||||
|
|
||||||
int run();
|
|
||||||
int runhead();
|
|
||||||
int runtrack(int trackno);
|
|
||||||
int runevent(long trackend);
|
|
||||||
|
|
||||||
long getpos() { return pos_; }
|
|
||||||
long geteventpos() { return pos_; }
|
|
||||||
long getcurpos() { return curpos_; }
|
|
||||||
unsigned long getcurtime() { return curtime_; } // in midi units
|
|
||||||
|
|
||||||
virtual void head(unsigned version, unsigned tracks, unsigned clicksperquarter);
|
|
||||||
virtual void track(int trackno, long length, int channel);
|
|
||||||
virtual void endtrack(int trackno); // closing track
|
|
||||||
|
|
||||||
virtual void time(unsigned long ticks); // delay between events
|
|
||||||
|
|
||||||
virtual void event(int what, int len = 0, unsigned char* data = 0);
|
|
||||||
|
|
||||||
// these are event categories:
|
|
||||||
virtual void meta(int what, int len, const unsigned char* data);
|
|
||||||
// these are special meta events:
|
|
||||||
virtual void text(int what, int len, const char* whattext, const unsigned char* txt);
|
|
||||||
virtual void end(); // end of track command
|
|
||||||
virtual void prefixchannel(unsigned char channel);
|
|
||||||
virtual void prefixport(unsigned char port);
|
|
||||||
virtual void seqnumber(unsigned int seqno);
|
|
||||||
virtual void smpteofs(int hour, int min, int sec, int frame, int fracframe);
|
|
||||||
virtual void tact(int nom, int denom, int clicksperbeat, int notes32perbeat);
|
|
||||||
virtual void tempo(unsigned long microsecperbeat);
|
|
||||||
virtual void key(int signature, int isminor); // C=0, -7=7flats +7=7sharps
|
|
||||||
virtual void program(int channel, int prg);
|
|
||||||
virtual void control(int channel, int what, int val); // general controls
|
|
||||||
// special controls:
|
|
||||||
virtual void highbank(int channel, int val);
|
|
||||||
virtual void wheel(int channel, int val);
|
|
||||||
virtual void breath(int channel, int val);
|
|
||||||
virtual void foot(int channel, int val);
|
|
||||||
virtual void portamentotime(int channel, int val);
|
|
||||||
virtual void data(int channel, int val);
|
|
||||||
virtual void volume(int channel, int val);
|
|
||||||
virtual void balance(int channel, int val);
|
|
||||||
virtual void expression(int channel, int val);
|
|
||||||
virtual void lowbank(int channel, int val);
|
|
||||||
virtual void hold(int channel, int val);
|
|
||||||
virtual void reverb(int channel, int val);
|
|
||||||
virtual void chorus(int channel, int val);
|
|
||||||
virtual void datainc(int channel, int val);
|
|
||||||
virtual void datadec(int channel, int val);
|
|
||||||
virtual void lowrpn(int channel, int val);
|
|
||||||
virtual void highrpn(int channel, int val);
|
|
||||||
virtual void resetctrlrs(int channel, int val);
|
|
||||||
virtual void allnotesoff(int channel, int val);
|
|
||||||
virtual void pitchbendrange(int channel, int val);
|
|
||||||
virtual void noteon(int channel, int note, int vel);
|
|
||||||
virtual void noteoff(int channel, int note, int vel);
|
|
||||||
virtual void pitchbend(int channel, int val);
|
|
||||||
virtual void polyaftertouch(int channel, int note, int val);
|
|
||||||
virtual void aftertouch(int channel, int val);
|
|
||||||
virtual void songpos(unsigned pos);
|
|
||||||
virtual void songselect(unsigned char song);
|
|
||||||
virtual void tunerequest();
|
|
||||||
virtual void timingclock();
|
|
||||||
virtual void start();
|
|
||||||
virtual void cont();
|
|
||||||
virtual void stop();
|
|
||||||
virtual void activesense();
|
|
||||||
virtual void sysex(int syslen, const unsigned char* sysdata);
|
|
||||||
// these are special sysex events:
|
|
||||||
virtual void xgreset();
|
|
||||||
virtual void gmreset();
|
|
||||||
virtual void gsreset();
|
|
||||||
virtual void gsexit();
|
|
||||||
|
|
||||||
virtual void endmidi(); // after last track
|
|
||||||
virtual void error(const char* msg);
|
|
||||||
virtual void warning(const char* msg);
|
|
||||||
|
|
||||||
virtual void percent(int perc);
|
|
||||||
|
|
||||||
int getchannel() { return curchannel_; }
|
|
||||||
void setchannel(int channel);
|
|
||||||
|
|
||||||
static const char* progname(int n, int channel);
|
|
||||||
static const char* notename(unsigned char note);
|
|
||||||
|
|
||||||
int options_;
|
|
||||||
|
|
||||||
int version_, tracks_, clicks_, trackno_;
|
|
||||||
|
|
||||||
void seek(long pos);
|
|
||||||
int getbyte();
|
|
||||||
unsigned getword();
|
|
||||||
unsigned long gettri();
|
|
||||||
unsigned long getlong();
|
|
||||||
unsigned long getdelta();
|
|
||||||
unsigned char* get(int len);
|
|
||||||
unsigned char* need(int nbytes);
|
|
||||||
|
|
||||||
unsigned long microsec(unsigned long units, unsigned long msperbeats);
|
|
||||||
long units(unsigned long microsec, unsigned long msperbeats);
|
|
||||||
|
|
||||||
// use scanchannel only at start of track!
|
|
||||||
int scanchannel(unsigned long maxlen); // channel 0-15 or -1=no channel or -2=multichannels
|
|
||||||
|
|
||||||
// use sysevent only directly after reading F0 or F7
|
|
||||||
int scansysevent(unsigned long maxlen);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const char *midiname_;
|
|
||||||
FILE* f_;
|
|
||||||
unsigned char shouldclose_; // 0=no, otherwise=yes
|
|
||||||
long filesize_;
|
|
||||||
unsigned char buf_[MIDI_BUFSIZE];
|
|
||||||
int buflen_, bufpos_;
|
|
||||||
int curchannel_;
|
|
||||||
unsigned long curtime_;
|
|
||||||
int percent_;
|
|
||||||
int lastcode_;
|
|
||||||
unsigned long tracklen_;
|
|
||||||
|
|
||||||
long pos_, curpos_;
|
|
||||||
unsigned char curdeltalen_; // number of bytes read by recent getdelta() call
|
|
||||||
};
|
|
||||||
|
|
||||||
class MidiWrite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const char* copyright();
|
|
||||||
|
|
||||||
MidiWrite(const char* filename);
|
|
||||||
virtual ~MidiWrite();
|
|
||||||
|
|
||||||
FILE* getf();
|
|
||||||
|
|
||||||
long getcurpos() { return curpos_; }
|
|
||||||
long getcurtime() { return curtime_; }
|
|
||||||
void cleardelta();
|
|
||||||
|
|
||||||
void head(int version = 1, int tracks = 0, unsigned clicksperquarter = 192);
|
|
||||||
void track();
|
|
||||||
void endtrack();
|
|
||||||
|
|
||||||
void event(int what, int len, const unsigned char* data);
|
|
||||||
|
|
||||||
void text(int what, int len, const unsigned char* txt);
|
|
||||||
void meta(int what, int len, const unsigned char* data); // 0xff ....
|
|
||||||
virtual void prefixchannel(unsigned char channel);
|
|
||||||
virtual void prefixport(unsigned char port);
|
|
||||||
virtual void seqnumber(unsigned int seqno);
|
|
||||||
virtual void smpteofs(int hour, int min, int sec, int frame, int fracframe);
|
|
||||||
virtual void key(int signature, int isminor);
|
|
||||||
void tact(int nom, int denom, int v1, int v2);
|
|
||||||
void tempo(unsigned long microsecperbeat);
|
|
||||||
void end();
|
|
||||||
void program(int channel, int prg);
|
|
||||||
void control(int channel, int what, int val);
|
|
||||||
// these are special controls
|
|
||||||
void highbank(int channel, int val);
|
|
||||||
void wheel(int channel, int val);
|
|
||||||
void breath(int channel, int val);
|
|
||||||
void foot(int channel, int val);
|
|
||||||
void portamentotime(int channel, int val);
|
|
||||||
void data(int channel, int val);
|
|
||||||
void volume(int channel, int val);
|
|
||||||
void balance(int channel, int val);
|
|
||||||
void expression(int channel, int val);
|
|
||||||
void lowbank(int channel, int val);
|
|
||||||
void hold(int channel, int val);
|
|
||||||
void reverb(int channel, int val);
|
|
||||||
void chorus(int channel, int val);
|
|
||||||
void datainc(int channel, int val);
|
|
||||||
void datadec(int channel, int val);
|
|
||||||
void lowrpn(int channel, int val);
|
|
||||||
void highrpn(int channel, int val);
|
|
||||||
void resetctrlrs(int channel, int val);
|
|
||||||
void allnotesoff(int channel, int val);
|
|
||||||
void pitchbendrange(int channel, int halfnotes);
|
|
||||||
|
|
||||||
void noteon(int channel, int note, int vel);
|
|
||||||
void noteoff(int channel, int note, int vel = 0);
|
|
||||||
void time(unsigned long ticks);
|
|
||||||
void pitchbend(int channel, int val);
|
|
||||||
void polyaftertouch(int channel, int note, int val);
|
|
||||||
void aftertouch(int channel, int val);
|
|
||||||
void songpos(unsigned pos);
|
|
||||||
void songselect(unsigned char song);
|
|
||||||
void tunerequest();
|
|
||||||
void timingclock();
|
|
||||||
void start();
|
|
||||||
void cont();
|
|
||||||
void stop();
|
|
||||||
void activesense();
|
|
||||||
void sysex(int syslen, const unsigned char* sysdata);
|
|
||||||
void xgreset();
|
|
||||||
void gmreset();
|
|
||||||
void gsreset();
|
|
||||||
void gsexit();
|
|
||||||
|
|
||||||
void putbyte(unsigned char val);
|
|
||||||
void putcode(unsigned char code);
|
|
||||||
void putword(unsigned val);
|
|
||||||
void puttri(unsigned long val);
|
|
||||||
void putlong(unsigned long val);
|
|
||||||
void putdelta(unsigned long val);
|
|
||||||
void puttime();
|
|
||||||
void put(int len, const unsigned char* c);
|
|
||||||
void seek(long pos);
|
|
||||||
|
|
||||||
virtual void error(const char* msg);
|
|
||||||
virtual void warning(const char* msg);
|
|
||||||
|
|
||||||
int unitsperquarter();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const char *midiname_;
|
|
||||||
FILE* f_;
|
|
||||||
long trackpos_, curpos_, filesize_;
|
|
||||||
int trackchannel_, trackcount_, lastcode_, endtrack_;
|
|
||||||
|
|
||||||
unsigned char buf_[MIDI_BUFSIZE];
|
|
||||||
int bufpos_, buflen_;
|
|
||||||
|
|
||||||
unsigned long curdelta_;
|
|
||||||
unsigned long curtime_;
|
|
||||||
|
|
||||||
int clicks_;
|
|
||||||
|
|
||||||
void flush();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class MidiCopy : public MidiRead
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MidiCopy(const char* filename, FILE* f = 0);
|
|
||||||
|
|
||||||
void setoutput(MidiWrite* dest);
|
|
||||||
void stopoutput();
|
|
||||||
MidiWrite* getoutput();
|
|
||||||
|
|
||||||
void mapchannel(int channel, int newchannel);
|
|
||||||
void ignorechannel(int channel);
|
|
||||||
|
|
||||||
virtual void head(unsigned version, unsigned tracks, unsigned clicksperquarter);
|
|
||||||
virtual void track(int trackno, long length, int channel);
|
|
||||||
virtual void endtrack(int trackno);
|
|
||||||
|
|
||||||
virtual void time(unsigned long ticks);
|
|
||||||
|
|
||||||
virtual void event(int what, int len = 0, unsigned char* data = 0);
|
|
||||||
|
|
||||||
virtual void meta(int what, int len, unsigned char* data);
|
|
||||||
virtual void text(int what, int len, char* whattext, unsigned char* txt);
|
|
||||||
virtual void end();
|
|
||||||
virtual void prefixchannel(unsigned char channel);
|
|
||||||
virtual void prefixport(unsigned char port);
|
|
||||||
virtual void seqnumber(unsigned int seqno);
|
|
||||||
virtual void smpteofs(int hour, int min, int sec, int frame, int fracframe);
|
|
||||||
virtual void tact(int nom, int denom, int clicksperbeat, int notes32perbeat);
|
|
||||||
virtual void tempo(unsigned long microsecperbeat);
|
|
||||||
virtual void key(int signature, int isminor); // C=0, -7=7flats +7=7sharps
|
|
||||||
virtual void program(int channel, int prg);
|
|
||||||
virtual void control(int channel, int what, int val);
|
|
||||||
virtual void highbank(int channel, int val);
|
|
||||||
virtual void wheel(int channel, int val);
|
|
||||||
virtual void breath(int channel, int val);
|
|
||||||
virtual void foot(int channel, int val);
|
|
||||||
virtual void portamentotime(int channel, int val);
|
|
||||||
virtual void data(int channel, int val);
|
|
||||||
virtual void volume(int channel, int val);
|
|
||||||
virtual void balance(int channel, int val);
|
|
||||||
virtual void expression(int channel, int val);
|
|
||||||
virtual void lowbank(int channel, int val);
|
|
||||||
virtual void hold(int channel, int val);
|
|
||||||
virtual void reverb(int channel, int val);
|
|
||||||
virtual void chorus(int channel, int val);
|
|
||||||
virtual void datainc(int channel, int val);
|
|
||||||
virtual void datadec(int channel, int val);
|
|
||||||
virtual void lowrpn(int channel, int val);
|
|
||||||
virtual void highrpn(int channel, int val);
|
|
||||||
virtual void resetctrlrs(int channel, int val);
|
|
||||||
virtual void allnotesoff(int channel, int val);
|
|
||||||
virtual void noteon(int channel, int note, int vel);
|
|
||||||
virtual void noteoff(int channel, int note, int vel);
|
|
||||||
virtual void pitchbend(int channel, int val);
|
|
||||||
virtual void polyaftertouch(int channel, int note, int val);
|
|
||||||
virtual void aftertouch(int channel, int val);
|
|
||||||
virtual void songpos(unsigned pos);
|
|
||||||
virtual void songselect(unsigned char song);
|
|
||||||
virtual void tunerequest();
|
|
||||||
virtual void timingclock();
|
|
||||||
virtual void start();
|
|
||||||
virtual void cont();
|
|
||||||
virtual void stop();
|
|
||||||
virtual void activesense();
|
|
||||||
virtual void sysex(int syslen, unsigned char* sysdata);
|
|
||||||
virtual void gmreset();
|
|
||||||
virtual void gsreset();
|
|
||||||
virtual void gsexit();
|
|
||||||
virtual void xgreset();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
MidiWrite* dest_;
|
|
||||||
int mapchannel_[16]; // channel 0-15 or events are ignored for invalid channel
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
0
img/Two-OP AM.png
Normal file → Executable file
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
0
img/Two-OP FM.png
Normal file → Executable file
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
0
img/abs_sine.png
Normal file → Executable file
Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 181 B |
0
img/adlib.png
Normal file → Executable file
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
0
img/algo_switch_off.png
Normal file → Executable file
Before Width: | Height: | Size: 162 B After Width: | Height: | Size: 162 B |
0
img/algo_switch_on.png
Normal file → Executable file
Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 168 B |
0
img/algo_switch_on2.png
Normal file → Executable file
Before Width: | Height: | Size: 169 B After Width: | Height: | Size: 169 B |
0
img/algo_switch_on3.png
Normal file → Executable file
Before Width: | Height: | Size: 151 B After Width: | Height: | Size: 151 B |
0
img/alternating_sine.png
Normal file → Executable file
Before Width: | Height: | Size: 197 B After Width: | Height: | Size: 197 B |
0
img/bassdrum.png
Normal file → Executable file
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 234 B |
0
img/camel_sine.png
Normal file → Executable file
Before Width: | Height: | Size: 174 B After Width: | Height: | Size: 174 B |
0
img/channeloff.png
Normal file → Executable file
Before Width: | Height: | Size: 414 B After Width: | Height: | Size: 414 B |
0
img/channelon.png
Normal file → Executable file
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
0
img/cymbal.png
Normal file → Executable file
Before Width: | Height: | Size: 237 B After Width: | Height: | Size: 237 B |
0
img/disabled.png
Normal file → Executable file
Before Width: | Height: | Size: 210 B After Width: | Height: | Size: 210 B |
0
img/full_sine.png
Normal file → Executable file
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 203 B |
0
img/half_sine.png
Normal file → Executable file
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 179 B |
0
img/hihat.png
Normal file → Executable file
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 189 B |
0
img/line_border_horiz.png
Normal file → Executable file
Before Width: | Height: | Size: 108 B After Width: | Height: | Size: 108 B |
0
img/line_border_vert.png
Normal file → Executable file
Before Width: | Height: | Size: 107 B After Width: | Height: | Size: 107 B |
0
img/logarithmic_saw.png
Normal file → Executable file
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 206 B |
0
img/quarter_sine.png
Normal file → Executable file
Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 181 B |
0
img/snare.png
Normal file → Executable file
Before Width: | Height: | Size: 261 B After Width: | Height: | Size: 261 B |
0
img/square.png
Normal file → Executable file
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 179 B |
0
img/toggle_off_sq.png
Normal file → Executable file
Before Width: | Height: | Size: 118 B After Width: | Height: | Size: 118 B |
0
img/toggle_on_sq.png
Normal file → Executable file
Before Width: | Height: | Size: 134 B After Width: | Height: | Size: 134 B |
0
img/tom.png
Normal file → Executable file
Before Width: | Height: | Size: 231 B After Width: | Height: | Size: 231 B |
0
img/yamaha.png
Normal file → Executable file
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
@ -1,13 +0,0 @@
|
||||||
lvls = [.75, 1.5, 3, 6, 12, 24]
|
|
||||||
|
|
||||||
def get_db(i):
|
|
||||||
db = 0.0
|
|
||||||
for d in lvls:
|
|
||||||
if i & 0x1:
|
|
||||||
db += d
|
|
||||||
i >>= 1
|
|
||||||
return db
|
|
||||||
|
|
||||||
for i in range(2**6):
|
|
||||||
db = get_db(i)
|
|
||||||
print '"%.2f dB",' % db,
|
|
340
py/oplparse.py
|
@ -1,340 +0,0 @@
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
|
|
||||||
REG_SCOPE = {
|
|
||||||
0x00: 'Chip',
|
|
||||||
0x20: '0x20',
|
|
||||||
0x30: '0x20',
|
|
||||||
0x40: '0x40',
|
|
||||||
0x50: '0x40',
|
|
||||||
0x60: 'Attack/decay',
|
|
||||||
0x70: 'Attack/decay',
|
|
||||||
0x80: 'Sustain/release',
|
|
||||||
0x90: 'Sustain/release',
|
|
||||||
0xA0: 'Frequency (L)',
|
|
||||||
0xB0: 'Key on/off/Frequency(H)',
|
|
||||||
0xE0: 'Wave select',
|
|
||||||
0xF0: 'Wave select',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Map register ranges to channel + operator
|
|
||||||
OPERATOR_MAP = {
|
|
||||||
0x00: (1, 1),
|
|
||||||
0x01: (2, 1),
|
|
||||||
0x02: (3, 1),
|
|
||||||
0x03: (1, 2),
|
|
||||||
0x04: (2, 2),
|
|
||||||
0x05: (3, 2),
|
|
||||||
0x08: (4, 1),
|
|
||||||
0x09: (5, 1),
|
|
||||||
0x0a: (6, 1),
|
|
||||||
0x0b: (4, 2),
|
|
||||||
0x0c: (4, 2),
|
|
||||||
0x0d: (6, 2),
|
|
||||||
0x10: (7, 1),
|
|
||||||
0x11: (8, 1),
|
|
||||||
0x12: (9, 1),
|
|
||||||
0x13: (7, 2),
|
|
||||||
0x14: (8, 2),
|
|
||||||
0x15: (9, 2),
|
|
||||||
}
|
|
||||||
OSC_MAP = {1: 'mod', 2: 'car'}
|
|
||||||
|
|
||||||
def reg_to_chan_and_op(reg):
|
|
||||||
# from REGOP in opl driver
|
|
||||||
#return ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f )
|
|
||||||
chan, op = OPERATOR_MAP.get(reg % 32, (-1, 1))
|
|
||||||
print 'ch%02d.%s: ' % (chan, OSC_MAP[op]),
|
|
||||||
return chan, op
|
|
||||||
|
|
||||||
def interpret_00(reg, val, ev):
|
|
||||||
regs = {1:'TEST', 2:'Timer 1', 3:'Timer 2', 4:'Timer Ctrl', 8:'CSM/keysplit'}
|
|
||||||
print '%02X (%s)' % (reg, regs.get(reg, '??')),
|
|
||||||
|
|
||||||
def interpret_20(reg, val, ev):
|
|
||||||
ch, op = reg_to_chan_and_op(reg)
|
|
||||||
ev[2]['ch'] = ch
|
|
||||||
bitfields = {7: 'tre', 6: 'vib', 5: 'sus', 4:'ksr'}
|
|
||||||
bf = val & 0xf0
|
|
||||||
opts = []
|
|
||||||
for b, opt in bitfields.iteritems():
|
|
||||||
optset = 'X' if (bf & (0x1 << b)) else '-'
|
|
||||||
opts.append('%s:%s' % (opt, optset))
|
|
||||||
ev[op-1][opt]=optset
|
|
||||||
fm_mult = val & 0x0f
|
|
||||||
mults = {0:0.5, 11:10, 13:12, 14:15}
|
|
||||||
fm_mult = mults.get(fm_mult, fm_mult)
|
|
||||||
opts.append('fm_mult:x%d' % (fm_mult))
|
|
||||||
ev[op-1]['fm_mult'] = fm_mult
|
|
||||||
print '; '.join(opts) ,
|
|
||||||
|
|
||||||
def _db_atten_to_factor(atten_db):
|
|
||||||
return (10 ** -(atten_db / 10))
|
|
||||||
|
|
||||||
def interpret_40(reg, val, ev):
|
|
||||||
ch, op = reg_to_chan_and_op(reg)
|
|
||||||
ev[2]['ch'] = ch
|
|
||||||
bit_db = {5:24, 4:12, 3:6, 2:3, 1:1.5, 0:0.75}
|
|
||||||
oct_db = {0:0, 0x40:1.5, 0x80:3, 0xC0:6}
|
|
||||||
lvl = 0.0
|
|
||||||
for b, db in bit_db.iteritems():
|
|
||||||
if (val & (0x1 << b)):
|
|
||||||
lvl += db
|
|
||||||
db_oct = oct_db[val & 0xC0]
|
|
||||||
oct_scale = '-%d dB/8ve' % db_oct
|
|
||||||
factor = _db_atten_to_factor(lvl)
|
|
||||||
ev[op-1]['db'] = lvl
|
|
||||||
ev[op-1]['db_oct'] = db_oct
|
|
||||||
ev[op-1]['scale'] = factor
|
|
||||||
print '%.2f dB; (x%.4f) %s' % (lvl, factor, oct_scale) ,
|
|
||||||
|
|
||||||
def interpret_60(reg, val, ev):
|
|
||||||
ch, op = reg_to_chan_and_op(reg)
|
|
||||||
ev[2]['ch'] = ch
|
|
||||||
a = val >> 4
|
|
||||||
d = val & 0x0f
|
|
||||||
ev[op-1]['a'] = a
|
|
||||||
ev[op-1]['d'] = d
|
|
||||||
print 'Att: 0x%1x; Dec: 0x%1x' % (a, d) ,
|
|
||||||
|
|
||||||
def interpret_80(reg, val, ev):
|
|
||||||
ch, op = reg_to_chan_and_op(reg)
|
|
||||||
ev[2]['ch'] = ch
|
|
||||||
s = val >> 4
|
|
||||||
r = val & 0x0f
|
|
||||||
ev[op-1]['s'] = s
|
|
||||||
ev[op-1]['r'] = r
|
|
||||||
print 'Sus: 0x%1x; Rel: 0x%1x' % (s, r) ,
|
|
||||||
|
|
||||||
def interpret_A0(reg, val, ev):
|
|
||||||
global freq_lsb
|
|
||||||
freq_lsb = val
|
|
||||||
chan = 1 + reg % 0xA0
|
|
||||||
print 'ch%02d: Freq-LSB=%02X' % (chan, val) ,
|
|
||||||
|
|
||||||
def interpret_B0(reg, val, ev):
|
|
||||||
global freq_lsb
|
|
||||||
try:
|
|
||||||
freq_lsb
|
|
||||||
except NameError:
|
|
||||||
freq_lsb = 0
|
|
||||||
oct = (val >> 2) & 0x7
|
|
||||||
fnum = ((val & 0x3) << 8) + freq_lsb
|
|
||||||
chan = 1 + reg % 0xB0
|
|
||||||
key = 'ON' if (1 << 5) & val else 'off'
|
|
||||||
frq = _fnum_to_hz(fnum, oct)
|
|
||||||
ev[1]['frq'] = frq
|
|
||||||
ev[2]['key'] = key
|
|
||||||
ev[2]['ch'] = chan
|
|
||||||
#ev[0]['gate'] = key
|
|
||||||
print 'ch%02d: Key-%s; f0x%03X oct:%d (%.4f Hz)' % (chan, key, fnum, oct, frq) ,
|
|
||||||
|
|
||||||
'''
|
|
||||||
A0-A8: Frequency Number:
|
|
||||||
|
|
||||||
Determines the pitch of the note. Highest bits of F-Number are stored
|
|
||||||
in the register below.
|
|
||||||
|
|
||||||
|
|
||||||
B0-B8: Key On / Block Number / F-Number(hi bits):
|
|
||||||
|
|
||||||
bit 5: KEY-ON. When 1, channel output is enabled.
|
|
||||||
bits 2-4: Block Number. Roughly determines the octave.
|
|
||||||
bits 0-1: Frequency Number. 2 highest bits of the above register.
|
|
||||||
|
|
||||||
The following formula is used to determine F-Number and Block:
|
|
||||||
|
|
||||||
F-Number = Music Frequency * 2^(20-Block) / 49716 Hz
|
|
||||||
'''
|
|
||||||
|
|
||||||
def _fnum_to_hz(fnum, octave):
|
|
||||||
return (49716.0 * fnum) / (2 ** (21 - octave))
|
|
||||||
|
|
||||||
def interpret_BD(reg, val, ev):
|
|
||||||
print '* BD' ,
|
|
||||||
|
|
||||||
def interpret_C0(reg, val, ev):
|
|
||||||
alg = 'ADD' if val & 0x1 else 'MODULATE'
|
|
||||||
feedback = (val >> 1) & 0xc
|
|
||||||
ev[2]['alg'] = alg
|
|
||||||
ev[2]['feedback'] = feedback
|
|
||||||
print 'feedback: %d algo: %s' % (feedback, alg) ,
|
|
||||||
|
|
||||||
def interpret_E0(reg, val, ev):
|
|
||||||
ch, op = reg_to_chan_and_op(reg)
|
|
||||||
ev[2]['ch'] = ch
|
|
||||||
waves = {0: 'SIN', 1: 'HALFSIN', 2: 'ABSSIN', 3: 'QUARTSIN'}
|
|
||||||
wav = waves[val & 0x3]
|
|
||||||
ev[op-1]['wav'] = wav
|
|
||||||
print wav ,
|
|
||||||
|
|
||||||
def interpret_write(ts, reg, val, ev):
|
|
||||||
print '%10d : ' % ts,
|
|
||||||
if reg >= 0x01 and reg <= 0x08:
|
|
||||||
interpret_00(reg, val, ev)
|
|
||||||
elif reg >= 0x20 and reg <= 0x35:
|
|
||||||
interpret_20(reg, val, ev)
|
|
||||||
elif reg >= 0x40 and reg <= 0x55:
|
|
||||||
interpret_40(reg, val, ev)
|
|
||||||
elif reg >= 0x60 and reg <= 0x75:
|
|
||||||
interpret_60(reg, val, ev)
|
|
||||||
elif reg >= 0x80 and reg <= 0x95:
|
|
||||||
interpret_80(reg, val, ev)
|
|
||||||
elif reg >= 0xA0 and reg <= 0xA8:
|
|
||||||
interpret_A0(reg, val, ev)
|
|
||||||
elif reg >= 0xB0 and reg <= 0xB8:
|
|
||||||
interpret_B0(reg, val, ev)
|
|
||||||
elif reg == 0xBD:
|
|
||||||
interpret_BD(reg, val, ev)
|
|
||||||
elif reg >= 0xC0 and reg <= 0xC8:
|
|
||||||
interpret_C0(reg, val, ev)
|
|
||||||
elif reg >= 0xE0 and reg <= 0xF5:
|
|
||||||
interpret_E0(reg, val, ev)
|
|
||||||
else:
|
|
||||||
print '?????',
|
|
||||||
print
|
|
||||||
|
|
||||||
#scope = REG_SCOPE.get(reg & 0xF0, '??')
|
|
||||||
#chan, operator = reg_to_chan_and_op(reg)
|
|
||||||
#aprint '%10f : %02d.%1d : %02x : %20s' % (float(ts)/1000, chan, operator, val, scope)
|
|
||||||
|
|
||||||
def parse_opldump(stream):
|
|
||||||
events = dict()
|
|
||||||
t0 = tp = False
|
|
||||||
line = stream.readline()
|
|
||||||
while len(line) >= 1:
|
|
||||||
ts, opl2, op = line.split(':')
|
|
||||||
if 'OPL2' == opl2:
|
|
||||||
ts = int(ts)
|
|
||||||
if not t0:
|
|
||||||
t0 = ts
|
|
||||||
ts -= t0
|
|
||||||
reg, val = op.split('=')
|
|
||||||
reg = int(reg, 16)
|
|
||||||
val = int(val, 16)
|
|
||||||
try:
|
|
||||||
ev = events[ts]
|
|
||||||
except KeyError:
|
|
||||||
ev = [dict(), dict(), dict()]
|
|
||||||
events[ts] = ev
|
|
||||||
interpret_write(ts, reg, val, ev)
|
|
||||||
line = stream.readline()
|
|
||||||
return events
|
|
||||||
|
|
||||||
def get_javascript_for(event):
|
|
||||||
mod = event[0]
|
|
||||||
car = event[1]
|
|
||||||
anc = event[2]
|
|
||||||
indent = 8*' '
|
|
||||||
lines = []
|
|
||||||
if 'ch' in anc:
|
|
||||||
lines.append('var ch = opl2.channels[%d];\n' % (anc['ch'] - 1))
|
|
||||||
if 'fm_mult' in car:
|
|
||||||
lines.append('ch.setModulatorMultiplier(%d); ch.setCarrierMultiplier(%d);\n' % (mod['fm_mult'], car['fm_mult']))
|
|
||||||
if 'scale' in car:
|
|
||||||
lines.append('ch.setModulatorAttenuation(%f); ch.setCarrierAttenuation(%f);\n' % (mod['scale'], car['scale']))
|
|
||||||
if 'a' in mod:
|
|
||||||
lines.append('ch.setEnvParams(ch.modEnv, 1/%d, 1/%d, 1/%d, 1/%d);\n' % (mod['a'], mod['d'], mod['s']+1, mod['r']))
|
|
||||||
if 'a' in car:
|
|
||||||
lines.append('ch.setEnvParams(ch.carEnv, 1/%d, 1/%d, 1/%d, 1/%d);\n' % (car['a'], car['d'], car['s']+1, car['r']))
|
|
||||||
if 'wav' in car:
|
|
||||||
lines.append('ch.setCarrierWaveform(ch.%s); ch.setModulatorWaveform(ch.%s);\n' % (car['wav'], mod['wav']))
|
|
||||||
if 'key' in anc:
|
|
||||||
if 'ON' == anc['key'].upper():
|
|
||||||
lines.append('ch.noteOn(%f);\n' % car['frq'])
|
|
||||||
elif 'OFF' == anc['key'].upper():
|
|
||||||
lines.append('ch.noteOff();\n')
|
|
||||||
return indent + indent.join(lines)
|
|
||||||
|
|
||||||
|
|
||||||
def find_unique_instruments(events):
|
|
||||||
instruments = dict()
|
|
||||||
ilist = list()
|
|
||||||
timestamps = events.keys()
|
|
||||||
timestamps.sort()
|
|
||||||
for t in timestamps:
|
|
||||||
ev = events[t]
|
|
||||||
try: # get rid of fields which don't define uniqueness
|
|
||||||
del ev[2]['key']
|
|
||||||
del ev[2]['ch']
|
|
||||||
del ev[1]['frq']
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
instr_json = json.dumps(ev, indent=2)
|
|
||||||
if instr_json not in instruments:
|
|
||||||
instruments[instr_json] = t
|
|
||||||
ilist.append(instr_json)
|
|
||||||
return ilist, instruments
|
|
||||||
|
|
||||||
def print_instrument(json_i, ts):
|
|
||||||
print
|
|
||||||
print '@ %10d:' % ts
|
|
||||||
try:
|
|
||||||
d = json.loads(json_i)
|
|
||||||
print 'Waveforms: %10s%10s' % (d[0]['wav'], d[1]['wav'])
|
|
||||||
print 'Freq mult: %9dx%9dx' % (d[0]['fm_mult'], d[1]['fm_mult'])
|
|
||||||
print 'Levels: %7d dB%7d dB' % (-d[0]['db'], -d[1]['db'])
|
|
||||||
envs = (d[0]['a'], d[0]['d'], d[0]['s'], d[0]['r'], d[1]['a'], d[1]['d'], d[1]['s'], d[1]['r'])
|
|
||||||
print 'Envelopes: %1x %1x %1x %1x %1x %1x %1x %1x' % envs
|
|
||||||
except KeyError:
|
|
||||||
print 'incomplete instrument?'
|
|
||||||
|
|
||||||
# Conversions mapping to VST floating point values
|
|
||||||
W2F = {'SIN':0, 'HALFSIN':.33, 'ABSSIN':.66, 'QUARTSIN':1}
|
|
||||||
def m2f(mult):
|
|
||||||
if mult < 1: # half frq
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
return float(mult)/15.0
|
|
||||||
|
|
||||||
def a2f(att_db):
|
|
||||||
a = float(att_db)/0.75
|
|
||||||
return a/63.0
|
|
||||||
|
|
||||||
def b2f(bool_param):
|
|
||||||
if 'X' == bool_param:
|
|
||||||
return 1.0
|
|
||||||
else:
|
|
||||||
return 0.0
|
|
||||||
D2F = {0:0.0,1.5:0.33,3.0:0.66,6.0:1.0}
|
|
||||||
|
|
||||||
def e2f(env_val):
|
|
||||||
return float(env_val)/15.0
|
|
||||||
|
|
||||||
def output_instrument_vst_program(json_i, ts):
|
|
||||||
try:
|
|
||||||
d = json.loads(json_i)
|
|
||||||
m=d[0]; c=d[1]
|
|
||||||
lines = [
|
|
||||||
' const float i_params_%d[] = {' % ts,
|
|
||||||
' %.6ff, %.6ff, // waveforms' % (W2F[c['wav']], W2F[m['wav']]),
|
|
||||||
' %.6ff, %.6ff, // frq multipliers' % (m2f(c['fm_mult']), m2f(m['fm_mult'])),
|
|
||||||
' %.6ff, %.6ff, // attenuation' % (a2f(c['db']), a2f(m['db'])),
|
|
||||||
' %.1ff, %.1ff, %.1ff, %.1ff, // tre / vib / sus / ks' % tuple([b2f(c[x]) for x in ['tre', 'vib', 'sus', 'ksr']]),
|
|
||||||
' %.1ff, %.1ff, %.1ff, %.1ff, // tre / vib / sus / ks' % tuple([b2f(m[x]) for x in ['tre', 'vib', 'sus', 'ksr']]),
|
|
||||||
' %.6ff, %.6ff, // KSR/8ve' % (D2F[c['db_oct']], D2F[m['db_oct']]),
|
|
||||||
' %.6ff, // algorithm' % (1.0 if 'ADD'==d[2]['alg'] else 0.0),
|
|
||||||
' %.6ff, // feedback' % (float(d[2]['feedback'])/7.0),
|
|
||||||
' %.1ff, %.1ff, %.1ff, %.1ff, // adsr' % tuple([e2f(c[x]) for x in ['a', 'd', 's', 'r']]),
|
|
||||||
' %.1ff, %.1ff, %.1ff, %.1ff, // adsr' % tuple([e2f(m[x]) for x in ['a', 'd', 's', 'r']]),
|
|
||||||
' };',
|
|
||||||
' std::vector<float> v_i_params_%d (i_params_%d, i_params_%d + sizeof(i_params_%d) / sizeof(float));' % (ts,ts,ts,ts),
|
|
||||||
' programs["Instr %d"] = std::vector<float>(v_i_params_%d);' % (ts, ts),
|
|
||||||
]
|
|
||||||
print
|
|
||||||
print '\n'.join(lines)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
#print
|
|
||||||
#print '// incomplete instrument..'
|
|
||||||
|
|
||||||
def main(argv):
|
|
||||||
events = parse_opldump(sys.stdin)
|
|
||||||
ilist, instruments = find_unique_instruments(events)
|
|
||||||
for i in ilist:
|
|
||||||
output_instrument_vst_program(i, instruments[i])
|
|
||||||
#print i, instruments[i]
|
|
||||||
#print_instrument(i, instruments[i])
|
|
||||||
|
|
||||||
if '__main__' == __name__:
|
|
||||||
main(sys.argv)
|
|
|
@ -1,45 +0,0 @@
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
|
|
||||||
class SBI:
|
|
||||||
def __init__(self, sbi_data):
|
|
||||||
if sbi_data[0:3] != b'SBI':
|
|
||||||
raise ValueError('Invalid file header.')
|
|
||||||
if len(sbi_data) != 52:
|
|
||||||
raise ValueError('Invalid file size.')
|
|
||||||
self.register_values = sbi_data[36:]
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return isinstance(other, SBI) and self.register_values == other.register_values
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash(self.register_values)
|
|
||||||
|
|
||||||
|
|
||||||
# Requires Python 3.5+
|
|
||||||
def find_distinct_sbis(root_dir):
|
|
||||||
sbis = {}
|
|
||||||
bad = []
|
|
||||||
for filename in glob.iglob(os.path.join(root_dir, '**', '*.sbi'), recursive=True):
|
|
||||||
with open(filename, 'rb') as f:
|
|
||||||
try:
|
|
||||||
sbi = SBI(f.read())
|
|
||||||
try:
|
|
||||||
dup_filename = sbis[sbi]
|
|
||||||
print('Duplicate SBI file: %s (duplicate of %s)' % (filename, dup_filename))
|
|
||||||
bad.append(filename)
|
|
||||||
except KeyError:
|
|
||||||
sbis[sbi] = filename
|
|
||||||
except ValueError as e:
|
|
||||||
print('Invalid SBI file: %s (%s)' % (filename, e))
|
|
||||||
bad.append(filename)
|
|
||||||
return sbis, bad
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
distinct_sbis, to_delete = find_distinct_sbis('.')
|
|
||||||
print('Found %d distinct SBI files' % len(distinct_sbis))
|
|
||||||
print('Writing batch file..')
|
|
||||||
with open('delete_bad_sbis.cmd', 'w') as batch_file:
|
|
||||||
for delete in to_delete:
|
|
||||||
print('DEL %s' % delete, file=batch_file)
|
|