From alsa-devel-owner@alsa.jcu.cz  Thu Apr 30 19:58:45 1998
Received: from altrade.nijmegen.inter.nl.net (altrade.nijmegen.inter.nl.net [193.67.237.6])
	by marvin.jcu.cz (8.8.8/8.8.8) with ESMTP id TAA17403
	for <alsa-devel@jcu.cz>; Thu, 30 Apr 1998 19:58:37 +0200
Received: from obelix.fvdpol.inter.nl.net by altrade.nijmegen.inter.nl.net
	via bd99-15.Breda.NL.net [193.79.246.240] with ESMTP
	id TAA23074 (8.8.8/3.27); Thu, 30 Apr 1998 19:45:15 +0200 (MET DST)
Received: (from frank@localhost) by obelix.fvdpol.inter.nl.net (8.8.7/8.7.3) id SAA14889; Thu, 30 Apr 1998 18:05:24 +0200
From: Frank van de Pol <F.K.W.van.de.Pol@inter.nl.net>
Message-Id: <199804301605.SAA14889@obelix.fvdpol.inter.nl.net>
Subject: Re: New Sequencer core
To: alsa-devel@jcu.cz
Date: Thu, 30 Apr 1998 18:05:24 +0200 (MET DST)
Cc: P.J.Leonard@bath.ac.uk (Paul Leonard)
In-Reply-To: <3546E73A.493F@bath.ac.uk> from "P.J.Leonard" at Apr 29, 98 09:39:22 am
Content-Type: text
Reply-To: alsa-devel@alsa.jcu.cz
Sender: alsa-devel-owner@alsa.jcu.cz
Precedence: list

P.J.Leonard wrote:
> 
>  Some comments.

Thanks! All input is welcome.

I'll put my (new/changed/polished) ideas next to your comments. Perhaps
later I'll beef up a version 0.02 of the proposal :-).


> 
> > Ascii graphic of architecture:
> > 
> >   =========================
> >   ||                     ||
> >   ||                    \||/                 \
> >   ||  +--------+      +--\/------------+      |
> >   ||  |        |      |                |      |
> >   ||  | Timing | -->- | Priority Queue |      |
> >   ||  |        |      |                |      |
> >   ||  +--------+      +--------||------+      |
> >   ||                           ||             \ Sequencer
> >   ||                          \||/            /   Core
> >   ||  +--------+  +------------\/--------+    |
> >   ||  | Client |  |                      |    |
> >   /\  | Manager|  |     Event Router     |    |
> >  /||\ |        |  |                      |    |
> >   ||  +--------+  +---||-----------||----+    |
> >   ||                 \||/         \||/        /
> >   ||               +--\/--+     +--\/--+
> >   ||               |Client|     |Client|
> >   ||               |  1   | ... |  n   |
> >   ||               +--||--+     +--||--+
> >   ||                  ||           ||
> >   ||                 \||/         \||/
> >   ||                  \/           \/
> >   ===================================
> > 
> > 
> > All events flow through the queue. Because a priority queue is used instead
> > of a simple FIFO, it's no problem to accept events from multiple clients.
> 
>  I think we may need several schedulers to allow different clients to
> vary
> their tempos independently. 
> 
> - 2 users may want to use the system. I do not want my tempo to be
> changed by another. 

Good point.

The architecture was designed as a 'single user' system, like is common with
musical workstations (and other sequencer systems). In this single user
environment it's an advantage to have a single 'master' time/song position. 

If there's a need to allow multiple independent (with regarard to timing)
concurrent applications; this scheme can be expanded by adding a priority
queue and 'master clock' (the "Timing" block from above diagram) per 'user'.
The addressing of message will have to be extended with an additional field
that determines in which priority queue (or perhaps even queues???) an event
has to be put.

> 
> - Another situation is the mixing of tempo and real time events. A
> sequencer may be
> playing a midi tune using the tempo but special effects applied to an
> individual
> note may require to be scheduled 80ms after the note on event.
>

I also had some thoughts in this issue. When implementing a priority queue,
we need to be able to compare time stamps of events. If there is a constant
tempo, that can easily be done. But when a tempo is changed, the number of
clock ticks (ppq) per second changes, and events in the queue will not have
correct ordering anymore. To avoid this problem, only one type of timestamp
is needed. We have basicly two options to choose from:

