# vim:set noet ts=8 sw=2:
# Updated 070515 notes {at} notes.for.sabi.co.UK

# Copyright (C) 2007 PeterG. This program is free software: you
# can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software
# Foundation, either version 2 of the License, or (at your
# option) any later version. This program is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.

# Syntax (somewhat) described in these links:
#   http://ALSA-project.org/alsa-doc/alsa-lib/conf.html
#   http://ALSA-project.org/alsa-doc/alsa-lib/confarg.html
#   http://ALSA-project.org/alsa-doc/alsa-lib/conffunc.html 
#   http://ALSA-project.org/alsa-doc/alsa-lib/confhooks.html

# In this file I use a style similar to the one I use for CSS style sheets.

# It may also help to read:
#   http://WWW.sabi.co.UK/Notes/linuxSoundALSA.html

# Also check carefully the contents of '/usr/share/alsa/alsa.conf',
# especially for the one liners defining standard device names
# and attributess, or the output of 'arecord -L' or 'aplay -L'.
 
# The device names "default", "dsp0", "mixer0" have special meanings.

# Standard channel number assignments:

#   0 front left	1 front right,
#   2 rear left		3 rear right
#   4 center		5 lfe/subwoofer
#   6 side left		7 side right

########################################################################

# Read very carefully the ALSA PCM plugin page at:
#   http://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html

# For the 'asym', 'dsnoop', 'dmix' plugins also read:
#   http://ALSA.OpenSrc.org/index.php?page=asym
#   http://ALSA.OpenSrc.org/index.php?page=dsnoop
#   http://ALSA.OpenSrc.org/index.php?page=DmixPlugin

pcm.c20
{
	@args [ CARD ]
	@args.CARD	{ type string; default "0"; }

	type		hw;
	card		$CARD;
}

pcm.c40			= pcm.surround40;
pcm.c51			= pcm.surround51;

pcm.dsp
{
	@args [ SNOOP MIX ]
	@args.SNOOP	{ type string; }
	@args.MIX	{ type string; }

	type		asym;

	capture.pcm	$SNOOP;
	playback.pcm	$MIX;
}

pcm.rec
{
	@args [ KEY SLAVE ]
	@args.KEY	{ type integer; }
	@args.SLAVE	{ type string; }

	type		dsnoop;
	ipc_key		$KEY;

	slave.pcm	$SLAVE;
}

pcm.iec
{
	@args [ SLAVE ]
	@args.SLAVE	{ type string; }

	type		iec958;

	slave.pcm	$SLAVE;
}

# For Tribes 2, which has the channels reversed.
#   http://home.Erin.UToronto.CA/~jbonham/tribes2-alsa.html

pcm.swap
{
	@args [ SLAVE ]
	@args.SLAVE	{ type string; }

	type		route;
	slave.pcm	$SLAVE;

	ttable.0.1	1;
	ttable.1.0	1;
}

# Buffering (period time defaults to 125000 usecs).

# Size of period, expressed either in usec or byte units:
#   period_time USECS
#   period_size BYTES

# Size of buffers, expressed either in period, usec, or byte units:
#   periods	PERIODS
#   buffer_time USECS
#   buffer_size BYTES

# The ALSA docs have examples with 'period_time' set to 0, when
# 'period_size' and 'buffer_size' are used instead, but this can
# cause trouble in later releases of ALSA.

# For OSS compatibility, 'period_size' and 'buffer_size' should
# be powers of 2. Also, many cards cannot accept a 'period_size'
# much greater than 4096, so 4096 is mostly safe. Some like the
# nForce 8x0 compatibles require a smaller one still.

# On my VIA 8233A, any value for 'period_time' greater than
# 85333 usecs (precisely!) causes hiccups in sound output.
# Why? At 48kHz, 85333 usec are just over 4096 bytes/channel.

pcm_slave.dmix-slave
{
	@args [ CHAN PCM RATE PSIZE BSIZE PTIME BTIME ]
	@args.CHAN	{ type integer; }
	@args.PCM	{ type string; }
	@args.RATE	{ type integer; default 48000; }
	@args.PSIZE	{ type integer; default 4096; }
	@args.BSIZE	{ type integer; default 40960; }
	@args.PTIME	{ type integer; default 84000; }
	@args.BTIME	{ type integer; default 840000; }

	pcm		$PCM;
	rate		$RATE;

	period_time	$PTIME;
	buffer_time	$BTIME;

	period_size	$PSIZE;
	buffer_size	$BSIZE;

	channels	$CHAN;
}

