[comp.sys.amiga] MIDI Questions ..

eraps2@aspvax.UUCP (09/11/87)

Well, thought I'd put my two cents in.  Yes, there is a problem.  No, it
is NOT in the hardware.  No it is NOT in the Amiga software.  It comes
from using the wrong tool to do the job.  Namely, serial.device is NOT
well suited to use as a MIDI interface.

Older midi programs had this problem - I am told (I still use a //e
for MIDI) that the newer software does not suffer from this.  Nonetheless,
I for one would prefer a more general (and easier [for the application
programmers]) solution, since I suspect much tweaking went into getting
the programs to work.

I experienced the problem early on when I first hooked up a MIDI cable
to the Amiga and wrote some code to drive it.  Stated basically, the
problem is that the serial device does not time stamp the incomming
data, and since the Amiga multitasks, by the time the program gets the
code, the time 'may' be wrong since another task 'may' have run in
between.  Note that by disabling other tasks the problem vanishes (but
then you can't multitask with the program).  The other problem is that
the serial device outputs the data as soon as it gets it - which may
not be when the program sent it, thus messing up the outgoing timing.
The same semi-solution applies.  To get real-time preformance in this
type of enviorment, the solution as traditionally been to put the nasty
timing stuff in the driver.  BUT, we can't really expect the serial
device to handle time stamping since that is not necessary for normal
serial applications.

****** Warning - Long Winded Suggested Solution Ahead ******

The Solution: Make a new device: midi.device.

Requirements:
-------------

1) Ability to grab EVERY byte as it comes in to at least 33000 baud
   (3300 bytes/sec).
2) Ability to know WHEN the byte came in (so we can calculate the
   durations between note on and note off, etc ...)
3) Ability to send out bytes at precise points in time (at least to
   a good enough resolution to fool the ear)


Current Implementation method:
------------------------------

Below, see a diagram of typical current recording method (some methods
are highly ingeneous to minimize the problems discussed, but this is the
basic problem).

  Read a byte    <-----------------
  ask timer.device for the time   |
  record note and time  -----------

The problem with this is that the time is NOT accurate since after the
byte has been read by the serial device, the task doing this may be
interrupted.  Also, although the serial device can read ALL the bytes,
the task may not (in the short run, due to other tasks), be able to
keep up with the bytes coming in, so that if the byte came and was
buffered up by the serial device, the task might not read it for another
2 seconds, and then, even if the time it got was accurate, there is still
a 2 second error in the timing.  These problems are CLEARLY audible.


A Solution:
-----------