1) real/clock-time, expressed in seconds (or fractions of it of course,
   eg. ms or us.

2) songposition, expressed in clock ticks, which are related to the tempo
  the song is playing. for an internal resolution of eg. 1920 PPQ (parts per
  quarter noter), and a tempo of 135 BPM, there are 1920*135=259200 clock ticks
  per minute = 4320 ticks per second. 


Because of the specific character of music (ie. it has tempo, groove etc.)
the second one is prefered. Conversion between these two types is trivial
once the currently active tempo and timestamp (in both units!) of last tempo
change is known.


> 
> 
> > Event Structure
> > ---------------
> > 
> > All the events have (apart) from their specific content a few common fields
> >         - timestamp (in midi ticks), like oss /dev/music
> >         - message type/id (eg. NOTE_ON, CHANGE_TEMPO,...)
> >         - destination, to which client(s) is the message to be send. An
> >           event can be send to either:
> >            a) a specific client, in this case the client number has to
> >               be given.
> >            b) all clients that have registered for this (class of) event
> >               this is basicly a broadcast.
> >           This destination also can have (for eg. note events) a port and
> >           channel.
> 
>  Maybe a handle for who sent the event might be required ?

Good idea, otherwise we can't discriminate between events from for example
two different MIDI keyboards (I'm sure want to!).


> 
> > Events a modeled after MIDI, but are not restricted to be MIDI events. Any
> > event that one can think of can be fed into the sequencer and dispatched at
> > the specified time to the specified device(s).
> 
>  MIDI events suck. MIDI should be a wrapper layer for those who have
> existing applications.

???? I'm not sure we are talking about the same MIDI. If 'your' MIDI is the
low-level MIDI protocol, with all those byte sequences, and only limited to
a few standard events I totally agree with you. But (perhaps I was not clear
enough) the type of events I was thinking of are modeled after MIDI in the
spirit of "Make sound with volume aaa, pitch bbb, on channel ccc of
intrument (port) ddd", and "Change parameter aaa to value bbb on channel ccc
of instrument dddd". MIDI is limited in may ways because it consists of
short packets of 7 bit values. We do not have that limit for specifying an
event. 

Because I had my own home studio (with Steinberg Cubase as sequencer, an XG
synth module, a Kawai K1 synth, a Novation BassStation synth and a Boss RV70
Reverb) in mind while composing my proposal, I know that even with the
restricted 'bare bones' MIDI standard it is possible to access all
parameters in my equipment (and there are much more parameters to fiddle
with than can be found on a GUS or AWE...). When dealing with MIDI equipment
there are a few commonly used ways to give access to the sound
characteristics (I'm sure you are familiar with these):


1) Program changes (only 0-127). To work around this restriction, synth
   vendors came up with two alternatives to enhance addressing: GS (Roland)
   and XG (Yamaha). Both standards use a controllor to select the bank the
   program will selected from.

2) Other channel messages eg. pitch bed, channel aftertouch, polyphonic
   aftertouch.

