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 but here standardised to lower-case), 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, manufacturer, 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_data and tune, which have scalar values.

See: doc/gravis.txt doc/headers.c doc/timidity/instrum.c doc/timidity/instrum.h doc/timidity/playmidi.c and doc/wav2pat.c for details of what the values mean...

See: test.pl 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 hundreths of Hz?). I would have expected a MIDI pitch there, like low=48 high=72, corresponding to the SoundFont key range parameter, allowing different wavsamples to be used for different tessituras. The number 12288.0 in TiMidity's doc/timidity/playmidi.c may hold a clue. See: perl examples/sf_list gravis/fiddle.pat | less

FUNCTIONS

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.

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.

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

Two 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.

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
man timidity         - (1) MIDI-to-WAVE converter and player
man timidity.cfg     - (5) configure file of TiMidity++