"luserXtrog" <
[email protected]> wrote in message
[overdue snippage]
I wrote a midi synth a few months ago (takes midi, produces
waveform...).
my idea was to make a more-or-less textual transcription of the MIDI
opcode
stream (although I would change delays into commands). this way, I would
have the full capabilities of the synth at-hand.
<
That sounds cool. But hopefully you'll have some niceties
like refering to notes by name, velocities by dynamic
(pp,p,mp,mf,f,ff), and those variable-length numbers.
it is not clear if some "gloss" would be in-line here...
<
I don't understand that fragment. Do you mean we shouldn't
hijack this thread for midi stuff? Do you mean my post
should have led-in to boasting about some old program
with some sort of segue? Do you mean the glissando effect
could be dealt with via some sort of macro-expansion?
this combines both points.
by "gloss" I meant what you meant be "niceties"...
basically, I am not sure if such niceties would be appropriate, but I
guess
some could be added...
<
Perhaps two phases? Like an assembler and compiler. The niceties
would work at a higher level (perhaps little more than macro
expansion), and the assembler listing would use the thinnest
set of mnemonics necessary not to require instrument numbers and
"note on" to be looked up in order to read.
yeah, maybe...
yesterday, I got around to implementing part of the process (binary MIDI ->
ASCII).
on average, there seems to be about a 2.9x inflation...
possible features being:
note names;
instrument names;
...
so, one could type:
"C0,synbass" vs "C0,38"
but, doing this almost demands command nmonics, ...
"PC 0,synbass NtOn 0,A4,127"
<
Not very hard with an enum, a char *[], and an X-macro.
#define instruments \
X(synbass) \
X(guitar) \
X(organ4)
#define X(a) a,
enum { instruments } einst;
#undef X
#define X(a) #a,
char *sinst[] = { instruments };
#undef X
A for loop with strcmp to turn a string into an enum,
and a simple indexing to turn the enum back to a string.
Quick. Painless.
lookups are not too difficult...
the issue though is that it would require more effort to parse the token.
with raw numbers I can get by with a while loop:
i=0; while((*s>='0') && (*s<='9'))i=i*10+((*s++)-'0');
basically, I was designing a character-level syntax, rather than a
tokenizing syntax...
handling multiple token-types in a character-level syntax is a pain...
and it is no longer clear exactly how far to go...
but, then again, I guess it could also be argued that if tools were going
to
have to rely on lots of knowledge of MIDI, they may almost just as well
craft the opcode stream manually, ... but, at the same time, lots of
knowledge of MIDI would still be necessary, for example, to know how to
operate the various controllers, ...
as well, with so many names and nmonics, there could easily be a 10x-20x
inflation vs the binary form, ...
so, this is why my original idea had leaned more towards minimalism,
mostly
so it would be mostly intended for machine processing, and for limited
human
usage, rather than something aiming more for human readability... (none
the
less, it could still be read and written, even if possibly with the help
of
a few text-files containing tables...).
in any case, it will still be far more readable than a hexdump, which
would
help with debugging, ... as well as being conviniently representable in C
strings, easier to process and craft than the raw opcodes, ...
<
Totally.
yep...
I had noticed though that, since my single-letter nmonics (A,B,C,D,E) are
mapped 1:1 with the hex values, in many cases the prefix of many commands
ends up resembling the hex version...
as is, spaces will be optional...
"C0,1T8N0,69,127T64M0,64"
would do the same as:
"C0,1 T8 N0,69,127 T64 M0,64"
and the same as:
"C 0,1 T 8 N 0,69,127 T 64 M 0,64"
...
<
All spaces are optional? That's a little wacko jacko.
the spaces are optional, since to parse them I insert periodic
whitespace-eating loops.
as noted, this is a char-level syntax rather than a tokenizing one.
similarly, for many tasks we don't really need the spaces anyways...
of course, I could use channel numbers 1-16 vs 0-15, so that at least
channel 10 is percussion, vs 9...
<
It's nice when the interface uses the same terminology as the
documentation. If a midi-knowledgeable non-programmer musician
tried to use your system, I suspect (s)he would expect 10 rather
than 9 to be drums.
maybe, I hadn't really that much considered human-produced data to be all
that important...
most data then would likely come either from prior-transcribed binary midi,
or from procedural generation (such as "drum machine" loops, ...).
of course, for procedural generation, support for absolute timecodes (and
the ability to have events out of order) would be convinient, but supporting
this would require a much more complex process to transcribe into binary
midi.
it is much simpler to produce multiple flat streams and then to merge them
later (I already have the logic for this for binary midi, for text midi
likely I would just convert to binary and merge this way, and then probably
convert back to ASCII...).
another possible approach could be to support such an ASCII form as well as
the binary form for driving the synth, but for now this is not needed (I can
convert to binary easily enough before sending it into the synth...).
"C1,1T8N1,69,127T64M1,64"
or such...
<
Niceties are nice; but I do agree that a barebones version
would be much more flexible for the expert.
yep, as well as being fast...
I am actually designing the notation more for machines than for humans, the
textual form is mostly to make inspecting data easier, and also making it a
little less effort to craft the data (vs the binary form where one has to
worry about a lot of little detail things...).
but, the "textual" aspect is more a sideband aspect...
FWIW, I actually before designed a bytecode/interpreter which worked this
way (for GP tasks), where the bytecode was represented in ASCII, and so
could thus be displayed via printf. internally though, it was structured
much like any other simplistic interpreter.
it is also similar to how I often manage "signature strings", where the
ASCII form is cannonical (there is no binary form), but most of the code
which handles them is based around loops and switches, and performs
similarly to if it were a binary representation. (note that sig strings do
not allow any whitespace, every character is meaningful and itself drives
the logic...).
so, ASCII need not be token based and slow...