3) Control changes. (128 controllers, 7 bits). This is intended for real-time
   control of sound characteristics. Think of panning, volume, modulation,
   filter control: Frequency/Resonance (also known as 'Brightness' and 
   'Harmonic Content' etc. To extend the numer of available controllers and
   range of the value (to 14 bits) Non Registered and Registered Parameter
   Numbers are used (RPN/NRPN). XG Makes heavy use of NRPN.

4) System exclusive messages. Vendor/Synth specific. Used in almost all
   syntheseisers to allow access to every configurable or programmable bit.
   Allows even download of samples... These messages are mostly non portable
   and require 'computer programmer musicians' or special applications (synth
   editors, bank managers. 

I think because of the huge installed base of MIDI equipment that should be
the first target to aim at, and use the methods shown above. For the synths
that are not 'stand-alone boxes that are hooked up with MIDI cables' like
the ones that are integrated on soundcards (OPL3, GUS, AWE, ...) I think the
best approach is to let the outside world (ie. the sequencer applications)
see these devices as 'just another synth'. All the specials and extras,
including programming capability should be wrapped in the standard available
control messages. 

Advantages of this approach:

- From musicians's point of view an internal synth (eg. my GUS) doesn't look 
  different from an external unit (both have there specific messages to
  massage the sound).

- Common interface for application programmer.

- If the Linux system is only used as patchbay, with MIDI->Internal Synth
  routing, one can use an external sequencer and make fully use of the 
  internal unit. (Great PLUS, my GUS is basicly a neat sampler, but only
  usefull for playing MOD files... If I can drive it from Cubase on my
  other computer, I've just another synth. Same applies if one wants to hook
  up a MIDI keyboard, and want to play using internal sounds.
  

> However, the design of good generic interface for the different devices
> is still quite tricky.
> If I have written a piece of music for my AWE32 using some of it's cool
> filter sweeps 
> how will a GUS card play this ? One solution is to have adaptors e.g.

If it's a special AWE32 feature that itsn't supported by the GUS, it will
just play, but without the great effects. This same applies using 'normal'
syntheseisers. If a send data sequenced for my K1 to the XG module, it will
sound very different, and the XG lacks the great analog sound of the
BassStation, and my reverb has far more parameters than the reverb unit of
the XG synth etc. etc. etc. etc. 

Bottom line: I don't think we should make life more complicated than it is,
and just accept the differences between the devices (otherwise one would
only but 1 synth and that's it; the reason for excistence of many devices
are their own strength and weaknesses.)

To make life a little more easy, we can try to standardize the internal
synths to GM and perhaps extend it with some of the XG features.

> AWE32->GUS but this
> explodes as the number of devices increases. A generic device would need
> to know about main features
> of all cards. Then we can have AWE32->generic   generic->GUS

No. If you have a song composed for AWE32, it will only sound _exactly same_
on AWE32 and on nothing else (ehh, perhaps on a AWE33 or AWE64 of these are
enhanced versions of the former.) 

I think a AWE32 can be seen as: "generic + AWE32 specials". The GUS can be
seend as "generic + GUS specials". A standalone XG module (eg. Yamaha MU90R)
is "generic + MU90R specials". If a AWE32 specific song is played to another
device, eg. GUS, the latter will not understand the specials and just
discard the extra data; the generic events will be played though 

> The raw Awe32 will provide the neatest possible interface to all the
> features of the AWE32.

Of course. That's the whole idea. And this raw AWE32 interface can be
implemented as a generic set of commands, that is extended with some AWE32
specific. These who combined should give access to every bit in the AWE.

> If you are not concerned about portibility you can use this direct. If
> you are concerned
> about portility you should use the generic interface and an adaptor ?

This not an issue anymore if we use the 'generic + device specific' concept.
Only one interface is needed.


> 
> 
> > ------------------------------------------------
> > 
> > For some (historical?) reason OSS provides two different sequencer
> > interfaces, /dev/sequencer (the old one), and /dev/sequencer2, also known
> > as /dev/music. Is there a good reason why a new sequencer core also should
> > provide 2 interfaces? What's exactly the difference between these
> > interfaces. For backwards compatiblity I understand why these two should be
> > implemented, but is there any reason why the functionalty cannot be provided
> > by one (good) sequencer?
> 
> 
>  _I think_ /dev/music adds some voice/patch management for the OPL3 and
> GUS cards. Whem
> I asked I was was told that there was no point using /dev/music for the
> AWE32 interface.
> The AWE32 driver does it's own voice management. [ within the device the
> AWE32 there are 30
> sample players when the user wants to play a note something needs to be
> clever enough to allocate
> these sample players for the job ]  The /dev/sequencer GUS interface
> required the user to do this.

I got the same feeling, though I didn't know of the AWE32 voice allocations
in /dev/sequencer level. So for AWE32 there is little difference between the
two APIs.

> 
> > If the only real issue is that the old interface gives lower-level access to
> > a synth device, and such can't be achieved by a simple interface wrapper
> > (eg. access to every single voice in the GUS for playing MOD files), it
> > could be an idea to provide such synths with a CAP_LOWLEVEL_SYNTH, or
> > CAP_LOWLEVEL_AWE32 capability flag. (And perhaps a message to switch from
> > one mode to another.
> > 
> > Idea: If one wants to have access to individual voices, these can also be
> > addressed as a buch of midi channels (eg. 0..31), with each channel
> > representing a singe voices.
> 
>  With the AWE32 the voices are done in software, each time a note is
> played
> the pointers to the sample in memory and all the synth parameters are
> loaded into the device.
> I do not know how the GUS works.

The gus has a number of (up to 32) 'Sample players' that play data from the
on-board memory. There is also some LFO and volume envelope (using volume
ramping in hardware).

When looking from programmer's perspective directly to the card at chip level,
we see just (up to 32) 'single monophonic' voice generators. Every voice
generator has to be (and can be) independently programmed, making it ideal
for playback of MOD files, but a pain in the ass for MIDI playback because
it lacks dynamic voice allocation. This is how the GUS is used in the
/dev/sequencer interface.

The /dev/music tries to turn the GUS into a synth like device, with 16
channels, something special for drums (different sample per note), and up to
32 voices polyphonic, dynamicly allocated over the 16 channels. For MOD
players, there is no way to force the card to use a specific tone generator
for a specific 'track'.

Comparison both (OSS) interfaces for GUS:

                       /dev/sequencer       /dev/music
 +--------------------+------------------+---------------+
 | total voices       |   14-32          |    14-32      |
 |                    |                  |               |
 | total channels     |   14-32          |    16         |
 |                    |                  |               |
 | voice alloc hidden |   no             |   yes         |
 | from user          |                  |               |
 |                    |                  |               |
 | Drum channel       |   none           |   channel 10  |
 +--------------------+------------------+---------------+


Note that the total number of voices (14 up to 32) is determined by the mode
the card is programmed into, and directly affects the sample rate (gets
lower with more voices).

The /dev/sequencer is _the_ prefered interface for MOD player writers
because it gives them more channels. For the MIDI player writers the
/dev/music interface is (or should be) the prefered interface, because it
looks more like a normal MIDI device, and the sequencer does not have to do
GUS specific voice allocations. The sequencer can then be more generic.

I would love to end up with a sequencer core that has only ONE interface,
and can also be used for the MOD players and similar stuff. 

Perhaps it helps to make one single GUS driver, that just has more channels:

- total voices:    14-32 (yep, determined by the hardware...)
- total channels:  32, presented as a 'MIDI like' GUS synth with 2 ports 
                   of 16 channels each. (or provide more ports? don't think 
                   that's usefull.)
- voice alloc:     dynamic of the 32 channels.

If there is a need to, we can even add a parameter to set the minimum and
maximum number of voices to be allocated for a specific channel (like the
Partial Reserve feature offered by Roland Syntheseisers). Set the max. to 1
to get a monophonic channel, set it to 0 to essentially mute the channel.

The Drum/Percussive channel can default to 10 (GM compatible), but should be
user configurable. The user should be able to set it to any channel he or
she want, and even switch it off. Conforming GS/XG standards, multiple 
(eg. 3) drum maps can be provided.

For changing the voice allocation and drum parameters we can simple use
NRPNs or sysex!!!


Regards,
Frank.



> 
> -- 
>  Cheers Paul.                                        
>                __         __                  
>               (  ) _ - _ (  )                 
>                ~~         ~~                  
>                 (  0   0  )                   
> ----------ooO----(       )----Ooo------------ 
>           '''     (     )     '''             
>                    (   )                      
>                     \ /                       
>                    ~~O~~                      
> 
>   Tel: +44 1225 826108
>   Fax: +44 1225 826305
> snail: P.J.Leonard
>        Applied Electromagnetic Research Centre
>        Bath University,
>        BATH, UK   BA2 7AY
> ------
> To unsubscribe from <alsa-devel@alsa.jcu.cz> mailing list send message
> 'unsubscribe' in the body of message to <alsa-devel-request@alsa.jcu.cz>.
> 

========================---------------->
#define NAME    "Frank van de Pol"     
#define ADDRESS "mgr. Nelislaan 10"  
#define CITY    "4741 AB Hoeven"    
#define COUNTRY "The Netherlands"  
#define EMAIL   "F.K.W.van.de.Pol@inter.NL.net     -o)
                                                   /\\
Linux - Why use Windows, since there is a door?   _\_v

