moinejf / abc2svg

project moved to https://chiselapp.com/user/moinejf/repository/abc2svg
GNU Lesser General Public License v3.0
48 stars 6 forks source link

play-1.js: add support for default instrument #21

Open joaocc opened 7 years ago

joaocc commented 7 years ago

Hi, We are trying to use the play-1.js script on an desktop app that can be used offline. One of the difficulties we are facing has to do with the dynamic download of audio files for MIDI playback. For offline support, it means that we would have to increase the download size.

An alternative for this would be to define the concept of a user-defined default instrument. Currently we are focused on violin, which means that most of the files (since they don't explicitly specify an instrument) end up playing as "acoustic_grand_piano". Allowing setting the default instrument via something like "set_default_instr" could address this.

Another possible improvement would be to detect failure to load an instrument and, in that case, try to load the default instrument. From our analysis of the code, it seems that this could be easier with the 'mp3' mode, as it already has support for "onerror". This would also mean that we would have to pack fewer instruments while still being able to deal with user-defined files.

We can try to add some of this, but we fear our javascript skills are not yet on the required level to deal with play-1.js :)

Anyway, it would be great if you could give some input on this. Thanks!

moinejf commented 7 years ago

Hi, There are many topics in your message.

MIDI sound font. I have no MIDI support (nor mp3) in the small set of web browsers that is available for my ARM machine, but using the html5 MIDI API could be a good alternative to the MIDI.JS fonts. Anyway, in all cases, some sound fonts should be downloaded in the user's computers.

Default instrument. Your proposal does not solve the general problem. Actually, the instruments are defined by '%%MIDI program' parameters. These parameters are voice related: they must be inserted in the tune body. My idea is to predefine default instruments per voice outside the ABC files. For this, only a small extension to the ABC notation is needed: define the instrument inside the V:/K: definitions. There were already some proposals to replace the %%MIDI parameter, especially 'I:timbre' from Alexander Scheutzow (http://abcnotation.com/wiki/abc:standard:v2.1:proposals:timbres_midi:alexmidicond:v1). So, I will propose the syntax: V: timbre="timbre name" to be added to the standard. Then, you could set a default instrument by adding: V:* timbre="instrument name" before parsing the user's ABC files.

Sound font loading failure. I did not carefully check this yet, but I don't see any easy workaround. How could a program know if there is any available MIDI font in the user's computer, and where?

joaocc commented 7 years ago

Hi, Sorry about the multiple questions. I can split in different issues to make discussion easier if you prefer.

[1] Regarding the default instrument, our initial driver was dealing with files that don't specify an instrument (we have about 40 of those). In the current implementation, those files are played as "accoustic_grand_piano" (index 0). We would like to be able to specify a different default in the app (for example, 40 or "violin" depending if we use index into the instrument table or specify the instrument by name).

[2] This is a related but separate issue. As of now, we can specify a stf mode of js and mp3. In any of these cases, play-1.js goes out to a server and fetches the needed sound data (either by dynamically loading a ogg-js file or by fetching individual mp3 audiofiles. For an electron based offline app, for this approach to work, we would need to bundle all the instruments in the installer package (which would make the app even bigger). Our intent in the pseudo-code in https://github.com/highskillz/abc2svg/commit/e29a47db97ea3fe94662cec135a1cc513d8c0acb was to keep the current behaviour (search for the content in 'stu') but, if it fails (ie, the .onerror callback is called), return the audio data for the "default_instrument" (which we would make sure would be available).

[3] On your proposals for ABC, we don't have enough understanding of the broader use of the ABC standard to be able to have a meaningful opinion. All we can say is that it seams reasonable. On our side, we would like to keep away from relying on changing content of end-user files, and instead increase the robustness of the processing pipeline.

Thanks

moinejf commented 7 years ago

OK, I think I understood: 1- you want that the voices with no defined instrument are played as a 'default' instrument. 2- you want this default instrument to be used when there is no font for some instrument.

For 1), you could insert a '%%MIDI program' before the ABC file when parsing the tune. In edit.js, the sequence would be:

var abc = new Abc(user);
abcplay.clear();
abc.tosvg("play", "%%play");

abc.tosvg("play", "%%MIDI program 40"); // default instrument = violin

abc.tosvg(abc_fname[0],...
...

For 2), if you know which instrument is available or not, you could change the instruments in the voices. In edit.js, this would be done in the get_abcmodel callback function:

user.get_abcmodel = function(tsfirst, voice_tb, music_types, info) { if (playing) {

        // replace the unavailable instruments by the default
        for (var i = 0; i < voice_tb.length; i++)
            if (!avail_instr[voice_tb[i].instr])
                voice_tb[i].instr = default_instr;

        abcplay.add(tsfirst, voice_tb)
    }
}
joaocc commented 7 years ago

Looks good. We'll give these a try.

In the meantime, if we manage to implement the "dynamic" detection of missing instruments, we will post them as PR.

Thx!