We need to do the time-stamping in the driver (where interupts are
impossible and we will be accurate to AT LEAST 1/3300 0.3 ms.  This
lets us record accurately.  Output should be double buffered and
under control of the driver as well.  The sequence to use the system
might go something like this:

open midi.device (default everthing to MIDI parameters)
while (record)
  read_midi_value, place in buffer
clear time value on 1st MIDI code/time element to 0
to playback:
write_midi(1st 1024 MIDI code/time data elements in buffer)
while (playback)
  write_midi(next 1024 MIDI code/time data elements in buffer)
write_midi(last partial data (< 1024))

data format:
[MIDI code][time since last code was read]

Driver Requirements:
new global: miditime last_time;   /* actual time of last code received */

open:
same as current driver, but make all values default to those MIDI uses
(as described in the RKM).  Therefore, setparms won't be used

input:
when a byte is received, place it in the buffer (as is currently done).
also add to the buffer the elapsed time since the last byte was received.
this is why we need a new global (or at least a static).  Thus, now each
input value is represented by 2 values, the actual code and a time-stamp.

output:
output MUST be buffered, since the task feeding us with values may be
interupted at any time (and the music would hang until it became active
again).  The simplest solution is to write the values in blocks.  Then
the driver may output them 1 at a time until the buffer is exhausted.  The
problem with this alone is that the task feeding us may not be active at the
exact instant we (the driver) need more values.  For this reason, I
suggest double buffering.  Thus, while 1 buffer is being output, the task
feeding us has the length of the 1st buffer to write a second.  When the
second buffer is being output, the task has that long to write the 1st
buffer.  To prevent the task from overflowing our buffers (writing
a buffer we are not done with), the writes can be forced to a syncronous
mode (thus if the task trys to write a 3rd buffer [overwrite the 1st], the
request will not return [will hang the task] until space is available).  This
also means we need a new (or modified status command, to see if a previous
write completed).
  schedule flow:  (driven by user requests)
    wiat for a write request to come in.
    buffer available ?
      no  - convert request to syncronous (so continue when buffer is free)
      yes - continue
    repeat

  use flow:  (sub-function of schedule flow)
    Is buffer N ready to be output? (N == 0 or 1)
      no  - wait
      yes - continue
    output buffer
    N = !N;
    repeat
    
  output flow:   (driven by data output rate)
    get next code/time stamp element
    wait time stamp amout of time
      do this by schedualing an interupt using a CIA timer (I think this is
         what the serial device uses it for now anyway - to regulate output
         baud rate).
    output the code
    if end-of-buffer, switch buffers
    repeat.

loop:
NEW command, tells driver to copy any incoming byte directly to the
output (since the task can't do this in real time, any many MIDI
programs have this feature, we might as well provide it).

Questions/problems to solve.  
What form should the timer values take - If the TOD (time of day) clock
is accurate enough (.3 ms resolution or better), this is the ideal solution,
since the MIDI codes are 8 bit and the TOD clock is 24 bits (and can be
read directly off of a chip register), 1 32 bit word (long) can represent
each value.  Is 32 bits a waste of space for this maybe?  At .3 ms per
bit, 8 bits only gives us 78 ms max delay time - clearly inadequate, and
16 bits gives us 20 seconds - good, but NOT good enough unless we want to
add a special code that the driver will not send out (to allow LONGER)
delays - also the receive part of the driver would have to padd with these.
Not elegant.  24 bits gives us 85 hrs between events - plenty.  Ok, so
we need 32 bits to represent each code.  Can we use the TOD register value
to provide this?  I don't know, I will have to find out the resolution
of this clock (do you know what it is?)  If it is not good enough, we
will have to generate a synthetic time value based on the 8 bit serial
timer and the TOD (not tough, but not as clean).

=============================================

Well, that's it ... anybody have something to do the trick?  This is
#3 on my hit list, so don't hold your breath waiting from my version.

                                      - Rob Ginn
                                        eraps1@nadc.arpa
                                        ...burdvax!jtids!aspvax!eraps2


"We want information ... information"       Rob Ginn 
                              - No. 2       ...burdvax!jtids!aspvax!eraps2
                                            eraps1@nadc.arpa

peter@sugar.UUCP (09/14/87)

I'm not a musician... these suggestions are purely from a software design
standpoint and exposure to MIDI people (wow, what's that 5-pin jack in your
neck for? :->).

In article <15740@aspvax.UUCP>, eraps2@aspvax.UUCP writes:
> [MIDI.DEVICE]
>
> 1) Ability to grab EVERY byte as it comes in to at least 33000 baud
>    (3300 bytes/sec).
> 2) Ability to know WHEN the byte came in (so we can calculate the
>    durations between note on and note off, etc ...)

  I would suggest softening this requirement to know when the first byte of
any MIDI packet comes in. This would require that the midi.device operate in
terms of midi packets, but that's a good idea anyway.

> 3) Ability to send out bytes at precise points in time (at least to
>    a good enough resolution to fool the ear)

  Again, make this "Ability to send out MIDI packets at precise points in
time".

> open midi.device (default everthing to MIDI parameters)

  In the open, specify what MIDI device number you want to be in the device
