Encode sound effects in a midi soundbank?

I’ve been reading that midi has pretty high polyphony - 32-128, but I think the number of wavs you can play simultaneously is low in comparison.

I was wondering if anyone has ever thought of making a midi soundbank from the individual game sounds and using java midi so they could get a better polyphony? I think since jdk 7 having access to some open source soundbank formats, creating those might be easier?

I might have skipped a page in the “What is midi?” section… I remember my old casio having different sounds attached to different keys for drums though I think some people put instruments on different channels just to make swapping instruments out easier.

I did that once and it worked pretty well.
I used the Gervill midi synthesizer source for manipulating the soundfonts but I would probably do it manually with Viena (yes with one ‘n’) if I ever do it again.

One thing to think of though: If you plan to use midi music together with sfxs the number of channels you can use for representing different sound sources shrink. It is max 16 channels if I don’t remember it wrong.

I got a sample soundfont from:
http://www.hammersound.com/cgi-bin/soundlink.pl?action=view_category&category=Sound+Effects&ListStart=0&ListLength=15

And tested the concept with some random code:



import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Synthesizer;
import javax.swing.JButton;
import javax.swing.JFrame;

public class LoadSoundbank extends JFrame {
	private static final boolean DEBUG = true;

	public static JButton playButton = new JButton("play");


	public static void main(String[] args) throws MidiUnavailableException, InvalidMidiDataException, IOException {

		Synthesizer	synth = null;
		synth = MidiSystem.getSynthesizer();
		if (DEBUG) out("Synthesizer: " + synth);

		Soundbank soundbank = null;
		File file = new File("SFX_StarWars_weapons.SF2");
		System.out.println(file.exists());
		soundbank = MidiSystem.getSoundbank(file);
		if (DEBUG) out("Soundbank: " + soundbank);

		synth.open();
		if (DEBUG) out("Defaut soundbank: " + synth.getDefaultSoundbank());

		if (soundbank != null)
		{
			out("soundbank supported: " + synth.isSoundbankSupported(soundbank));
			boolean bInstrumentsLoaded = synth.loadAllInstruments(soundbank);
			if (DEBUG) out("Instruments loaded: " + bInstrumentsLoaded);
		}

		playButton.addActionListener(new PlayListener(synth));

		new LoadSoundbank();

	}


	private static void printUsageAndExit()
	{
		out("LoadSoundbank: usage:");
		out("java LoadSoundbank [<soundbankfilename>]");
		System.exit(1);
	}


	private static void out(String strMessage)
	{
		System.out.println(strMessage);
	}

	public LoadSoundbank (){

		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new BorderLayout());
		add(playButton, BorderLayout.CENTER);
		pack();
		show();
	}

	private static class PlayListener implements ActionListener {

		int	nNoteNumber = (int)(80*Math.random());	// MIDI key number
		int	nVelocity = 100;	// MIDI note on velocity

		int	nDuration = 50;
		
		int channelNumber = 10;

		Synthesizer synth;

		public PlayListener(Synthesizer synth){
			this.synth = synth;
			channelNumber = 0;
		}

		@Override
		public void actionPerformed(ActionEvent arg0) {

			for (int i = 0;i < 50; i++){

				MidiChannel[]	channels = synth.getChannels();

				nNoteNumber = (int)(80*Math.random());

				//			nNoteNumber = 45;
				
				MidiChannel channel = channels[9];
				
//				channels[9].noteOn(nNoteNumber, nVelocity);
				
				 int PAN_CONTROLLER = 10;
				 
				// Pan to Center:
//				channel.controlChange(PAN_CONTROLLER, 64);

				
				if (i<25){
					// Pan hard left:
				channel.controlChange(PAN_CONTROLLER, 0);
				}
				else {
				// Pan hard right:
				channel.controlChange(PAN_CONTROLLER, 127);
				}

				// "Active stereo", Jimi-Hendrix-style
				// sweep from almost-full left to almost-full right:
//				for (int position = 8; position < 127; position += 8) {
//				    channel.controlChange(PAN_CONTROLLER, position);
//				    try {
//				        Thread.sleep(5);
//				    } catch (InterruptedException e) {
//				    }
//				}
				
				
				channels[channelNumber].setMono(false);
				channels[channelNumber].noteOn(nNoteNumber, nVelocity);


				/*
				 *	Wait for the specified amount of time
				 *	(the duration of the note).
				 */
				try
				{
					Thread.sleep(nDuration);
				}
				catch (InterruptedException e)
				{
				}

				//			channels[channelNumber].noteOff(nNoteNumber);
			}


			/*
			 *	Turn the note off.
			 */

		}
	}
}


Problem now is how to get MY soundeffects into a sf2 file… :confused:

OH! thanks for the tip!

If you want to automate the soundfont construction, I have some code for you :slight_smile:

It is taken out of its context but you can probably see how to use the Gervill soundfont-related classes for creating/manipulating sfx-soundfonts.

Thanks, I’ve bookmarked that to investigate later. I got Viena to encode some old sound effects, and I was interested that it did some pitch shifting to attach them to a range of keys… Might be good for adding variety to sound effects, maybe?

Remember, if you don’t need pitching, that you can have drumkit soundfonts with 128 different sounds on one channel. Unlike some synthesizers, Gervill is also meant to support drumkits on every MIDI channel. As certain things (FX, panning, etc.) will be channel based, you could potentially load the same drumkit instrument on each channel, and rotate through them for each sound effect.

Some more ideas of things you can do with midi/gervill with sfxs:

  • doppler shift with pitch bend
  • positioning with balance
  • attenuation with volume
  • environment effects with chorus, reverb and lp filter freq/bandwidth

If you have a channel for each sound source and manage/prioritize these depending on context, it should be a pretty straightforward coding adventure :slight_smile:

Gervill has also an implementation of key-based tuning, which you can use (see the demos). It also has a bunch of different chorus and reverb filters that you can change with some fancy midi messages.

Btw, I extracted some of the effects from Gervill as part of the JAudioLib’s AudioOps library, should you wish to use them on plain audio data. There’s no release yet, but the source is at http://code.google.com/p/jaudiolibs/source/browse/?repo=audioops

Just linking to this thread from elsewhere and noticed the link I posted is old.

All this code is now on GitHub (so fork away! :wink: ) - https://github.com/jaudiolibs/