#						2/4/6 CHANNEL SW SHARING
#						########################

pcm.dmix-20
{
	@args [ KEY PCM RATE PSIZE BSIZE PTIME BTIME ]
	@args.KEY	{ type integer; }
	@args.PCM	{ type string; }
	@args.RATE	{ type integer; default 48000; }
	@args.PSIZE	{ type integer; default 4096; }
	@args.BSIZE	{ type integer; default 40960; }
	@args.PTIME	{ type integer; default 84000; }
	@args.BTIME	{ type integer; default 840000; }

	type		dmix;
	ipc_key		$KEY;

#	slave		{ @func concat
#			    strings [ "dmix-slave:2," $PCM "," $RATE ","
#			      $PSIZE "," $BSIZE "," $PTIME "," $BTIME ] };

	slave
	{
#	  @func concat strings [ "dmix-slave:2," $PCM "," $RATE ","
#				  $PSIZE "," $BSIZE "," $PTIME "," $BTIME ] };
	  channels	2;
	  pcm		$PCM;	rate		$RATE;
	  period_time	$PTIME;	buffer_time	$BTIME;
	  period_size	$PSIZE;	buffer_size	$BSIZE;
	}

	bindings.0	0;
	bindings.1	1;
}

pcm.dmix-40
{
	@args [ KEY PCM RATE PSIZE BSIZE PTIME BTIME ]
	@args.KEY	{ type integer; }
	@args.PCM	{ type string; }
	@args.RATE	{ type integer; default 48000; }
	@args.PSIZE	{ type integer; default 4096; }
	@args.BSIZE	{ type integer; default 40960; }
	@args.PTIME	{ type integer; default 84000; }
	@args.BTIME	{ type integer; default 840000; }

	type		dmix;
	ipc_key		$KEY;

	slave
	{
#	  @func concat strings [ "dmix-slave:4," $PCM "," $RATE ","
#				  $PSIZE "," $BSIZE "," $PTIME "," $BTIME ] };
	  channels	4;
	  pcm		$PCM;	rate		$RATE;
	  period_time	$PTIME;	buffer_time	$BTIME;
	  period_size	$PSIZE;	buffer_size	$BSIZE;

	}

	bindings.0	0;
	bindings.1	1;
	bindings.2	2;
	bindings.3	3;
}

pcm.dmix-51
{
	@args [ KEY PCM RATE PSIZE BSIZE PTIME BTIME ]
	@args.KEY	{ type integer; }
	@args.PCM	{ type string; }
	@args.RATE	{ type integer; default 48000; }
	@args.PSIZE	{ type integer; default 4096; }
	@args.BSIZE	{ type integer; default 40960; }
	@args.PTIME	{ type integer; default 84000; }
	@args.BTIME	{ type integer; default 840000; }

	type		dmix;
	ipc_key		$KEY;

	slave
	{
#	  @func concat strings [ "dmix-slave:6," $PCM "," $RATE ","
#				  $PSIZE "," $BSIZE "," $PTIME "," $BTIME ] };
	  channels	6;
	  pcm		$PCM;	rate		$RATE;
	  period_time	$PTIME;	buffer_time	$BTIME;
	  period_size	$PSIZE;	buffer_size	$BSIZE;
	}

	bindings.0	0;
	bindings.1	1;
	bindings.2	2;
	bindings.3	3;
	bindings.4	4;
	bindings.5	5;
}

#							4/6 CHANNEL AS STEREO
#							#####################

# Distribute 2 channel stereo to 4 or 5.1 surround channels
# 'surround40' and 'surround51' should be predefined.
#   http://ALSA.OpenSrc.org/index.php?page=FAQ028
#   http://ALSA.OpenSrc.org/index.php?page=SurroundSound

# 'table.X.Y Z' means add channel 'X' multiplied by 'Z' to 'Y'.

# Does not support sharing, stack 'dmix' for that.

# Note that all (some?) USB sound device config do not define the
# 'surroundXY' style name, so substitute the equivalent 'hw' name.

pcm.stereo-40
{
	@args [ PCM ]
	@args.PCM	{ type string; }

	type		route;

	slave.pcm	$PCM;
	slave.channels	4;

	ttable.0.0	1.0;
	ttable.0.2	0.6;

	ttable.1.1	1.0;
	ttable.1.3	0.6;
}

pcm.stereo-51
{
	@args [ PCM ]
	@args.PCM	{ type string; }

	type		route;

	slave.pcm	$PCM;
	slave.channels	6;

	ttable.0.0	1.0;
	ttable.0.2	0.6;
	ttable.0.4	0.3;
	ttable.0.5	0.3;

	ttable.1.1	1.0;
	ttable.1.3	0.6;
	ttable.1.4	0.3;
	ttable.1.5	0.3;
}

