|
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
|
|
|
|
|
It does. It really does, assuming those mag tapes are interleaved like "raided" kind.
To err is human. Fortune favors the monsters.
|
|
|
|
|
|
They use butterflies.
"In testa che avete, Signor di Ceprano?"
-- Rigoletto
|
|
|
|
|
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.
|
|
|
|
|
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.
|
|
|
|
|
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.
|
|
|
|
|
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.
|
|
|
|
|
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);
}
}
}
|
|
|
|
|
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.
|
|
|
|
|
All good. Every problem is difficult, until it's not .
|
|
|
|
|
|
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.
|
|
|
|
|
I found the solution. It couldn't hide from me forever.
To err is human. Fortune favors the monsters.
|
|
|
|
|
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;
|
|
|
|
|
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.
|
|
|
|
|
honey the codewitch wrote: 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. I like it! I've used this approach on occasion when I "couldn't see the forest for the trees".
Software Zen: delete this;
|
|
|
|
|
It also helps keep it cross platform, so it's win win. I developed most of my GFX library for IoT devices on a PC. I would just draw to in memory bitmaps and then write those to the console as ascii. =)
To err is human. Fortune favors the monsters.
|
|
|
|
|
honey the codewitch wrote: memory bitmaps and then write those to the console as ascii That triggers a flashback to the early 90's. At the time all of the fonts in our printers were hand-drawn bitmaps. We had a text format where each character's bitmap was drawn using "." for a white pixel, and "@" for a black one. We then had a utility that would convert the text format to the binary form of the font file.
Software Zen: delete this;
|
|
|
|
|
haha I had a python script that created or extracted win 3.1 .FON files in that format for editing or creating.
I used it as a reference to create my raster font loading routines.
To err is human. Fortune favors the monsters.
|
|
|
|
|
|
I got my book written in French last week from a German seller and browsed some pages.
I felt 50% French words are English and guessed their meanings.
figured out some formulas and graphs and got some sense of this book already...
diligent hands rule....
|
|
|
|
|
formulase
The other half is Latin.
|
|
|
|
|
thanks
diligent hands rule....
|
|
|
|
|
And the third half is German.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|