Closed chipweinberger closed 9 months ago
this way my example code is simple:
import 'package:dart_melty_soundfont/dart_melty_soundfont.dart';
import 'package:flutter/services.dart' show rootBundle;
// Create the synthesizer.
ByteData bytes = await rootBundle.load('assets/akai_steinway.sf2');
Synthesizer synth = Synthesizer.loadByteData(bytes,
SynthesizerSettings(
sampleRate: 44100,
blockSize: 64,
maximumPolyphony: 64,
enableReverbAndChorus: true,
));
// select the first instrument preset
synth.selectPreset(channel: 0, preset: 0);
// Turn on some notes
synth.noteOn(channel: 0, key: 72, velocity: 120);
synth.noteOn(channel: 0, key: 76, velocity: 120);
synth.noteOn(channel: 0, key: 79, velocity: 120);
synth.noteOn(channel: 0, key: 82, velocity: 120);
// Render the waveform (3 seconds)
ArrayInt16 buf16 = ArrayInt16.zeros(numShorts: 44100 * 3);
synth.renderMonoInt16(buf16);
I was considering adding several useful methods to Synthesizer
. For instance, a method like the one below that simplifies program changes:
public static void ChangeProgram(this Synthesizer synthesizer, int channel, int value)
{
synthesizer.ProcessMidiMessage(channel, 0xC0, value, 0);
}
However, I pondered 🤔
Would it be better for value
to be int
, or should it represent the GM sound set as an enum, or should it have overloads for both? Moreover, if there's ChangeProgram
, it seems logical to also have methods like ChangeBank
, SetExpression
, SetPitchBend
, and so on. Should the argument for SetExpression
range from 1-127 or would 0.0-1.0 be more intuitive? After much deliberation on such matters, I concluded that users should create such utility methods according to their preferences. Hence, I decided not to provide them.
By the way, in dart_melty_soundfont's simple chord sample, does the mention of the preset serve to avoid silence when the SoundFont doesn't have a preset assigned to #0? If so, you might want to implement a fallback mechanism to a default preset when a preset is not found. #17 and related commits https://github.com/sinshu/meltysynth/pull/19/commits/d1f8ebe8a86b877831de47e7e3052fc7e5b11edf, https://github.com/sinshu/meltysynth/commit/f5078d1e6a7410299a07fd8eec19e21a20449cf6 might be helpful references.
I concluded that users should create such utility methods according to their preferences.
That's a reasonable conclusion.
for changeProgram
I would use an integer, and also provide an enum that can be converted to integer.
for setPitchBend, etc would use the integer values as well.
By the way, in dart_melty_soundfont's simple chord sample, does the mention of the preset serve to avoid silence when the SoundFont doesn't have a preset assigned to #0? If so, you might want to implement a fallback mechanism to a default preset when a preset is not found. https://github.com/sinshu/meltysynth/issues/17 and related commits https://github.com/sinshu/meltysynth/commit/d1f8ebe8a86b877831de47e7e3052fc7e5b11edf, https://github.com/sinshu/meltysynth/commit/f5078d1e6a7410299a07fd8eec19e21a20449cf6 might be helpful references.
Yes, that is the reason. Also, so users know how to switch instruments.
The first preset in the preset array might not be suitable for default. For example, the first preset of TimGM6mb.sf2 is the flute. I believe that the default preset should be the piano if the sf2 is GM compatible.
If the preset with non-zero bank number can be fallback to the GM sound set (bank #0), it should do so.
I suppose I am okay with the first preset being a flute. In my example code, I now print all the presets and their names so users know what is available. That said, I'm not sure if the sf2 preset.name + instrument.name is useful.
https://github.com/sinshu/meltysynth/commit/d1f8ebe8a86b877831de47e7e3052fc7e5b11edf is an interesting change. So if a complicated midi file with many instruments uses an instrument that is not available in the soundfont, you will get the default preset instead of silence?
I pushed https://github.com/chipweinberger/dart_melty_soundfont/commit/90befd4bd3531bbc49b718f022eb7d823574d85a to match your 2 commits
https://github.com/sinshu/meltysynth/commit/d1f8ebe8a86b877831de47e7e3052fc7e5b11edf is an interesting change. So if a complicated midi file with many instruments uses an instrument that is not available in the soundfont, you will get the default preset instead of silence?
Yes, every instrument might turn into a piano or something 😅
To the best of my knowledge, the behavior when a preset is not found is not explicitly stated in either the SoundFont or MIDI specification, so I think it’s ultimately up to the author to decide based on their preferences. Personally, considering the user experience, I thought it was a good decision to make sure that sound is produced as soon as NoteOn
is executed 🤔
yes that makes sense. thanks for your help :)
In my README, I have these rather wordy docs.
So simplify things, perhaps we could add a
synth. selectPreset(int channel, int preset)
function?Curious your thoughts @sinshu