field, that way you can have a number of midi programs running simultaneously
without interfering with each other. You also want to echo midi messages from
one program to all the other programs (sounds like SoundScape, don't it?).

> while (record)
>   read_midi_value, place in buffer

  Read midi packets...

> clear time value on 1st MIDI code/time element to 0
> to playback:
> write_midi(1st 1024 MIDI code/time data elements in buffer)

  Write midi packets...

> while (playback)
>   write_midi(next 1024 MIDI code/time data elements in buffer)
> write_midi(last partial data (< 1024))
> 
> data format:
> [MIDI code][time since last code was read]

  [MIDI packet][wallclock time packet arrived]

> Driver Requirements:
> new global: miditime last_time;   /* actual time of last code received */
> 
> open:
> same as current driver, but make all values default to those MIDI uses
> (as described in the RKM).  Therefore, setparms won't be used

  Use "unit number" in open to specify MIDI device number.

> input:
> when a byte is received, place it in the buffer (as is currently done).
> also add to the buffer the elapsed time since the last byte was received.
> this is why we need a new global (or at least a static).  Thus, now each
> input value is represented by 2 values, the actual code and a time-stamp.

  Whan a byte is received, buffer it up. When a MIDI packet is recieved,
place it in the buffer or send it to the task, depending on the settings of
timeout and buffer size. If a packet is interrupted by a higher priority
packet (I don't remember whet these are called... system exclusive?), stack
the first packet and accumulate (and pass on) the new one first. Then when
it finishes unstack and finish gathering the old one.

When the first byte of a MIDI packet is received, timestamp the packet.

> output:
> output MUST be buffered, since the task feeding us with values may be
> interupted at any time (and the music would hang until it became active
> again).  The simplest solution is to write the values in blocks.  Then
> the driver may output them 1 at a time until the buffer is exhausted.  The
> problem with this alone is that the task feeding us may not be active at the
> exact instant we (the driver) need more values.  For this reason, I
> suggest double buffering.  Thus, while 1 buffer is being output, the task
> feeding us has the length of the 1st buffer to write a second.  When the
> second buffer is being output, the task has that long to write the 1st
> buffer.  To prevent the task from overflowing our buffers (writing
> a buffer we are not done with), the writes can be forced to a syncronous
> mode (thus if the task trys to write a 3rd buffer [overwrite the 1st], the
> request will not return [will hang the task] until space is available).  This
> also means we need a new (or modified status command, to see if a previous
> write completed).

It would be preferable to queue the packets being written up. That way, the
task can be writing packets until the buffer fills (make it, like, 2K long).
This would give you all the advantages of your method, but a lot more
versatility.

>   schedule flow:  (driven by user requests)
>     wiat for a write request to come in.
      room in the buffer?
	no  - go to sleep until there is.
	yes - put the request in the buffer. Signal something to send.
>     repeat
> 
>   output flow:   (driven by data output rate)
      wait for transmitter ready.
      anything to send?
	no  - go to sleep until there is.
	yes -
	      get next packet.
	      if the packet has a non-zero timestamp
	        wait until packet timestamp >= wallclock time.
	      output the packet.
	      signal room in the buffer.
      repeat
> 
> loop:
> NEW command, tells driver to copy any incoming byte directly to the
> output (since the task can't do this in real time, any many MIDI
> programs have this feature, we might as well provide it).

  It could do this for any device numbers that don't match open units in
the midi.device as well.

> Questions/problems to solve.  
> What form should the timer values take [... is 32 bits too big?]

Not if you timestamp MIDI packets instead of bytes. You really only care
about the time the first byte got in anyway.
-- 
-- Peter da Silva `-_-' ...!hoptoad!academ!uhnix1!sugar!peter
--                 'U`      ^^^^^^^^^^^^^^ Not seismo!soma (blush)

ronhill@pnet01.CTS.COM (Ronald Hill) (09/16/87)

Does the Midi Device floating around the boards handle all of the problems you
mentioned? 


UUCP: {cbosgd, hplabs!hp-sdd, sdcsvax, nosc}!crash!pnet01!ronhill
ARPA: crash!pnet01!ronhill@nosc.mil
INET: ronhill@pnet01.CTS.COM

jwabik@shamash.cdc.com (Jeff Wabik) (12/30/88)

Forgive me if this topic has come up recently...  With the traffic here
these days, I haven't been able to keep up with it all and still keep 
my sanity, and (what's left of my) sanity won out..  Anyhow ..

One of the toys I got for Christmas was a nice Casio (musical) keyboard,
with 7 billion sounds and nice ports on the back marked "MIDI IN", and
"MIDI OUT".  I know what MIDI is and what its supposed to do, but I know
nothing about MIDI specifics on the Amiga..  Specificially:

	1) What types of interface boxes are out there, what are the
	   differences, and which is best.  Are there interfaces that
	   attach to the Amiga by other than the Serial port?  Are
	   those 5-pin DIN looking cables as innocent (pin 1 to pin
	   1,...,pin 5 to pin 5) as they look?

	2) What software is cool?  I've heard Deluxe Music Construction
	   Set is funky.  I saw the MIDI software flow thru .binaries.
	   last week, but haven't played yet ..  I'd like to be able 
	   to "program" a complicated score (like 4 voices, or more) 
	   from the (musical) keyboard, then play back on either Amy
	   or the Casio .. 

	3) Why invented liquid soap and why?

