Why not adopt me?
NAME
MIDI::SoundFont - Handles .sf2 SoundFont and .pat and .zip Gravis files
SYNOPSIS
use MIDI::SoundFont();
use Data::Dumper(Dumper);
$Data::Dumper::Indent = 1; $Data::Dumper::Sortkeys = 1;
my %sf = MIDI::SoundFont::file2sf('doc/Jeux14.sf2');
open (P, '|-', 'less'); print P Dumper(\%sf); close P;
MIDI::SoundFont::sf2file('/tmp/Jeux15.sf2', %sf);
my %gus = MIDI::SoundFont::file2gravis('gravis/Gravis.zip');
open (P, '|-', 'less'); print P Dumper(\%gus); close P;
MIDI::SoundFont::gravis2file('/tmp/Gravis2.zip', %gus);
print MIDI::SoundFont::timidity_cfg('/home/me/Gr.zip',%gus);
print MIDI::SoundFont::timidity_cfg('/home/me/Sf.sf2',%sf);
DESCRIPTION
This module offers a Perl interface to ease the manipulation of SoundFont and Gravis files.
This module loads these files into a Perl associative array whose structure is documented in the section IN-MEMORY SOUNDFONT FORMAT or IN-MEMORY GRAVIS FORMAT below.
Nothing is exported by default, but all the documented functions can be exported, e.g.: use MIDI::SoundFont(file2sf, sf2file);
No functions are provided to manipulate the .pat members in a Gravis .zip archive; to do this work you should use Archive::Zip directly.
Future versions should offer translation between Gravis and SoundFont formats, and should also allow importing a .wav snippet into a patch by automatically detecting the optimal StartLoop and EndLoop points. These features are currently unimplemented.
IN-MEMORY SOUNDFONT FORMAT
See:
perl examples/sf_list doc/Jeux14.sf2 | less
perl examples/sf_list -b 0 -p 17 -l doc/Jeux14.sf2 | less
file2sf($filename) returns a hash with keys: ifil, isng, INAM, irom, iver, ICRD, IENG, IPRD, ICOP, ICMT and ISFT which have scalar values (see http://www.pjb.com.au/midi/sfspec21.html#i5 ), and the keys: phdr whose value is an arrayref, and inst and shdr whose values are hashrefs.
Each item of the phdr array is a Preset ("Preset" is a SoundFont term which means substantially the same as the MIDI "Patch"), which is a hashref with the following keys: achPresetName is the Patch-name, wBank is the MIDI Bank-number, wPreset is the MIDI Patch-number ( see http://www.pjb.com.au/midi/sfspec21.html#7.2 ), plus pbags which is an arrayref. Each pbag is a hashref with the following keys: modulators which is an arrayref ( see http://www.pjb.com.au/midi/sfspec21.html#7.4 ) and generators which is a hashref ( see http://www.pjb.com.au/midi/sfspec21.html#7.5 ). The generators is where most of the action is ( see http://www.pjb.com.au/midi/sfspec21.html#8.1.3 ), and particularly crucial is instrument which tells the Patch (i.e. Preset) which Instrument it will be using.
Each key of the inst hash is an Instrument-name, ( see http://www.pjb.com.au/midi/sfspec21.html#7.6 ), and each value is an Instrument ( see http://www.pjb.com.au/midi/sfspec21.html#8.5 ), which is a hashref with just one key: ibags whose value is an arrayref. Each ibag is a hashref with the following keys: modulators which is an arrayref ( see http://www.pjb.com.au/midi/sfspec21.html#7.8 ) and generators which is a hashref ( see http://www.pjb.com.au/midi/sfspec21.html#7.9 ). The generators is where most of the action is ( see http://www.pjb.com.au/midi/sfspec21.html#8.1.3 ), and particularly crucial is sampleID which (at last!) tells the Instrument and hence the Preset which Sample it will be using :-)
Each item of the shdr array is a Sample which is a hashref with the following keys, which all have scalar values: achSampleName, dwStart, dwEnd, dwStartloop, dwEndloop, dwSampleRate, byOriginalKey, chCorrection, wSampleLink and sfSampleType ( see http://www.pjb.com.au/midi/sfspec21.html#7.10 ), plus sampledata, which (at last!!) contains the (16-bit signed little-endian) audio data.
The Patch-names ( achPresetName ) must be unique, the Instrument-names ( achInstName ) must be unique, and the Sample-names ( achSampleName ) must be unique.
IN-MEMORY GRAVIS FORMAT
See: perl examples/sf_list gravis/fiddle.pat | less
file2gravis($filename) returns a hash with keys: description, filename, num_channels, and num_voices, which have scalar values, and instruments whose value is an arrayref (although in practice I've never met a patch-file with more than one instrument). The instrument is a hash with keys: instr_name and instr_num, which have scalar values, and layers whose value is an arrayref. Each layer has keys: id and previous, which have scalar values (apparently unused), and wavsamples whose value is an arrayref. Each wavsample is a hash with keys: balance, data, envelope_data, high_freq, loop_end, loop_start, low_freq, mode, root_freq, sample_name, sample_rate, scale_factor, scale_freq, tremolo_depth, tremolo_phase, tremolo_sweep, vibrato_depth, vibrato_ctl, vibrato_sweep and tune, which have scalar values.
Unlike the SoundFont format, the frequencies low_freq, high_freq and root_freq are in thousandths of a Hz, and the loop_start and loop_end are in bytes, not samples.
The mode bits describes the format of the data, and the following package variables can be imported with use MIDI::SoundFont(':CONSTS'); MODES_16BIT=1 MODES_UNSIGNED=2 MODES_LOOPING=4 MODES_PINGPONG=8 MODES_REVERSE=16 MODES_SUSTAIN=32 MODES_ENVELOPE=64 MODES_CLAMPED=128
See: doc/gravis.txt doc/headers.c doc/timidity/instrum.c doc/timidity/instrum.h doc/timidity/playmidi.c doc/wav2pat.c and ftp://ftp.gravis.com/Public/Sdk/ for more details of what the values mean. The tremolo and vibrato data displayed by timidity -idvv -x 'bank 0\n0 ./gravis/fiddle.pat' are different from the values of the tremolo and vibrato variables above, because the timidity variables have been multiplied by corresponding control ratios: see doc/timidity/instrum.c
See: test.pl, examples/make_bank5 and examples/sf_list for examples manipulating this data-structure.
SOUNDFONT FILE-FORMAT
Fortunately, there exists authoritative and clear documentation of the SoundFont file format: http://connect.creativelabs.com/developer/SoundFont/sfspec21.pdf Unfortunately, it's a fairly hard format to work with...
A SoundFont-2 compatible RIFF file comprises three chunks: an INFO-list chunk containing a number of required and optional sub-chunks describing the file, its history, and its intended use, see http://www.pjb.com.au/midi/sfspec21.html#i5
an SDTA-list chunk comprising a single sub-chunk containing any referenced digital audio samples, see http://www.pjb.com.au/midi/sfspec21.html#i6
and a PDTA-list chunk containing nine sub-chunks which define the articulation of the digital audio data, see http://www.pjb.com.au/midi/sfspec21.html#i7
GRAVIS FILE-FORMAT
The files doc/gravis.txt, doc/headers.c and doc/wav2pat.c disagree somewhat about the file format. Most authoritative is the TiMidity source in doc/timidity/, but it's also somewhat hard to interpret. The format adopted here seems to work with all patches in gravis/Gravis.zip
Several of the parameters seem obscure: for example, num_channels is often zero, when it should be either 1 or 2, and instr_num is either zero or, in non-Gravis patches, usually random. In the wavsample section, low_freq and high_freq seem large (perhaps in thousandths of Hz? See: ftp://ftp.gravis.com/Public/Sdk/PATCHKIT.ZIP). These are the parameters that must correspond to the SoundFont key range, allowing different wavsamples to be used for different tessituras. See: perl examples/sf_list gravis/fiddle.pat | less
FUNCTIONS
- %sf = file2sf($filename)
-
Reads the file, which should be a SoundFont file, and converts it to the data-structure documented above in the IN-MEMORY SOUNDFONT FORMAT section.
The filename can also be a URL, or - meaning STDIN
- sf2file($filename, %soundfont)
-
Converts a data-structure as documented above in the IN-MEMORY SOUNDFONT FORMAT section into a file as documented in the SOUNDFONT FILE-FORMAT section.
- %sf = new_sf($inam)
-
Returns a minimal empty soundfont data-structure as documented above in the IN-MEMORY SOUNDFONT FORMAT section. The optional argument $inam sets the 'INAM' value. You can then change $sf{'INAM'} and $sf{'phdr'}[0]{'wPreset'} or push onto @{$sf{'phdr'}} and so on. See examples/make_bank5 in the examples/ directory.
- %gr = file2gravis($filename)
-
Reads the file, which should be either a Gravis .pat patch-file, or a .zip archive of patch-files, and converts it to the data-structure documented above in the IN-MEMORY GRAVIS FORMAT section.
The filename can also be a URL, or - meaning STDIN
- gravis2file($filename, %gravis)
-
Converts a data-structure as documented above in the IN-MEMORY GRAVIS FORMAT section either into a .pat patch-file as documented in the GRAVIS FILE-FORMAT section, or into a .zip archive of patch-files.
- %sf = new_pat()
-
Returns a minimal empty patch data-structure; the reference to this is a value in the gravis data-structure documented above in the IN-MEMORY GRAVIS FORMAT section, the key being the filename it will get when given a home in a .zip file. See examples/make_bank5 in the examples/ directory.
- timidity_cfg($filename, %sf_or_gravis)
-
This returns a suggested timidity.cfg paragraph to allow you to use your soundfont, or gravis patch or zip, in timidity. The filename is the .sf2 or .pat or .zip file in which it resides, or will reside.
You should insert the resulting string into your timidity.cfg by hand, using your favourite text editor, because there are bound to be things you'll want to change.
For Gravis .zip archives, the String::Approx module is used to guess some General-Midi-conformant patch-numbers.
EXAMPLES
Five simple examples in the examples/ subdirectory are already useful applications:
- sf_list
-
sf_list displays, in a readable format, a list of the Patches available in a .sf2 SoundFont file, or in a Gravis .zip archive, or the contents of a Gravis .pat patch-file. It displays the Patches in a readable format, e.g.: bank 8 patch 17 # Detuned Organ 2
It also has options -l for long, detailed output, and -b and -p to restrict the choice to particular Banks and Patches, and a -c option to suggest a paragraph for your timidity.cfg
- sf_edit
-
sf_edit is a Term::Clui application which allows certain simple operations such as moving Banks, deleting Patches.
- make_bank5
-
make_bank5 puts together a SoundFont file from scratch, using some simple waveforms, and then puts together some substantially identical Gravis patches. These files can be used successfully both by timidity and by csound, which is a reasonable test of MIDI::SoundFont's conformance to the file-formats. See: http://www.pjb.com.au/midi/free/Bank5.sf2 http://www.pjb.com.au/midi/free/SawtoothToTriangle.pat and http://www.pjb.com.au/midi/free/SquareToSine.pat
- csound_scoresynth.csd
-
csound_scoresynth.csd evolves from the script explained on page 148 of the book Csound Power by Jim Aikin. It shows how to load a SoundFont into csound and play its notes directly from the Score section of the .csd file.
It assumes you have run make_bank5, so that the SoundFont /tmp/Bank5.sf2 already exists.
- csound_midisynth.csd
-
csound_midisynth.csd evolves from the script fluidcomplex.csd by Istvan Varga, as included in the csound documentation. It shows how to load a SoundFont into csound and play its notes using a midi keyboard, which you will have to connect by hand using some command such as aconnect ProKeys 14:0
It assumes you have run make_bank5, so that the SoundFont /tmp/Bank5.sf2 already exists.
DOWNLOAD
This module is available from CPAN at http://search.cpan.org/perldoc?MIDI::SoundFont
AUTHOR
Peter J Billam, http://www.pjb.com.au/comp/contact.html
SEE ALSO
http://search.cpan.org/perldoc?MIDI::SoundFont
http://search.cpan.org/perldoc?File::Format::RIFF
http://search.cpan.org/perldoc?File::Format::RIFF::Container
http://search.cpan.org/perldoc?Archive::Zip
http://search.cpan.org/perldoc?File::Temp
http://search.cpan.org/perldoc?String::Approx
http://connect.creativelabs.com/developer/SoundFont/sfspec21.pdf
http://www.pjb.com.au/midi/sfspec21.html
http://www.onicos.com/staff/iz/timidity/dist/tools-1.1.0/wav2pat.c
http://timidity.sourceforge.net
ftp://ftp.gravis.com/Public/Sdk/
http://www.csounds.com/manual/html/fluidEngine.html
http://www.csounds.com/manual/html/fluidNote.html
http://www.csounds.com/manual/html/fluidLoad.html
"Csound Power" by Jim Aikin, Course Technology, Cengage Learning, 2013,
ISBN-13 978-1-4354-6004-1
ISBN-10 1-4354-6004-9
man timidity - (1) MIDI-to-WAVE converter and player
man timidity.cfg - (5) configure file of TiMidity++