#							4 CHANNEL AS 2 STEREO
#							#####################

# Using one four channel card as two stereo cards.
#   http://ALSA.OpenSrc.org/index.php?page=.asoundrc

# Note that all (some?) USB sound device config do not define the
# 'surroundXY' style name, so substitute the equivalent 'hw' name.


pcm.card-f
{
	@args [ PCM ]
	@args.PCM	{ type string; }

	type		route;

	slave.pcm	$PCM;
	slave.channels	2;

	ttable.0.0	1.0;
	ttable.1.1	1.0;
}

# Note that all (some?) USB sound device config do not define the
# 'surroundXY' style name, so substitute the equivalent 'hw' name.

pcm.card-r
{
	@args [ PCM ]
	@args.PCM	{ type string; }

	type		route;
	slave.pcm	$PCM;
	slave.channels	4;

	ttable.0.2	1.0;
	ttable.1.3	1.0;
}

pcm.card-s
{
	@args [ PCM ]
	@args.PCM	{ type string; }

	type		route;

	slave.pcm	$PCM;
	slave.channels	8;

	ttable.0.6	1.0;
	ttable.1.7	1.0;
}

########################################################################

# The top level shared pseudo device, with both PCM and CTL interfaces
# The ALSA default is "default", but many programs like XMMS and 'aoss'
# assume "dsp0" as default name for PCM and "mixer0" for CTL.

# Amazingly, XMMS has problems if one defines 'pcm.dsp0' to be
# 'plug' for 'pcm.asym0' and not directly as 'asym'.

ctl.!default		= ctl.dsp0;
pcm.!default		= pcm.dsp0;

########################################################################

# The two detailed card configurations are for generic 2 to 5.1 channel
# chipsets. It is assumed that both cards need software sharing, and can
# only natively handle 48000Hz.

# These assumptions are fairly typical of recent (2004) low end and
# on-motherboard cards and chipsets, and their configs are not really
# specific to either models.

########################################################################

ctl.dmixer { type hw; card 0 }
pcm.dmixer {
  type dmix
  ipc_key 1024
  slave {
    pcm "hw:0,0"
    period_time 0
    period_size 1024
    buffer_size 4096
    rate 44100
  }
  bindings { 0 0 1 1 }
}
 

#							CARD 0 DEVICES
#							##############

ctl.card0		{ type hw; card 0; }
pcm.card0		{ type hw; card 0; }

pcm.dsnoop0		= "rec:23760,card0";

ctl.dmix0		= ctl.card0;
pcm.dmix0		= "dmix-20:13760,card0,48000";

ctl.mixer0		= ctl.card0;
ctl.dsp0		= ctl.card0;
pcm.dsp0		= "dsp:dsnoop0,dmix0";

ctl.dmix0-rev		= ctl.card0;
pcm.dmix0-rev		= "swap:dmix0";

ctl.stereo0-40		= ctl.card0;
pcm.stereo0-40		= "stereo-40:surround40:0";

ctl.stereo0-51		= ctl.card0;
pcm.stereo0-51		= "stereo-51:surround51:0";

ctl.digi0		= ctl.card0;
pcm.digi0		= "iec:hw:0,2";

ctl.card0-f		= ctl.card0;
pcm.card0-f		= "card-f:dsp0";

ctl.card0-r		= ctl.card0;
pcm.card0-r		= "card-r:surround40:0";

########################################################################

#							CARD 1 DEVICES
#							##############

# For my #1 card, a CMI8738, the 'hw:1,1' device is either the
# rear channels or a multi channel device depending on a mixer
# control setting.

ctl.card1		{ type hw; card 1; }
pcm.card1		{ type hw; card 1; }

ctl.mixer1		= ctl.card1;
ctl.dsp1		= ctl.card1;
pcm.dsp1		= "dsp:dsnoop1,dmix1";

pcm.dsnoop1		= "rec:29370,card1";

ctl.dmix1		= ctl.card1;
pcm.dmix1		= "dmix-20:19370,card1,44100";

ctl.dmix1-rev		= ctl.card1;
pcm.dmix1-rev		= "swap:dmix1";

ctl.stereo1-40		= ctl.card1;
pcm.stereo1-40		= "stereo-40:surround40:1";

ctl.stereo1-51		= ctl.card1;
pcm.stereo1-51		= "stereo-51:surround51:1";

