2
0
Fork 0

Add support for writing .sbi instruments to dro2midi.

This commit is contained in:
bruce 2013-11-14 21:47:47 +08:00
parent ebf75b5dd6
commit 265be73088
2 changed files with 221 additions and 2 deletions

177
dro2midi/README Normal file
View 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

View file

@ -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) {