Basically, I know nothing about this stuff so any other information
would be great, too..

Thanks!

	-Jeff

--
Jeff A. Wabik   INTERNET: jwabik@shamash.cdc.com    AT&T: +1 612 853 6811
  ____  ____    UUCP:     jwabik@shamash.UUCP       FAX:  +1 612 853 4789
 / ___||___ \   
| |___  ___| |  Control Data Corporation - We're not a computer company ..
 \____||____/      				but we play one on TV .. 

      "I want something with reclining leather seats that goes 
		      really fast, and gets really shitty gas mileage .. "

mrr@amanpt1.zone1.com (Mark Rinfret) (01/05/89)

In article <10294@shamash.cdc.com>, jwabik@shamash.cdc.com (Jeff Wabik) writes:
> Forgive me if this topic has come up recently...  
> 
> 	1) What types of interface boxes are out there, what are the
> 	   differences, and which is best.  Are there interfaces that

There is a wide range of products available, ranging in price from $40-$100.
The primary differences appear to be the number of MIDI ports available
(In, Out, Thru, Sync, etc.).
> 	   attach to the Amiga by other than the Serial port?  Are
Nope.
> 	   those 5-pin DIN looking cables as innocent (pin 1 to pin
> 	   1,...,pin 5 to pin 5) as they look?
Yup.
> 
> 	2) What software is cool?  I've heard Deluxe Music Construction
> 	   Set is funky.  I saw the MIDI software flow thru .binaries.

DMCS is a nice scoring package, but its MIDI user interface stinks. I can
provide details if you want.  DMCS is the only scoring package I use since
I haven't seen anything better.  

Open question to other net.readers: 
Are there any good _configurable_ patch editors out there?  I have a Casio
CZ-1 (superset of the the CZ-101, CZ-1000, CZ-3000 family) which is not
supported in any commercially available software.  If I can buy a truly
configurable patch editor (editable sysex codes, etc.) I won't have to 
finish writing mine :-).

> 	   last week, but haven't played yet ..  I'd like to be able 
> 	   to "program" a complicated score (like 4 voices, or more) 
> 	   from the (musical) keyboard, then play back on either Amy
> 	   or the Casio .. 

Forget DMCS on this one.  I'm not aware of a good alternative, though.
As I understand it, you can record "tracks" of information with several
of the sequencer products available (see below), but none of them provide
a scoring interface.
> 
> 	3) Why invented liquid soap and why?

Don't you mean "Why invented soap and who?" :-) :-).
(I'm sure glad this wasn't Pete Da Silva's message. HIS typos are his
OWN damned business! :-) )

