From alsa-devel-owner@alsa.jcu.cz  Sun Feb 14 11:40:53 1999
Received: from galjas.cs.vu.nl (root@galjas.cs.vu.nl [130.37.24.13])
	by marvin.jcu.cz (8.9.1a/8.9.1) with ESMTP id LAA05239
	for <alsa-devel@alsa.jcu.cz>; Sun, 14 Feb 1999 11:39:19 +0100
Received: from localhost by galjas.cs.vu.nl with esmtp
	(Smail3.1.28.1 #49) id m10ByxJ-0006MyC; Sun, 14 Feb 99 11:39 +0100
Date: Sun, 14 Feb 1999 11:39:17 +0100 (MET)
From: Andy Lo A Foe <arloafoe@cs.vu.nl>
To: alsa-devel@alsa.jcu.cz
Subject: Re: Mixing
In-Reply-To: <Pine.LNX.4.05.9902140125140.3906-100000@screech.cs.alfred.edu>
Message-ID: <Pine.GSO.4.05.9902141043010.5996-100000@galjas.cs.vu.nl>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Reply-To: alsa-devel@alsa.jcu.cz
Sender: alsa-devel-owner@alsa.jcu.cz
Precedence: list

On Sun, 14 Feb 1999, Christopher T. Lansdown wrote:

> 	I'm in the process of writing a music library, targeted at games.
> On of it's functions will be mixing different sounds (PCM streams).  What
> is the right way to mix PCM streams?  Adding the samples, averaging them,
> or something else?  Assume identicle sample rate and stereo.

The methode I use is to add the samples and then clip if needed:

int32 result;

int16 stream1;	// 16 bit sample
int16 stream2;

result = stream1 + stream2;

if (result > 32767) result = 32767;
else
if (result < -32768) result = -32768;

This works quite well for low stream counts, but I'm sure there is a
better and more high quality ways of doing this, probably floating
point based. Anyone?

> 	Also, if there is more than one way, what way produces the best
> quality sound?  What's the fastest method that produces acceptable
> results?  Thank you very much.

Last night I rewrote much of the ALSA classes for AlsaPlayer. It now
works very much like the BeOS audio system. I choose the older version of
DAC/ADC and Subscribers since I understand that better and it's all you 
need for stream mixing. Basically you have 2 types of ALSA Interface
objects, AlsaDAC and AlsaADC (not implemented yet). These objects talk
to the soundcard in their own threads. You also have Subscribers
(AlsaSubscriber). Subscribers are the interface to your program. A
Subscriber can be subscribed to either an AlsaDAC or AlsaADC. Once you
are subscribed you will get a chance to read/modify every buffer that's
send or received to/from the DAC/ADC. There can be multiple Subscribers
per AlsaDAC or AlsaADC object (placed in random order for now) so you can
in effect mix multiple PCM streams to the DAC (each Subscribers has do to
its own mixing for now, i.e. add/clip to the buffers). Here is a little
code as an expample:

---

AlsaDAC *dac = new AlsaDAC(0); // Attach to the DAC on first card
			       // could be extended to handle multiple
			       // DACs per card

AlsaSubscriber *sub = new AlsaSubscriber(); // No arguments for now

dac->SetStreamBuffers(128, 4); // Low latency 128 byte fragments, 4 max
			       // With these numbers you better have this
                               // process scheduled as "real-time"
			       // Smaller frag size increases machine load!

dac->SetSamplingRate(44100);	// Set the rate of the hardware DAC
				// It defaults to 16 bit, stereo, 44Khz

sub->Subscribe(dac);	// Attach sub to the DAC

sub->EnterStream(streamer_function, some_arg); // Start processing
			// If this is the first subscriber to enter
			// the stream it will spawn a thread wich will
			// start feedings the DAC in a loop
			// (which nicely blocks on snd_pcm_write)
----

streamer_function should look like:

bool streamer_function(void *arg, void *buffer, int buffer_size)
{
	// This function gets called for every fragment 
	// - arg is the some_arg you gave to EnterStream()
	// - buffer a pointer to the buffer you can read/write
	// - buffer_size is the length of the buffer (frag_size)

	// Do some crazy stuff with the fragment like mixing
	// your own PCM data in or writing its contents to
	// disk...
	
	return true; // Everything ok so return true.If we return
		     // false this subscriber will be removed from 
		     // the loop
}

----

I'll package up the AlsaDAC and AlsaSubscriber code and put it on
the FTP site later today (yes, its all C++ :( )
These classes are not really tested (only a few hours old) but so
far the results are very promising, rivaling basic BeOS audio even ;-))

Andy
--
Andy Lo A Foe, arloafoe@cs.vu.nl |   Linux v2.2.1   | PII 266 
http://www.cs.vu.nl/~arloafoe    |    ALSA 0.3.0    | Bebox 133
http://orbital.xs4all.nl/andy    |  IRCNet: adnans  | DVD freak


