Search Unity

Maestro Midi Player Tool Kit - Good news for your rhythm game !

Discussion in 'Made With Unity' started by BachmannT, Apr 14, 2018.

  1. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Yes, I confirm there is strange behaviors. I need more time to understand. I take you inform.
     
  2. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello
    Good news, the issue has been identified. The bad news is that the correction is not simple, I need some time to make a full test.
    A new version is quite ready, I will publish it before making important change. So the correction could be available to end of september. Is it correct for you ?
    BR
     
  3. BasicallyGames

    BasicallyGames

    Joined:
    Aug 31, 2018
    Posts:
    91
    Yeah, no rush! Thanks for working on a fix. I'll just work around the issue by recording a WAV of the music and using that until the issue has been resolved.
     
  4. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello
    Finally, the fix was not so hard to implement, so I have added it to the version 2.84:

    Version 2.84 on the way :)
    • Now switching between Midi playing is immediate.
    • Add functions to facilitate integration with Bolt [Pro]
    • Start and Stop playing gradually (ramp-up) [Pro].
    • Now Midi play also with Time.timeScale = 0.
    • And globally, a lot of enhancements on the demos (7 for free, 6 more with the pro version).
     
  5. Jezeus

    Jezeus

    Joined:
    Sep 27, 2018
    Posts:
    6
    Hi,
    Is there a way to be notified when there is a rest going on (whatever the rest size) ? there are events for notes on and off but I cannot find any for rests. I need to display a score, and computing the rest duration in between notes off and on is not sufficient, there is missing data, the resulting score cannot always be equal to the reference midi. Even when parsing with MidiLoad, cannot have the rest information.
    Thanks in advance for the advice !
     
    Last edited: Sep 10, 2020
  6. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello, what is a rest ?
     
  7. Jezeus

    Jezeus

    Joined:
    Sep 27, 2018
    Posts:
    6
  8. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    ok, I understand ! Sorry, i'm quite bad in english.
    'rest' don't exists in midi norm :https://discussions.apple.com/thread/6517602. So you can't have event of type rest.
    You have to deduce it from TimeSignature and the other notes event, if there is a hole in the tick count ... there is a rest !

    Perhaps, you could have the need of these API with MPTK:

    MPTK_NumberBeatsMeasure

    int MPTK_NumberBeatsMeasure
    From TimeSignature event: The numerator counts the number of beats in a measure. For example a numerator of 4 means that each bar contains four beats. This is important to know because usually the first beat of each bar has extra emphasis. http://www.deluge.co/?q=midi-tempo-bpm

    MPTK_TimeSigNumerator
    int MPTK_TimeSigNumerator
    From TimeSignature event: The numerator counts the number of beats in a measure. For example a numerator of 4 means that each bar contains four beats. This is important to know because usually the first beat of each bar has extra emphasis. In MIDI the denominator value is stored in a special format. i.e. the real denominator = 2^[dd] http://www.deluge.co/?q=midi-tempo-bpm

    BR
    Thierry
     
  9. Jezeus

    Jezeus

    Joined:
    Sep 27, 2018
    Posts:
    6
    Hi again ! Many thanks for this reply. It's amazingly true, there is no rest in midi, must be computed, knowing there are multiple solutions for a rest ... anyways, not your fault ! Thanks for the links, I will do it this way, do not have a choice. But I must tell you that I am unable to open these links (same goes for the ones in your source code), I always have these errors:
    Fatal error: Only variables can be passed by reference in /homepages/23/d181601631/htdocs/Drupal7/sites/all/modules/commerce/modules/cart/commerce_cart.module on line 1164

    Thanks again for your time.
     
  10. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    ok thank to inform me. I will update the doc!
    Please, don't hesitate to let a comment on the Unity store, it's very important to stay alive!
    All my best
    Thierry
     
  11. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    424
    Hi! Does this asset work in the background on both android an ios?
     
  12. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello
    Yes!
     
  13. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Sorry, I was short in time to answer more in detail. To play in background, we need two processes: the Midi Reader and the Synthesizer. These two process are running out of the main Unity Thread, so they are working in autonomous from Unity. What you done on Unity don't interfere with the player and the synth. Obviously, if heavy CPU is need for Unity, that could have an impact to the Midi player. But it's another story!
     
    justtime likes this.
  14. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    424
    Thanks for explanation! Could you specify which demo scene i can use for test? I used "TestMidiPlayer" for android build and it doesn't work in background.
     
  15. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Try the demo scene TestMidiFilePlayer.
    Perhaps, I did'nt understood your question. Could you be more precise by "background" ? Is playing Midi is not stopped when smartphone app is on background ?
     
  16. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    424
    Sorry, i tried TestMidiFilePlayer. By background I mean when app is on background, so i can use another app for example (not just another from UI thread) That is "Is playing Midi is not stopped when smartphone app is on background".
     
  17. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    By default, no.
    Application is paused on Android and iOS when app is send to background.
    Perhaps, there is a solution with background service ...
    Please take me inform if you get some result!!!
    Best regards
     
    justtime likes this.
  18. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    424
    Thanks for feedback! Work in background possible with different sound library, for example BASS. They also have midi possibilities.
     
  19. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Have you tested with BASS ?
     
  20. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    424
    Now, because i don't know how your asset works, but i will certainly investigate it.
     
  21. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Dear Bachmann-san,

    Thank you for your support by email a few days ago. This time, I'm asking you here, because sharing the info is helpful for to beginners like me.

    From your TestMidiStream.cs, I want to set different instruments to different channels, as
    channel 1 for patch 40 (violin)
    channel 2 for patch 14 (Tubler Bells).

    So I wrote below. Now channel 1 is OK (Tubler Bells). But channel 0 is Piano.
    What is wrong with this?

    if (!midiStreamPlayer.OnEventSynthStarted.HasEvent()){
    CurrentPreset = 40;
    StreamChannel = 0;
    midiStreamPlayer.OnEventSynthStarted.AddListener(EndLoadingSynth);
    CurrentPreset = 14;
    StreamChannel = 1;
    midiStreamPlayer.OnEventSynthStarted.AddListener(EndLoadingSynth);
    }
    ------------------------------
    // Modify PlayOneNote
    private void PlayOneNote(int note, int velocity, int channel)

    -------------------------------
    PlayOneNote(CurrentNote, 80, 0);
    PlayOneNote(CurrentNote, 80, 1);
     
    Last edited: Sep 19, 2020
  22. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello Mister
    First of all, thank for your appreciation in the Unity store, it's always very appreciable and encouraging.

    For your question, I will answer more later with a full example. Just for now, OnEventSynthStarted is not the good method to change the preset. Let me some time to put a good answer!
    Best Regards
    Thierry
     
  23. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Thank you for your support. I'll wait.

    Regards,
    MathComposer
    Kazuo
     
  24. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Sorry for the delay. I wanted to build a short example.
    The method to use for changing preset if MPTK_ChannelPresetChange. The method must be called after the synthesizer is initialized. So we used the event OnEventSynthStarted to call EndLoadingSynth in the script.
    Try this code in your script:

    Code (CSharp):
    1.  
    2. void Start()
    3. {
    4.             if (midiStreamPlayer != null)
    5.             {
    6.                 // The call of this methods can also be defined in the prefab MidiStreamPlayer from the Unity editor inspector.
    7.                 // See "On Event Synth Started.
    8.                 // EndLoadingSynth will be called when the synthesizer will be ready.
    9.                 if (!midiStreamPlayer.OnEventSynthStarted.HasEvent())
    10.                     midiStreamPlayer.OnEventSynthStarted.AddListener(EndLoadingSynth);
    11.             }
    12.             else
    13.                 Debug.LogWarning("midiStreamPlayer is not defined. Check in Unity editor inspector of this gameComponent");
    14. }
    15.  
    16. /// <summary>
    17. /// This methods is run when the synthesizer is ready.
    18. /// It's a good place to set some synth parameter's as defined preset by channel
    19. /// </summary>
    20. /// <param name="name"></param>
    21. public void EndLoadingSynth(string name)
    22. {
    23.             Debug.LogFormat($"Synth {name} is loaded");
    24.  
    25.             // Set music box (preset 10) to channel 0. Could be different for another SoundFont.
    26.             midiStreamPlayer.MPTK_ChannelPresetChange(0, 10);
    27.             Debug.LogFormat($"Preset {midiStreamPlayer.MPTK_ChannelPresetGetName(0)} defined on channel 0");
    28.  
    29.             // Set reed organ (preset 20) to channel 1. Could be different for another SoundFont.
    30.             midiStreamPlayer.MPTK_ChannelPresetChange(1, 20);
    31.             Debug.LogFormat($"Preset {midiStreamPlayer.MPTK_ChannelPresetGetName(1)} defined on channel 1");
    32. }
    33.  
    PS: i updated the demo TestMidiStream to be more clear on this subject. That was not so obvious.

    Thierry
     
  25. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Now it worked well.
    I really appreciate your support.

    Regards,
    kazuo
     
  26. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    A few questions on TestMidiWriter.cs.

    Hello, Bachmann-san,

    Helped by your TestMidiStream.cs, I completed conversion of one of my program from Python to Unity, and now I'm adding Midi file saving function. So, let me ask a few small questions on TestMidiWriter.cs.

    (1) Just confirmation. In your tool. Midi channel is from 0 to 15. But for Writer, channel is 1 to 16. (Your set 1 for channel 0 in the file). Probably that is due to NAudio.Midi, right?

    (2) For MPTK_AddEvent (other than playing notes), you set absoluteTime++.
    Why you add ++? Same timing (just using absoluteTime without++) doesn't work well? (Sorry I didn't test.)

    Regards,
    Kazuo
     
  27. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello Kazuo
    I need to look at this demo. I writed it a long time ago! and go back to you with answers.
    Thierry
     
  28. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello Kazuo
    (1) Yes channel is from 1 to 16. It's not consistent with other MPTK API. I apologize for that. I will perhaps change this in a next version.
    (2) I can't remenber why i used absoluteTime++.!!! perhaps to control in the Midi generated ... So, useless, for sure.

    Best Regards
    Thierry
     
  29. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Bachmann-san,

    Than you for sharing your time. Well Understood.

    Regards,
    Kazuo
     
  30. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Only one Drum note played by MidiStreamPlayer

    Thank you for your support. This is a bit more serious question.
    By MidiStreamPlayer, I can't play more than one drum note at the same timing.
    How can I play Bass_drum, Snare and Hihat at the same time?

    Based on your TestMidiStream.cs
    -------------------------------
    // Modify PlayOneNote as
    private void PlayOneNote(int note, int velocity, int channel)

    -------------------------------
    Notes (e.g. Piano) below can play at the same time.
    PlayOneNote(60, 80, 0); // note C4 channel 0
    PlayOneNote(64, 80, 0); // note E4 channel 0

    But, drum notes below cannot play at the same time and only the last note plays. Why and How can I fix this?
    PlayOneNote(36, 80, 9); // Bass_drum channel 9
    PlayOneNote(42, 80, 9); // Closed Hihat channel 9
     
  31. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello Kazuo
    try this before playing notes:
    midiStreamPlayer.MPTK_KillByExclusiveClass = false;
    if it correct your issue, I will explain!

    Best regards
    Thierry
     
  32. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Bachmann-san,

    It worked well. Thank you.

    Best Regards,
    Kazuo
     
  33. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Some explanation:
    Kill By Exclusive Class: the default behavior of a Midi synthesizer is to released a note when a note of the same class is played in the same preset. The Class (a number) is defined in the SoundFont. Generally, this function is used by drum kit: a cymbal will kill other drum instrument.

    Currently, this parameter is available only in the prefab inspector of MidiFilePlayer or by script. With the next version it will be available in other MPTK prefab.

    Best Regards
    Thierry
     
  34. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Thank you for your kind explanation.
    Understood. I really appreciate your support.

    Best Regards,
    Kazuo
     
  35. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    I like have talk about MPTK, it's always interesting; so thank to you!
    I created a post about SoundFont exclusive classes here

    Have Fun !
     
  36. djidane535

    djidane535

    Joined:
    Jun 19, 2016
    Posts:
    3
    Hi!

    Thanks for your hard work on this library. It fills exactly a need I had for making rythm games based on MIDI files. I have just one regret about it at the moment: the lack of support for WebGL engine.

    I started to participate to a few game jams, and I know it's very important to have a WebGL version of the game. Before buying the Pro version, is there any plan to make it compatible? (is it possible or are there any major missing components preventing it?).

    Thanks in advance.
     
  37. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello
    Thanks for your interest with MPTK.
    Sadly, there is no solution for WebGL with its current version. Mainly, the issues is WebGL platform does not support threads,so it's not possible ...
    Sorry.
    All My Best
    Thierry
     
  38. djidane535

    djidane535

    Joined:
    Jun 19, 2016
    Posts:
    3
    Thanks for your honest answer.
     
  39. Linkraft

    Linkraft

    Joined:
    May 30, 2019
    Posts:
    1
    Is there a way to get the current measure being played as well as the current beat of that measure? Either from MidiFileLoader or MidiFilePlayer?
     
  40. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello
    Not directly. You have to convert the current tick MPTK_TickCurrent to the current measure. You will need also MPTK_NumberBeatsMeasure MPTK_DeltaTicksPerQuarterNote and perhaps MPTK_NumberQuarterBeat ... and a good understanding of music notation!!!
    That could be an interesting new method in the API!
    Best Regards
    Thierry
     
    Linkraft likes this.
  41. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Hi, Bachmann-san, This is Kazuo,again.
    I need your help.

    I completed development of my music tool on Windows and now I built it for Android. But on Android, the notes did not play at regular intervals.

    Even for the simplest program below, notes played at irregular intervals.

    I found you commented a few years ago. So I imported the package.
    But I don't understand how to fix the issue using below (or any other way) with MidiStreamPlayer.
    Could you please help me?

    Thank for your kind comment ! The lag issue on Android is a well known problem with audio ;-) You could try this package https://assetstore.unity.com/packages/tools/audio/android-native-audio-35295 to correct the problem. Please, go to the MPTK Forum if you want to continue this discussion.

    ----
    void Update()
    {
    if (Time.time > prevTime + 0.2f){
    PlayOneNote(60,80,0.2f,0);
    prevTime = Time.time;
    }
    }

    Regards,
    Kazuo Kuroiwa
     
  42. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Hello
    Thank for using MPTK!
    I think the issue is not from the lag with audio on Android but rather with Update(). There is no guarantee to be enough regular for music. Perhaps you could try with FixedUpdate ? but not sure that will be enough regular.

    The best method is to use system thread: like this
    Code (CSharp):
    1.  new Thread(PlaySequencerThread);
    If you have the Pro version, have a look to the demo EuclideSeq and source code TestEuclideanRhythme.cs

    But beware, you can't run Unity API in a system thread. It's not as coroutine.
    Good news :) MPTK has been designed to be used within a system thread. So you can call method as this one
    Code (CSharp):
    1.  midiStream.MPTK_PlayEvent(new MPTKEvent()
    to play music.

    Take me inform !
    Best Regards
    Thierry
     
  43. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Bachmann-san,

    Thank you for your quick response every time.
    I tested FixedUpdate() too and got the similar irregular result.

    I don't know what are "system thread" and Unity API.
    I have PRO version. So I'll check your TestEuclideanRhythme.cs to learn them.

    Regards,
    Kazuo
     
  44. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    One question.
    Your PlayOneNote() is as below. * I slightly modified to set note, velocity, duration and channel.
    So it seems my program already uses above. Doesn't it?

    ------
    private void PlayOneNote(int note, int velocity, float NoteDuration, int channel)
    {
    // Start playing a new note
    NotePlaying = new MPTKEvent()
    {
    Command = MPTKCommand.NoteOn,
    Value = note,
    Channel = channel,
    Duration = Convert.ToInt64(NoteDuration * 1000f), // millisecond, -1 to play undefinitely
    Velocity = velocity,
    Delay = Convert.ToInt64(NoteDelay * 1000f),
    };
    midiStreamPlayer.MPTK_PlayEvent(NotePlaying);
    }
     
  45. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    Yes, absolutely !
    System.thread is a framework available when you are using C#. It's independent of Unity. You could look at this site https://www.geeksforgeeks.org/how-to-create-threads-in-c-sharp/ to well understand c# thread.
    Have Fun!
     
  46. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Thank you.
    But that means I've already used it and have the issue. So, I have No way to solve the issue. Right?
     
  47. BachmannT

    BachmannT

    Joined:
    Nov 20, 2016
    Posts:
    388
    No, that means that you have to call your method PlayOneNote(int note, int velocity, float NoteDuration, int channel) from your thread. See method PlaySequencerThread() in estEuclideanRhythme.cs
    Don't forget a call to Thread.Sleep(1); in your loop in the thread to not knock the CPU !!!
     
  48. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Thank you. I'll try it.
     
  49. MathComposer

    MathComposer

    Joined:
    Sep 18, 2020
    Posts:
    14
    Thank you.
    I wrote above simple program using a thread and understood that
    it is no Unity Update(), but like a normal programming language under it's own timeline.
    I'll modify my program using the thread.

    Regards,
    Kazuo
     
  50. citromfa

    citromfa

    Joined:
    Jan 18, 2019
    Posts:
    1
    Hello!

    I've been using the free version of MPTK and so far It's been perfect.
    Thank you for making this publicly available!

    One thing has been bothering me, though.
    I'm trying to pass a byte array into a MidiFilePlayer prefab, but I can't seem to figure out how to play it.
    The byte array is downloaded from the web and it is in .mid format.
    When I write this piece of code, I can see the midi events and even the length of the song, but MidiFilePlayer refuses to play it:
    void LoadMidi(byte[] bytes)
    {
    MidiPlayer.miditoplay = new MidiLoad();
    MidiPlayer.miditoplay.MPTK_Load(bytes);

    // these values are displayed correctly
    Debug.Log("MidiPlayer event count: " + MidiPlayer.MPTK_MidiEvents.Count);
    Debug.Log("MidiPlayer duration: " + MidiPlayer.MPTK_DurationMS);

    // but the midi is not being played
    MidiPlayer.MPTK_Play();
    }

    Do you have any suggestions as to how can I parse a byte array into the MidiFilePlayer and then play it?
    Thank you for your time.

    Best regards,
    Robert