ctl.digi1		= ctl.card1;
pcm.digi1		= "iec:hw:1,2";

ctl.card1-f		= ctl.card1;
pcm.card1-f		= "card-f:dsp1";

ctl.card1-r		= ctl.card1;
pcm.card1-r		= "card-r:surround40:1";

ctl.card1-s		= ctl.card1;
pcm.card1-s		= "card-s:surround71:1";

########################################################################

#							SW VOLUME CONTROL
#							#################

#pcm.name		{ type			softvol;
#			  slave			STR;
#			  control {
#			    name		STR;
#			      [card		INT;]
#			      [iface		STR;]
#			      [index		INT;]
#			      [device		INT;]
#			      [subdevice	INT;]
#			      [count		INT;]
#			  }
#			}

########################################################################

#							FILE OUTPUT
#							###########

pcm.file
{
	@args [ PCM FILE ]
	@args.PCM		{ type string; }
	@args.FILE		{ type string; default "/tmp/alsa.raw"; }

	type			file;

	file			$FILE;
	#[format		"raw";]
	#[perm			0600;]

	slave.pcm		$PCM;
}

ctl.file0		= ctl.card0;
pcm.file0		{ type copy; slave.pcm "file:dsp0,/tmp/alsa0.raw"; }

ctl.file1		= ctl.card1;
pcm.file1		{ type copy; slave.pcm "file:dsp1,/tmp/alsa1.raw"; }

########################################################################;

#							2 CARDS AS 1
#							############

# Using multiple cards to simulate a single card is usually a bad idea
# because they have different latencies and multichannel sound can come
# out with quite a bit of skew. Some people however have a legitimate
# need for this.

# Using two cards as one four channel card.
#   http://ALSA.OpenSrc.org/index.php?page=TwoCardsAsOne

######################################
# 1st >= 2 channels, 2nd >= 2 channels

ctl.multi40-22		= ctl.card0;

pcm.multi-22
{
	@args [ PCM1 PCM2 ]
	@args.PCM1		{ type string; }
	@args.PCM2		{ type string; }

	type			multi;

	slaves.a.pcm		$PCM1;
	slaves.a.channels	2;

	slaves.b.pcm		$PCM2;
	slaves.b.channels	2;

	bindings.0.slave	a;
	bindings.0.channel	0;

	bindings.1.slave	a;
	bindings.1.channel	1;

	bindings.2.slave	b;
	bindings.2.channel	0;

	bindings.3.slave	b;
	bindings.3.channel	1;
}


# Using two cards as one 5.1 channel card, the first has
# 2 channels and the second has 4 channels, and viceversa.
#   http://ALSA.OpenSrc.org/index.php?page=TwoCardsAsOne

######################################
# 1st >= 2 channels, 2nd >= 4 channels

pcm.multi51-24
{
	@args [ PCM1 PCM2 ]
	@args.PCM1		{ type string; }
	@args.PCM2		{ type string; }

	type			multi;

	slaves.a.pcm		$PCM1;
	slaves.a.channels	2;

	slaves.b.pcm		$PCM2;
	slaves.b.channels	4;

	bindings.0.slave	a;
	bindings.0.channel	0;

	bindings.1.slave	a;
	bindings.1.channel	1;

	bindings.2.slave	b;
	bindings.2.channel	0;

	bindings.3.slave	b;
	bindings.3.channel	1;

	# Center, physically rear left, 2nd card
	bindings.4.slave	b;
	bindings.4.channel	2;

	# LFE/subwoofer, physically rear right, 2nd card
	bindings.5.slave	b;
	bindings.5.channel	3;
}

######################################
# 1st >= 4 channels, 2nd >= 2 channels

pcm.multi51-42
{
	@args [ PCM1 PCM2 ]
	@args.PCM1		{ type string; }
	@args.PCM2		{ type string; }

	type			multi;

	# could be "dmix0"
	slaves.a.pcm		$PCM1;
	slaves.a.channels	4;

	# could be "dmix1"
	slaves.b.pcm		$PCM2;
	slaves.b.channels	2;

	bindings.0.slave	a;
	bindings.0.channel	0;

	bindings.1.slave	a;
	bindings.1.channel	1;

	bindings.2.slave	a;
	bindings.2.channel	2;

	bindings.3.slave	a;
	bindings.3.channel	3;

	# Center, physically front left, 2nd card
	bindings.4.slave	b;
	bindings.4.channel	0;

	# LFE/subwoofer, physically front right, 2nd card
	bindings.5.slave	b;
	bindings.5.channel	1;
}
