Author Topic: Stacking soundfonts and keeping banks not yet loaded  (Read 316 times)

Wayne McHugh

  • Posts: 39
I am enhancing my MIDI player to offer MIDI instrument banks>0, whereas in the past I've offered only bank 0. My situation is that I have a specialised guitars soundfont, with excellent bank 0 guitars. But I have a GM soundfont that also offers 12 string, mandolin and other variations on the guitar presets on banks > 0. I need to stack my soundfonts to get the specialised guitar preset bank 0, but would love to keep the non-bank 0 guitar presets from the GM font. I hope that makes logical sense. Does it make sense technically, and more importantly, can it be done? Thanks.

Wayne McHugh

  • Posts: 39
I'm actually having trouble getting banks > 0 to work at all.  I'm stacking 3 soundfonts, the last one being GM/GS hence includes all instruments on bank 0, and some on banks > 0.
I am using BASS_MIDI_StreamEvent to send my instrument to the stream - BASS_MIDI_StreamEvent(chan, ch, MIDI_EVENT_PROGRAM, dwParam);  // this has always worked
I am attempting to use BASS_MIDI_StreamEvent to send the requested bank - BASS_MIDI_StreamEvent(chan, ch, MIDI_EVENT_BANK, dwBank);  // I've tried this with dwBank being just the requested bank, also as MAKEWORD(0, nBank) because of your MSB note, but not at all convinced I'm doing the right thing here.  I can't find anything clearer, or any example trying to select different banks. I'm sure it's a little thing I'm not understanding.

Ian @ un4seen

  • Administrator
  • Posts: 24331
I am enhancing my MIDI player to offer MIDI instrument banks>0, whereas in the past I've offered only bank 0. My situation is that I have a specialised guitars soundfont, with excellent bank 0 guitars. But I have a GM soundfont that also offers 12 string, mandolin and other variations on the guitar presets on banks > 0. I need to stack my soundfonts to get the specialised guitar preset bank 0, but would love to keep the non-bank 0 guitar presets from the GM font. I hope that makes logical sense. Does it make sense technically, and more importantly, can it be done? Thanks.

Yes, that should be possible. If you want to use all of the presets as they are defined in the "specialised guitars" soundfont then you can simply stack them like this:

Code: [Select]
BASS_MIDI_FONT fonts[2];
fonts[0].font = guitarfont;
fonts[0].preset = -1; // all presets
fonts[0].bank = 0; // default banks
fonts[1].font = mainfont;
fonts[1].preset = -1; // all presets
fonts[1].bank = 0; // default banks
BASS_MIDI_StreamSetFonts(handle, fonts, 2); // apply it to the stream

If you only want to use a single preset from the "specialised guitars" soundfont then you can do that like this:

Code: [Select]
BASS_MIDI_FONT fonts[2];
fonts[0].font = guitarfont;
fonts[0].preset = 25; // preset 25
fonts[0].bank = 0; // default banks
fonts[1].font = mainfont;
fonts[1].preset = -1; // all presets
fonts[1].bank = 0; // default banks
BASS_MIDI_StreamSetFonts(handle, fonts, 2); // apply it to the stream

If you want to use multiple (but not all) presets from the "specialised guitars" soundfont then you can add another entry for each to the fonts array (before the "mainfont" entry).

