Add support for writing .sbi instruments to dro2midi.
This commit is contained in:
parent
ebf75b5dd6
commit
265be73088
2 changed files with 221 additions and 2 deletions
177
dro2midi/README
Normal file
177
dro2midi/README
Normal file
|
@ -0,0 +1,177 @@
|
|||
---------------------------------------------------------------
|
||||
DRO2MIDI - version 1.4 (2009-03-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.
|
||||
|
||||
// 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
|
|
@ -70,8 +70,12 @@
|
|||
// - Added detectors for the (at this time) two DRO formats, and a hint
|
||||
// to let us know that the DRO v2.0 format is not supported.
|
||||
//
|
||||
// v1.6 / 2013-11-14 / bsa (http://bsutherland.github.io/JuceOPLVSTi)
|
||||
// - Added -s switch to save detected instruments in Creative Sound
|
||||
// Blaster Instrument format (.sbi)
|
||||
//
|
||||
|
||||
#define VERSION "1.5"
|
||||
#define VERSION "1.6"
|
||||
#define MAPPING_FILE "inst.txt"
|
||||
|
||||
#define PATCH_NAME_FILE "patch.txt"
|
||||
|
@ -113,6 +117,7 @@ bool bUsePitchBends = true; // use pitch bends to better match MIDI note frequen
|
|||
bool bApproximatePitchbends = false; // if pitchbends are disabled, should we approximate them by playing the nearest note when the pitch changes?
|
||||
bool bPerfectMatchesOnly = false; // if true, only match perfect instruments
|
||||
bool bEnableVolume = true; // enable note velocity based on OPL instrument volume
|
||||
bool bWriteSbiInstruments = false; // write detected instruments to .SBI files
|
||||
|
||||
// Rhythm instruments
|
||||
enum RHYTHM_INSTRUMENT {
|
||||
|
@ -240,7 +245,7 @@ void version()
|
|||
printf("DRO2MIDI v" VERSION " - Convert raw Adlib captures to General MIDI\n"
|
||||
"Written by malvineous@shikadi.net in 2007\n"
|
||||
"Heavily based upon IMF2MIDI written by Guenter Nagler in 1996\n"
|
||||
"With contributions by Wraithverge (C) 2010.\n"
|
||||
"With contributions by Wraithverge (C) 2010, bsa in 2013\n"
|
||||
"http://www.shikadi.net/utils/\n"
|
||||
"\n"
|
||||
);
|
||||
|
@ -267,6 +272,8 @@ void usage()
|
|||
" of artificial pitchbends in the output MIDI.\n"
|
||||
" -v Disable note velocity and play all notes as loudly as possible,\n"
|
||||
" instead of trying to match the volume of the OPL note.\n"
|
||||
" -s Write detected instruments to .sbi files\n"
|
||||
" (Creative Sound Blaster Instrument).\n"
|
||||
"\n"
|
||||
"Supported input formats:\n"
|
||||
" .raw Rdos RAW OPL capture\n"
|
||||
|
@ -599,6 +606,36 @@ long compareinstr(INSTRUMENT& a, INSTRUMENT& b, RHYTHM_INSTRUMENT ri)
|
|||
}
|
||||
}
|
||||
|
||||
void writesbi(const char* filename, int instrno, int chanOPL) {
|
||||
char fname[100];
|
||||
char title[32];
|
||||
snprintf(fname, 100, "%s_%03d.sbi", filename, instrno);
|
||||
FILE* f_sbi = fopen(fname, WRITE_BINARY);
|
||||
if (!f_sbi) {
|
||||
fprintf(stderr, "Could not open instrument file %s for writing.\n", filename);
|
||||
} else {
|
||||
fwrite("SBI\x1a", sizeof(char), 4, f_sbi);
|
||||
memset(title, 0, 32);
|
||||
snprintf(title, 32, "dro2midi_%03d", instrno);
|
||||
fwrite(title, sizeof(char), 32, f_sbi);
|
||||
unsigned char instr[16];
|
||||
memset(instr, 0, 16);
|
||||
instr[0] = (unsigned char)reg[chanOPL].reg20[0];
|
||||
instr[1] = (unsigned char)reg[chanOPL].reg20[1];
|
||||
instr[2] = (unsigned char)reg[chanOPL].reg40[0];
|
||||
instr[3] = (unsigned char)reg[chanOPL].reg40[1];
|
||||
instr[4] = (unsigned char)reg[chanOPL].reg60[0];
|
||||
instr[5] = (unsigned char)reg[chanOPL].reg60[1];
|
||||
instr[6] = (unsigned char)reg[chanOPL].reg80[0];
|
||||
instr[7] = (unsigned char)reg[chanOPL].reg80[1];
|
||||
instr[8] = (unsigned char)reg[chanOPL].regE0[0];
|
||||
instr[9] = (unsigned char)reg[chanOPL].regE0[1];
|
||||
instr[10] = (unsigned char)reg[chanOPL].regC0;
|
||||
fwrite(instr, sizeof(char), 16, f_sbi);
|
||||
fclose(f_sbi);
|
||||
}
|
||||
}
|
||||
|
||||
int findinstr(int chanMIDI)
|
||||
{
|
||||
assert((chanMIDI < 9) || ((chanMIDI >= CHAN_BASSDRUM) && (chanMIDI <= CHAN_HIHAT)));
|
||||
|
@ -657,6 +694,9 @@ int findinstr(int chanMIDI)
|
|||
reg[chanOPL].regC0,
|
||||
reg[chanOPL].regE0[0], reg[chanOPL].regE0[1]
|
||||
);
|
||||
if (::bWriteSbiInstruments) {
|
||||
writesbi(output, instrcnt, chanOPL);
|
||||
}
|
||||
break;
|
||||
case TomTom:
|
||||
case HiHat:
|
||||
|
@ -930,6 +970,8 @@ int main(int argc, char**argv)
|
|||
} else if (strncasecmp(*argv, "-v", 2) == 0) {
|
||||
::bEnableVolume = false;
|
||||
printf("Note velocity disabled, all notes will be played as loud as possible.\n");
|
||||
} else if (strncasecmp(*argv, "-s", 2) == 0) {
|
||||
::bWriteSbiInstruments = true;
|
||||
} else if (strncasecmp(*argv, "-c", 2) == 0) {
|
||||
argc--; argv++;
|
||||
if (argc == 0) {
|
||||
|
|
Loading…
Reference in a new issue