> Basically, I know nothing about this stuff so any other information
> would be great, too..

I haven't ventured into the "sequencer" area yet.  Sequencers let you take
"tracks" of pre-recorded MIDI information and edit it, cutting and pasting
song segments much as you would edit a text document.  I think you'd have
to devote just about all of your free time to MIDI music in order to benefit
from this level of effort.

Get yourself some back issues of AmigaWorld and Amazing Computing.  There
are ads, product reviews, etc. for lots of this stuff.  MIDI on the Amiga
is great fun for me.  Keep us posted on your progress.  E-mail me if you
want to chat some more.
> 
> Thanks!
> 
> 	-Jeff

	Sure!
		Mark

-- 
< Mark R. Rinfret,  mrr@amanpt1.ZONE1.COM | ...rayssd!galaxia!amanpt1!mrr    >
< HyperView Systems Corp.               Home: 401-846-7639                   >
< 28 Jacome Way                         Work: 401-849-9390 x301              >
< Middletown, RI 02840                  Hypermedia R Us!                     >

scotty@ziggy.UUCP (Scott Drysdale) (01/07/89)

In article <540@amanpt1.zone1.com> mrr@amanpt1.zone1.com (Mark Rinfret) writes:
>In article <10294@shamash.cdc.com>, jwabik@shamash.cdc.com (Jeff Wabik) writes:
>> 	2) What software is cool?  I've heard Deluxe Music Construction
>> 	   Set is funky.  I saw the MIDI software flow thru .binaries.
>
>DMCS is a nice scoring package, but its MIDI user interface stinks. I can
>provide details if you want.  DMCS is the only scoring package I use since
>I haven't seen anything better.  

DMCS does have a few bugs, most of which can be worked around.  all is not
lost - read on.

>
>Open question to other net.readers: 
>Are there any good _configurable_ patch editors out there?  I have a Casio
>CZ-1 (superset of the the CZ-101, CZ-1000, CZ-3000 family) which is not
>supported in any commercially available software.  If I can buy a truly
>configurable patch editor (editable sysex codes, etc.) I won't have to 
>finish writing mine :-).
>
>> 	   last week, but haven't played yet ..  I'd like to be able 
>> 	   to "program" a complicated score (like 4 voices, or more) 
>> 	   from the (musical) keyboard, then play back on either Amy
>> 	   or the Casio .. 
>
>Forget DMCS on this one.  I'm not aware of a good alternative, though.
>As I understand it, you can record "tracks" of information with several
>of the sequencer products available (see below), but none of them provide
>a scoring interface.

try the DMCS-SoundScape combination.  soundscape is a "midi studio" type
program which allows you to route various midi sources around to
destinations and perform lots of operations on the midi stream.  with
DMCS and soundscape present in the system, DMCS will start up soundscape
and appear as a midi source in the soundscape patch panel.  from there, 
you can have dmcs play your score into soundscape's midi recorder and then
edit the midi data and add events DMCS can't.  you can also use a utility
which comes with soundscape to convert recorded midi data to DMCS scores,
with control over quantization of midi event duration to note length.  of
course, some stuff is lost in the translation, but it's probably easier than
trying to write things down while fooling around at the keyboard.  soundscape
also allows you to write your own source/destination modules in C and
will install them in the patch panel so they can be used like any other
soundscape source/dest.  this is useful for doing things like reserving a
section of your keyboard for switching patches in a synth by converting the
reserved keys to different midi events.  i wrote a module which allows the
keyboard to be split at as many arbitrary places as you like and allows the
split regions to be sent to one or more different midi channels.
soundscape is relatively easy to use (i got it recording/playing back without
reading the manual).  it will work with just about any midi interface for
the amiga that plugs into the serial port (i built one out of about $15 worth
of common parts).  it seems to be pretty much bug free, too.  check it out.

  --Scotty