If you want to do more complex remapping of presets (eg. change the soundfont's preset numbers) then that's also possible with the BASS_MIDI_FONTEX option. Please see the BASS_MIDI_StreamSetFonts documentation (includes example snippet).

I'm actually having trouble getting banks > 0 to work at all.  I'm stacking 3 soundfonts, the last one being GM/GS hence includes all instruments on bank 0, and some on banks > 0.
I am using BASS_MIDI_StreamEvent to send my instrument to the stream - BASS_MIDI_StreamEvent(chan, ch, MIDI_EVENT_PROGRAM, dwParam);  // this has always worked
I am attempting to use BASS_MIDI_StreamEvent to send the requested bank - BASS_MIDI_StreamEvent(chan, ch, MIDI_EVENT_BANK, dwBank);  // I've tried this with dwBank being just the requested bank, also as MAKEWORD(0, nBank) because of your MSB note, but not at all convinced I'm doing the right thing here.  I can't find anything clearer, or any example trying to select different banks. I'm sure it's a little thing I'm not understanding.

Make sure you send the MIDI_EVENT_BANK event before the MIDI_EVENT_PROGRAM event. If it's still having no effect, also make sure the stream isn't in GM1 mode (MIDI_SYSTEM_GM1), which disables bank changes. You can also use BASS_MIDI_StreamGetEvent to confirm the current MIDI_EVENT_BANK and MIDI_EVENT_PROGRAM values.

Wayne

  • Guest
Hi Ian, and thanks. I am sending the bank change first, by chance. But Iíll check out the other ideas.

On the first question, youíve not quite understood me. I am loading the specialised guitars first and they are all fine. Iím loading a gm/gs font last, and it omits the presets already loaded (by design). I want to omit bank=0 presets already loaded, because the specialised fonts do them better, but Iíd like to load bank > 0 presets because they are other variations or similar instruments. But in the stacking all banks get omitted when bank 0 is already loaded. I canít name them because they are many and the gm/gs font could be any gm/gs font.  I know Iím being clumsy in my exposition but does that make sense?

Ian @ un4seen

  • Administrator
  • Posts: 24331
Stacking soundfonts shouldn't prevent non-0 banks working, unless that's what the soundfont config in the BASS_MIDI_StreamSetFonts call specifies. The way it works is that when a preset is requested, BASSMIDI will search the soundfont config in the specified order until it finds the preset, hence the "guitarfont" comes before the "mainfont" in the examples above.

If you're sure it isn't working properly then please post your BASS_MIDI_StreamSetFonts call and upload the 2 soundfonts to have a look at (and state what preset/bank you're trying to use):

   ftp.un4seen.com/incoming/

Wayne McHugh

  • Posts: 39
I'm pleased to say that my selecting of non-bank 0 instruments is now working. It was an error at my end, so I'm sorry to have wasted your time on that one.

However I did more work on the stacking. If I load my gm/gs font on its own, I get nylon guitar and steel guitars on bank 0 and other variations on those presets, non-bank 0.  When I load my specialised guitar font first and the gm/gs font second, I lose those non-bank 0 instruments on the nylon and steel guitar presets. I've uploaded MyMIDI_un4seen.zip at the ftp link you gave me, containing the 2 soundfonts, mymidiplayercpp that loads the soundfonts (lines 2835-2991), and the drumdata.cpp (lines 26-119, but esp. drive by 45-49) which queries the loaded fonts and creates data structures for my reference.  These are not my working soundfonts, but I replicated the scenario with them.  Filezilla said the upload was successful but it doesn't show in your directory listing - I'm hoping that's your setup moving the file elsewhere.

Ian @ un4seen

  • Administrator
  • Posts: 24331
Your upload was indeed received (uploaded files are not publicly visible or downloadable). The mentioned mymidiplayercpp file seems to be missing, so I couldn't check your BASS_MIDI_StreamSetFonts calls, but I tried to reproduce the problem myself and it didn't seem to happen. What I did was stack the soundfonts as in the first code snippet I posted above, and then send a MIDI_EVENT_BANK=8 event and a MIDI_EVENT_PROGRAM=24/25/26/27 event, and in each case the corresponding preset from the main soundfont (instead of the guitar soundfont) was used to play subsequent notes. Does that match what you're trying, or is it something different?

Wayne McHugh

  • Posts: 39
Please ignore the latest upload.  I checked for the non-bank 0 guitars by hard overriding all BASS_MIDI_StreamEvent(...  MIDI_EVENT_BANK ...) and BASS_MIDI_StreamEvent(... MIDI_EVENT_PROGRAM ...) to a non-bank 0 guitar, with the stacking in place - and voila I got the non-bank 0 instrument. The mystery then was why the code I indicated in drumdata.cpp saw the non-bank 0 guitars when the guitar soundfont isn't stacked, but does not see it when the guitar soundfont is stacked.  Some detailed debugging through that process found code that assumed only one soundfont could provide a preset - it was error checking gone wrong and now all is working as it should be.  Thank you for your assistance again after all these years.  How long have you been providing and supporting the BASS libraries, Ian?  It seems a lifetime.

Wayne McHugh

  • Posts: 39
Ian, I've realised part of my confusion is caused by MIDI files I have from a different source.  I've been testing on a range of MIDI files throughout this latest work.  Now that I have it working I've realised that MIDI files I've produced are switching instruments to other banks perfectly.  But most MIDI files from another source do not.  The fonts are loading and the bank/preset are send to the stream - but no instrument change.  I've uploaded one such MIDI file in the hope that you might be able to shed some light on the reason it won't switch presets to a different bank.  My guess is it will work for you, which will leave me nowhere.  But I've run out of tests.

Ian @ un4seen

  • Administrator
  • Posts: 24331
Good to hear that you've got the stacked soundfonts working well now, mostly :)

Regarding the uploaded MIDI file, it doesn't appear to contain any bank changes, and furthermore it contains a "GM1 system on" sysex. GM1 mode doesn't permit bank changes, so if you want to manually change the banks then you will first need to disable GM1 mode, which you can do via the MIDI_EVENT_SYSTEM event. If wanted, you could use BASS_MIDI_StreamSetFilter to drop any MIDI_EVENT_SYSTEM events set to MIDI_SYSTEM_GM1.

Wayne

  • Guest
MIDI_SYSTEM_GM1
« Reply #10 on: 5 Jan '22 - 18:30 »
Brilliant, Ian, Iíd have never tracked that down. Thank you so much! Iíll build in a search-and-destroy for that midi instruction.

Wayne McHugh

  • Posts: 39
Re: Stacking soundfonts and keeping banks not yet loaded
« Reply #11 on: 5 Jan '22 - 21:06 »
Feeling really useless at this point!  I can't get the callback to fire at all.

// definition
BASS_MIDI_StreamSetFilter(chan, TRUE, MidiFilterProc, NULL); 

// implementation
BOOL CALLBACK MidiFilterProc(HSTREAM handle, DWORD track, BASS_MIDI_EVENT *event, BOOL seeking, void *user)
{
   sprintf(message, "Event", event->event);
   Trace(message);
   ...
   return TRUE; // process the event
}

Trace is a macro that throws up a messagebox.
It links and runs, but I can open the MIDI file I sent you and play it, and no messagebox.
Beyond that I don't know how to recognise the event I'm after, but I'm assuming at present the event->event will be MIDI_EVENT_SYSTEM and hibyte or lobyte will be MIDI_SYSTEM_GM1.
Is there anything in my setup above that is wrong, causing it not to fire?
BASSMIDI .h .lib and .dll are dated 16/09/2020.

Ian @ un4seen

  • Administrator
  • Posts: 24331
Re: Stacking soundfonts and keeping banks not yet loaded
« Reply #12 on: 6 Jan '22 - 14:22 »
That's strange. Is the BASS_MIDI_StreamSetFilter call reporting success, ie. returning TRUE? If so, just to be sure there isn't a problem with the logging code, perhaps you could place a breakpoint in the MidiFilterProc function and try running it under the debugger?

Regarding recognising and dropping GM1 mode events, you can do that in there like this:

Code: [Select]
if (event->event == MIDI_EVENT_SYSTEM && event->param == MIDI_SYSTEM_GM1) return FALSE;

Wayne McHugh

  • Posts: 39
Re: Stacking soundfonts and keeping banks not yet loaded
« Reply #13 on: 6 Jan '22 - 21:22 »
With further investigation the callback is working and I've implemented exactly the code you supplied.  The code catches the GM1 instruction once per song. However sadly the non-bank 0 instrument changes still are not working.  I've rechecked MIDI files I've made and non-bank 0 instrument changes still work in them.  So while the GM1 instruction is being eliminated, it hasn't resolved the problem.  I've rechecked on multiple MIDI files to ensure it isn't just this one, and it is not just this one.

Wayne McHugh

  • Posts: 39
Re: Stacking soundfonts and keeping banks not yet loaded
« Reply #14 on: 7 Jan '22 - 06:48 »
Ian, I've discovered a solution.  Instead of removing the event I'm changing event->param from MIDI_SYSTEM_GM1 to MIDI_SYSTEM_GS (or MIDI_SYSTEM_GM2) and allowing the event to be processed.  The non-bank 0 instrument changes then work.  Thanks heaps for all your help.

Ian @ un4seen

  • Administrator
  • Posts: 24331
Re: Stacking soundfonts and keeping banks not yet loaded
« Reply #15 on: 7 Jan '22 - 15:34 »
Ah, I forgot to point out that you will also need to override the MIDI_EVENT_SYSTEM setting, as it will initially be set to the file's default, ie. MIDI_SYSTEM_GM1 in this case. The MIDIFILTERPROC will then prevent the MIDI file resetting it. You could indeed override the setting in the MIDIFILTERPROC, but if you want to be able to set custom banks before starting playback, then you should do it first thing via BASS_MIDI_StreamEvent instead. For example, like this:

Code: [Select]
midi = BASS_MIDI_StreamCreateFile(...);
system = BASS_MIDI_StreamGetEvent(midi, 0, MIDI_EVENT_SYSTEM);
if (system == MIDI_SYSTEM_GM1)
BASS_MIDI_StreamEvent(midi, 0, MIDI_EVENT_SYSTEM, MIDI_SYSTEM_DEFAULT);

Wayne McHugh

  • Posts: 39
Re: Stacking soundfonts and keeping banks not yet loaded
« Reply #16 on: 7 Jan '22 - 23:19 »
Thanks Ian, it is now adjusted according to your recommendations, and still working. I had tried to set the default to MIDI_SYSTEM_DEFAULT, according to your earlier recommendation, but in the wrong place and the wrong way. After all these years I'm still such a novice.