Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. How did they do it?

How did they do it?

Scheduled Pinned Locked Moved The Lounge
csharpiotperformancehelpquestion
27 Posts 11 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H honey the codewitch

    I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

    To err is human. Fortune favors the monsters.

    D Offline
    D Offline
    David ONeil
    wrote on last edited by
    #2

    honey the codewitch wrote:

    However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas.

    Why? Why not have a 'pre-stream' of events that are the absolute times of next 'event' of each track? Then you just keep polling the track with the next playable event until its 'time' falls behind the next track with an upcoming playable event. Poll that one until ...

    Our Forgotten Astronomy | Object Oriented Programming with C++

    H 1 Reply Last reply
    0
    • D David ONeil

      honey the codewitch wrote:

      However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas.

      Why? Why not have a 'pre-stream' of events that are the absolute times of next 'event' of each track? Then you just keep polling the track with the next playable event until its 'time' falls behind the next track with an upcoming playable event. Poll that one until ...

      Our Forgotten Astronomy | Object Oriented Programming with C++

      H Offline
      H Offline
      honey the codewitch
      wrote on last edited by
      #3

      That's what I do essentially as far as the deltas. My pre stream is n contexts where n is the number of tracks. I use those to pull events out in the right order

      To err is human. Fortune favors the monsters.

      K 1 Reply Last reply
      0
      • H honey the codewitch

        I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

        To err is human. Fortune favors the monsters.

        P Offline
        P Offline
        Peter_in_2780
        wrote on last edited by
        #4

        Even older than MIDI, mergesort on multi mag tapes. The issue sounds awful similar.

        Software rusts. Simon Stephenson, ca 1994. So does this signature. me, 2012

        H 1 Reply Last reply
        0
        • H honey the codewitch

          I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

          To err is human. Fortune favors the monsters.

          L Offline
          L Offline
          Lost User
          wrote on last edited by
          #5

          I have no idea whether this will help, but it might point you in the right direction How To Use Amiga's MIDI Facilities[^]

          1 Reply Last reply
          0
          • H honey the codewitch

            I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

            To err is human. Fortune favors the monsters.

            CPalliniC Offline
            CPalliniC Offline
            CPallini
            wrote on last edited by
            #6

            They use butterflies.

            "In testa che avete, Signor di Ceprano?" -- Rigoletto

            In testa che avete, signor di Ceprano?

            1 Reply Last reply
            0
            • P Peter_in_2780

              Even older than MIDI, mergesort on multi mag tapes. The issue sounds awful similar.

              Software rusts. Simon Stephenson, ca 1994. So does this signature. me, 2012

              H Offline
              H Offline
              honey the codewitch
              wrote on last edited by
              #7

              It does. It really does, assuming those mag tapes are interleaved like "raided" kind.

              To err is human. Fortune favors the monsters.

              1 Reply Last reply
              0
              • H honey the codewitch

                I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

                To err is human. Fortune favors the monsters.

                W Offline
                W Offline
                Wizard of Sleeves
                wrote on last edited by
                #8

                From what I recall, having done some MIDI stuff in the days before time, on a 1 MHz 8 bit CPU with 4k RAM, is that the data stream was at 31.25 kbaud. [insert match equation here] Which was one tick every 10 milliseconds; all 16 channels combined. So all I had to do was was to preprocess everything in less than 10 ms.

                Nothing succeeds like a budgie without teeth. To err is human, to arr is pirate.

                H 1 Reply Last reply
                0
                • H honey the codewitch

                  I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

                  To err is human. Fortune favors the monsters.

                  D Offline
                  D Offline
                  Dougy83
                  wrote on last edited by
                  #9

                  I think you're overcomplicating things. You could use a simple class for each track. Initialise it with the track length, byte offset/state, and a getNextByte(offset/state) callback function. Implement getNextEventTime(), and getNextEvent(). Now you can get the minimum getNextEventTime() of all tracks, and then getNextEvent() for any track that matched that minimum time. Calling getNextEvent() will update that track's next event time. Rinse & repeat. Rinsing is optional.

                  H 1 Reply Last reply
                  0
                  • D Dougy83

                    I think you're overcomplicating things. You could use a simple class for each track. Initialise it with the track length, byte offset/state, and a getNextByte(offset/state) callback function. Implement getNextEventTime(), and getNextEvent(). Now you can get the minimum getNextEventTime() of all tracks, and then getNextEvent() for any track that matched that minimum time. Calling getNextEvent() will update that track's next event time. Rinse & repeat. Rinsing is optional.

                    H Offline
                    H Offline
                    honey the codewitch
                    wrote on last edited by
                    #10

                    How do I know which track to pull an event from next? That's where it gets weird.

                    To err is human. Fortune favors the monsters.

                    D 3 Replies Last reply
                    0
                    • H honey the codewitch

                      I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

                      To err is human. Fortune favors the monsters.

                      O Offline
                      O Offline
                      ot_ik_
                      wrote on last edited by
                      #11

                      Long time not working with MIDI files. Aren't you mixing track and channels? Why would you play multiple track at once?

                      1 Reply Last reply
                      0
                      • H honey the codewitch

                        How do I know which track to pull an event from next? That's where it gets weird.

                        To err is human. Fortune favors the monsters.

                        D Offline
                        D Offline
                        Dougy83
                        wrote on last edited by
                        #12

                        My last response is suspected of being spam, probably because it contains code, and programming questions are forboden in the lounge. Can you provide a link to your question in the programming section? The code is very simple.

                        1 Reply Last reply
                        0
                        • H honey the codewitch

                          How do I know which track to pull an event from next? That's where it gets weird.

                          To err is human. Fortune favors the monsters.

                          D Offline
                          D Offline
                          Dougy83
                          wrote on last edited by
                          #13

                          From whichever tracks have the next time equal to the minimum-next-time of all tracks:

                          void playNextNotes()
                          {
                          int nextTime = MAX_INTVAL;
                          for (auto &track : tracks)
                          {
                          if (track.getNextTimestamp() < nextTime)
                          nextTime = track.getNextTimestamp();
                          }

                          waitUntil(nextTime);
                          
                          for (auto &track : tracks)
                          {
                              if (track.getNextTimestamp() == nextTime)
                              {
                                  auto event = track.getNextEvent();
                                  midi.playEvent(event);
                              }
                          }
                          

                          }

                          H 1 Reply Last reply
                          0
                          • H honey the codewitch

                            I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

                            To err is human. Fortune favors the monsters.

                            C Offline
                            C Offline
                            Cpichols
                            wrote on last edited by
                            #14

                            I know this feel. The problem is always present in your mind like an earworm. It invades your dreams and you can't escape it even though that is what it will take to gain a fresh perspective on it. Have you tried any of the meditation apps? Maybe you could attend a yoga class? Sometimes writing down or talking out everything you know about the issue can help offload some of the brain activity. There is a solution. Try to be settled by that.

                            H 1 Reply Last reply
                            0
                            • D Dougy83

                              From whichever tracks have the next time equal to the minimum-next-time of all tracks:

                              void playNextNotes()
                              {
                              int nextTime = MAX_INTVAL;
                              for (auto &track : tracks)
                              {
                              if (track.getNextTimestamp() < nextTime)
                              nextTime = track.getNextTimestamp();
                              }

                              waitUntil(nextTime);
                              
                              for (auto &track : tracks)
                              {
                                  if (track.getNextTimestamp() == nextTime)
                                  {
                                      auto event = track.getNextEvent();
                                      midi.playEvent(event);
                                  }
                              }
                              

                              }

                              H Offline
                              H Offline
                              honey the codewitch
                              wrote on last edited by
                              #15

                              I got it all working last night. The trick was in implementing your "getNextEvent()" method correctly (I don't call mine that, but same-o same-o)

                              To err is human. Fortune favors the monsters.

                              D 1 Reply Last reply
                              0
                              • H honey the codewitch

                                How do I know which track to pull an event from next? That's where it gets weird.

                                To err is human. Fortune favors the monsters.

                                D Offline
                                D Offline
                                Dougy83
                                wrote on last edited by
                                #16

                                The class code is here: honey code - My Paste Text[^]

                                1 Reply Last reply
                                0
                                • W Wizard of Sleeves

                                  From what I recall, having done some MIDI stuff in the days before time, on a 1 MHz 8 bit CPU with 4k RAM, is that the data stream was at 31.25 kbaud. [insert match equation here] Which was one tick every 10 milliseconds; all 16 channels combined. So all I had to do was was to preprocess everything in less than 10 ms.

                                  Nothing succeeds like a budgie without teeth. To err is human, to arr is pirate.

                                  H Offline
                                  H Offline
                                  honey the codewitch
                                  wrote on last edited by
                                  #17

                                  Yeah, it wasn't really the speed that was my problem. It was the difficulty of streaming midi file tracks while merging them without loading more than I absolutely had to in RAM at once. I got it working. It only keeps N messages in memory at a time, where N is the number of tracks. That's about as good as it gets I think.

                                  To err is human. Fortune favors the monsters.

                                  1 Reply Last reply
                                  0
                                  • H honey the codewitch

                                    I got it all working last night. The trick was in implementing your "getNextEvent()" method correctly (I don't call mine that, but same-o same-o)

                                    To err is human. Fortune favors the monsters.

                                    D Offline
                                    D Offline
                                    Dougy83
                                    wrote on last edited by
                                    #18

                                    All good. Every problem is difficult, until it's not :laugh: .

                                    1 Reply Last reply
                                    0
                                    • C Cpichols

                                      I know this feel. The problem is always present in your mind like an earworm. It invades your dreams and you can't escape it even though that is what it will take to gain a fresh perspective on it. Have you tried any of the meditation apps? Maybe you could attend a yoga class? Sometimes writing down or talking out everything you know about the issue can help offload some of the brain activity. There is a solution. Try to be settled by that.

                                      H Offline
                                      H Offline
                                      honey the codewitch
                                      wrote on last edited by
                                      #19

                                      I found the solution. It couldn't hide from me forever. :)

                                      To err is human. Fortune favors the monsters.

                                      1 Reply Last reply
                                      0
                                      • H honey the codewitch

                                        I'm working on complicated MIDI wizardry for IoT gadgets, so I can make MIDI "smart" pedals and controllers and such. Playing a multitrack MIDI file without reading it into memory is a bear. I have just not been able to get this code right. The trouble is each midi event has a delta attached to it that is the offset in "MIDI ticks"* from the previous event. *A midi tick is a fixed time duration based on the tempo and timebase. With a multitrack midi file, each track has its own sequence of events and the deltas are all relative to that track. However, in order to play them, you must merge all the tracks into one event stream, adjusting the deltas. The actual adjusting of the deltas isn't so bad, but the logic to figure out when to pull from what track - I'm not even sure I have it right yet, because my code has other issues. My point in all this, is MIDI is early 1980s protocol and multitrack midi isn't exactly brand spanking new. Sequencers with scant amounts of RAM were doing this. I feel like in so many ways MIDI was designed to make it possible to do things on little devices without much RAM. But this particular operation - in C# I just merged the tracks in memory before I played them. I can't afford the RAM or the CPU to do that here. I have to stream everything. And I've convinced myself I'm overcomplicating things. I hate when I do that - it means I have tunnel vision, and/or am missing something big and important. I don't like knowing that I don't know something I need to know, you know? It bugs me, like a song that's stuck in my head I can't remember the entire hook to.

                                        To err is human. Fortune favors the monsters.

                                        G Offline
                                        G Offline
                                        Gary Wheeler
                                        wrote on last edited by
                                        #20

                                        For a moment forget about your environment and try to think like the original developers. You've got very limited RAM, and slightly-less limited code space. This means your code has to be clever. It also implies you don't necessarily have to handle the arbitrary, general case where all possibilities are handled regardless of what seems to be allowed by the parameters. As an example, suppose you have a signed 16-bit value to handle. Does the usage really need to allow for negative values? What about zero (0)? What's the actual, practical range for the value? Figuring out the actual, implicit (and undocumented) constraints can help figure out a practical algorithm.

                                        Software Zen: delete this;

                                        H 1 Reply Last reply
                                        0
                                        • G Gary Wheeler

                                          For a moment forget about your environment and try to think like the original developers. You've got very limited RAM, and slightly-less limited code space. This means your code has to be clever. It also implies you don't necessarily have to handle the arbitrary, general case where all possibilities are handled regardless of what seems to be allowed by the parameters. As an example, suppose you have a signed 16-bit value to handle. Does the usage really need to allow for negative values? What about zero (0)? What's the actual, practical range for the value? Figuring out the actual, implicit (and undocumented) constraints can help figure out a practical algorithm.

                                          Software Zen: delete this;

                                          H Offline
                                          H Offline
                                          honey the codewitch
                                          wrote on last edited by
                                          #21

                                          I totally agree with this, and when I originally planned this I was writing clever code. :) I use signed values for most things because midi is largely a 7-bit protocol. that way if I accidentally set the sign bit the number jumps out at me as negative. In the end I solved it. It took me moving my code to a real PC so I could fire up a debugger. It was just too complicated to work through it without one.

                                          To err is human. Fortune favors the monsters.

                                          G 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups