paulrosen / abcjs

javascript for rendering abc music notation
Other
1.94k stars 285 forks source link

How to update audio params without calling setTune() method again. #777

Open pandya293 opened 2 years ago

pandya293 commented 2 years ago

Hello Paul, Thank you very much for very good library and every-time very much supporting.

I am using v6.0.1 abcjs version in web html page. I need to on/off drum param while user paying music. Also I need to do mute/unmute volume while already playing music-note.

currently whenever user make metronome ON/OFF. I need to update my abc string with %%MIDI param in header and again calling renderABC and setTune method on synthControl object. Therefore when user enable/disable metronome, music-sheet is re-start playing from the 1st beat.

Can I update audio param while paying music-note? So If user reach to 3rd bar and make on/off metronome or mute/unmute volume at that time, without disturbing current play operation, it just update metronome and volume in synthControl. And while paying next 4th bar it apply metronome and volume param new change.

Will it possible to update drum and volume on/off without calling ABCJS.renderAbc, synthControl.load, and synthControl.setTune

Current in my code, when user make volume mute/unmute below three methods will execute and it reset the music-note play from 1st beat.

  1. ABCJS.renderAbc(),
  2. synthControl.load()
  3. synthControl.setTune()

Thank you for your support and time,

Regards, Punita

paulrosen commented 2 years ago

That's not currently supported but it is a good feature. I can think of a possible workaround:

1) create the drum in a separate string of the same length and call prime() but not play(). 2) do the same thing with your music, without the drum. 3) start play() on both buffers in statements right next to each other. They will play together and you can pause them independently. I've done that and javascript is fast enough that they start together.

The trick would be to know where to unpause so that the drum isn't out of time. Probably what you would have to do is pause the music which will give you the location it currently is, then start both again. I don't know how fast that would be so there might be a little silence when you do that but they would be in sync at least.

You could also, instead of pausing right away when the user clicks the button, pause in response to the beat callback so you are always pausing on a beat and restarting on a beat callback. I don't know if that would be exact enough or not.

Good luck! If you make it work let me know.

I'll think about it some more and maybe come up with another idea.

pandya293 commented 2 years ago

Thanks for you reply. I will try your suggestion and let you know.

pandya293 commented 2 years ago

can you please let me know how to create abc string with only drum option and no rhythm-note with play?

abc string without drum: let abc_string = "M: 4/4\nL: 1/8\nQ:1/4=60\nK:clef=perc stafflines = 1\n%%equalbars 1\n%%stretchlast 0.6\n%%partsbox 1\nV:1\nA2 z2 z2 z2|\nz2 z2 z2 A2|\nz2 z2 A2 z2|\nA2 z2 z2 z2|\nA2 z2 z2 z2|\nz2 A2 z2 z2|\nz2 A2 z2 z2|\nA2 z2 z2 z2|\nA2 z2 z2 z2|\nz2 A2 z2 z2|";

abc string with drum let abc_string_with_drum = "M: 4/4\nL: 1/8\nQ:1/4=60\nK:clef=perc stafflines = 1\n%%equalbars 1\n%%stretchlast 0.6\n%%partsbox 1\n%%MIDI channel 10\n%%MIDI program 0\n%%MIDI drumon\n%%MIDI gchordoff\n%%MIDI drum dddd 76 77 77 77 70 70 70 70\nV:1\nA2 z2 z2 z2|\nz2 z2 z2 A2|\nz2 z2 A2 z2|\nA2 z2 z2 z2|\nA2 z2 z2 z2|\nz2 A2 z2 z2|\nz2 A2 z2 z2|\nA2 z2 z2 z2|\nA2 z2 z2 z2|\nz2 A2 z2 z2|";

pandya293 commented 2 years ago

I am very new in create abc string, as you have suggested I have created object of CreateSynth class, one abc string with %%MIDI param and 2nd without %%MIDI param and start playing both synth

When user press On/OFF Metronome button at that start playing drum's Synth on onBeat playback method of main normal music's TimingCallbacks.

My issue is that actual rhythm is playing two time from 1st and 2nd both synth's audio object.

How Can I create abc string that only play drum on 4/4 measure length? currently rhythm-not sound coming two times with 0.5 second fractional, but its audible two sounds. I will share video-clip after some time.

Thank You Paul

pandya293 commented 2 years ago

I have removed all A2 rhythm note from drum's abc string. so it removed music-note two time sound while play two CreateSynth object simultaneously.

Metronome on/off between music is playing is worked perfectly!! But still there is issue in Volume mute/unmute while playing music-note.

can I update soundFontVolumeMultiplier value while playing ?

Thank you very much!!

paulrosen commented 2 years ago

Sorry for the delay in answering...

I'm not sure I follow what you are doing but I would do it a little differently. I would use just one abc_string and control the drum with parameters. So use the first string above for both, but for the metronome part call it with the parameters:

var metronome = abcRender("*", abc_string)
// ...
midiBuffer.init({
  visualObj: metronome[0],
  options: {
    drum: "dddd 76 77 77 77 60 30 30 30",
    voicesOff: true
  }
})

That way you only have one abc_string to keep straight.

pandya293 commented 2 years ago

Thanks for you reply!!

Where should I execute this code ? White playing music. If I call midiBuffer.init() method in onBeat() callback then playing take few seconds pause.

Metronome On/Off is worked perfectly with two diff synth control created.

But now issue in changing BPM value while user is playing music-note. I am setting qpm param as below, but we have to stop midiBuffer and then again start.

midiBuffer.init({ visualObj: metronome[0], options: { drum: "dddd 76 77 77 77 60 30 30 30", voicesOff: true, bpm: 120 } })

e.g. I have to call midiBuffer.stop method, then after few second, again call midiBuffer.init() then in success response of init() method we will calling midiBuffer.start().

Thank You Sir!!

paulrosen commented 2 years ago

I think you will have to stop and restart to change the tempo. If you get the return value from pause(), that is the position it is currently at. Then when you restart, you can immediately seek() to that position.