Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
<<importTiddlers>>
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<!--{{{-->
<div class='header' role='banner' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected {color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:alpha(opacity=60);}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0; top:0;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0 3px 0 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0; padding-bottom:0;}

.fieldsetFix {border:0; padding:0; margin:1px 0px;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<<<
''Work in progress'' -- Prior to version 1.0.0, the API may be subject to revisions which break backwards code compatibility.
<<<

!Classes

[[Audio]] -- The audio module; it creates audio output for the duration of its lifetime.

[[Clip|AudioClip]] -- Used for storing segments of audio in memory.

[[Utilities]] -- Utility classes for mixing, sharing, splicing, transcoding and controlling audio which are generally useful.

[[Effects]] -- Audio streams which take an input and change it somehow.

[[Synths]] -- Audio streams which create audio from nothing using mathematics.

[[Analysis]] -- Audio streams which extract data from audio signals.
{{{#include <plaid/audio/effects.h>}}}

An ''Amp'', short for //amplifier//, is an [[effect|Effects]] makes things louder and quieter, with smooth changes in volume.

It supports ''coefficient'' and ''decibel'' measures of volume, and can ramp between values linearly or exponentially.

Observe [[appropriate caution|Safety]] when using this class; it can endanger your hearing!

!!Constructor

{{{Amp(Signal source, float volume = 1.0f);}}}
<<<
Creates a new Amp from the given source [[Signal]] and with the given coefficient volume as its initial value.
<<<

!!Member Methods

{{{float volume();}}}
{{{void  volume(float v);}}}
<<<
This [[Property]] represents the ''coefficient volume'' of the Amp -- the multiplier which scales input audio.
Coefficient volume is a linear scale, with 0.0 being silence, 0.5 being 50% volume, and 1.0 being "normal" loudness as if no Amp was used.
Values may be larger than 1.0 to make the sound louder, or negative to invert it.
<<<

{{{float decibels();}}}
{{{void  decibels(float d);}}}
<<<
This [[Property]] represents the ''decibel loudness'' of the Amp -- this approximates human-perceived loudness.
Decibel loudness is a logarithmic scale, with 0.0 being "normal" loudness, -10.0 being 10 times quieter, 10.0 being 10 times louder, -20.0 being 100 times quieter, et cetera.
Setting {{{volume}}} to a value less than or equal to zero will cause calls to {{{decibels()}}} to return {{{NaN}}} or {{{-HUGE_VAL}}} respectively.
<<<

{{{void rampLinear();}}}
{{{void rampExponential();}}}
<<<
Set the ramping scheme for this Amp, which defaults to exponential.
Linear ramping means change in {{{volume}}} will occur at a constant rate.
Exponential means change in {{{decibels}}} will be constant.
When {{{volume}}} crosses zero, ramping is linear for that frame regardless.
<<<

!!Related Global Functions

{{{float Decibels(float db);}}}
{{{float ToDecibels(float volume);}}}
<<<
These functions convert decibels to linear volume and vice versa.
Mind that ~ToDecibels will return strange values for inputs less than or equal to zero.
<<<
{{{#include <plaid/audio/analysis.h>}}}

A set of classes useful for extracting descriptive information from audio.  Presently there is just one.

''Built-in analysis:''
* [[Envelope]] -- A running approximation of a Sound's amplitude.
{{{#include <plaid/audio.h>}}}

The{{{ Audio }}}class manages the core functionality of{{{ <plaid/audio> }}}:  setting up audio I/O, playing sound to the speakers, and getting sound from files and the microphone.
For convenience, it runs a ''master [[mixer|Mixer]]'' and exposes its functionality.

The first thing you'll generally want to do when using the engine is to create an instance of Audio and store its pointer, perhaps in a handy [[Ref]].

!!Constructor

{{{explicit Audio(bool headless = false);}}}
<<<
Call this constructor to create an Audio module using the default [[Driver]].

//Advanced:// +++[bool headless]
If ''headless'' is true, the Audio module will not actually connect to the system's audio I/O or construct a [[Driver]] layer, using a dummy instead.
It will give the appearance of functioning as usual, pulling tiny amounts of audio data from attached streams whenever{{{ update() }}}is called.
This is useful for debugging in certain situations.===
<<<

!!Member Methods

{{{void update();}}}
<<<
The system will work best if you call it on a regular basis.  +++[but what does it do?]This function regulates audio timeslicing and causes state changes to propagate from the controlling thread to the audio thread via lock-free queues.=== 

//Tip:  If your software is a game or mutimedia application with a framerate, calling{{{ update(); }}}once per graphical frame is ideal.//
<<<

{{{float load();}}}
<<<
Returns the CPU time usage of the audio thread, where{{{ 0.0 }}}is 0% and{{{ 1.0 }}}is 100%.
You want this to stay low; if it goes over 1.0 your audio will begin to glitch and skip.

//Tip:  CPU usage isn't the only contributor to this number.  Disk access and locking can also cause [[waits|Waiting]].//
<<<

{{{AudioFormat format()}}}
<<<
Returns the [[AudioFormat]] used for output -- all played sound will be transcoded to this format by the master mixer.
<<<

{{{float volume();}}}
{{{void  volume(float v);}}}
<<<
Use this [[property|Property]] to access the master volume for all sound.
{{{1.0}}} is 100%, {{{0.5}}} is 50%, {{{0.0}}} is silence.  It could be higher, like {{{1.5}}} for 150%, but [[be careful|Safety]]!
<<<

{{{void play(Sound s);}}}
{{{void play(Sound s, float volume);}}}
<<<
This method causes a [[Sound]] to begin playing immediately.
The second version allows you to set an initial volume, which works just like the{{{ volume }}}method above.
<<<

{{{void pause(Sound s);}}}
<<<
This causes a Sound to stop playing, but it will not be dropped from the master mixer.  It can be easily resumed later with a call to{{{ play}}}.
The cutoff is sudden and may create a popping noise, which can be mitigated with a gradual volume change.

//Tip:  Mind that you{{{ stop }}}sounds you've left paused when their controlling objects are destroyed -- they will otherwise sit around in the mixer wasting resources.//
<<<

{{{void stop(Sound s);}}}
<<<
This causes a Sound to stop playing and be removed from the Mixer, releasing the Mixer's [[reference|Ref]] to it.

//Tip:  This command must be completed in the audio thread; the release is not instant.  Re-using an audio stream after such an unbinding is possible but rarely worth doing.//
<<<

{{{float volume(Sound sound)}}}
{{{void  volume(Sound sound, float volume);}}}
<<<
Query or alter the volume factor of a sound.  Output volume is ''sound volume * master volume''.
Changes are instant and liable to create a popping noise, especially for large changes; for smooth volume changes, use an [[Amp]] effect.
<<<

{{{bool playing(Sound sound);}}}
<<<
Returns whether the given sound is playing on this mixer.
This will be false for sounds which were never played, have been paused or stopped, or have [[exhausted|Exhaustion]].

//Tip:  It's possible for this to be "slow" in changing.  For instance, it may remain true for a frame or two after stopping a sound.  This is because it's based on feedback data from the audio thread.//
<<<

{{{bool has(Sound sound);}}}
<<<
This function works exactly like{{{ playing }}}but returns{{{ true }}}if the sound is paused.

//Tip:  If you ever need to add a Sound to the mixer without actually playing it, "pause" it and it will be bound.//
<<<

{{{Sound stream(String filename, bool loop = false);}}}
<<<
Creates a stream that plays an audio file from disk, looping it seamlessly if{{{ loop }}}is true.
This will fail if no [[Codec]] is available for the filetype.

//Tip:  Streaming uses less memory but takes up more CPU and disk bandwidth than a [[loaded sound|AudioClip]].  Streaming multiple copies of the same sound can get very inefficient.//
<<<

''TODO:''
<<<
Add an easy method for loading a file into an [[AudioClip]].
<<<

{{{Sound microphone();}}}
<<<
Returns a stream of audio input from the [[Microphone]].
<<<
<<<
''Work in Progress'': This class is functional and safe to use, but incomplete.
<<<

{{{#include <plaid/audio/clip.h>}}}

The{{{ AudioClip }}}class provides a way to store audio data in memory, and play the stored clip like any other Sound.

As a rule of thumb, it's most practical to use this class to buffer small or frequent sounds -- especially where more than one copy of the sound could be playing at once.  Large, singular sounds such as music are often streamed from disk to save memory.

This class is not itself an [[AudioStream]] -- it simply stores a buffer of audio data, which can be played by creating an{{{ AudioClip::Player}}}.  Any number of Players may read from an ~AudioClip at a given time.

!!Constructors

{{{static AudioClip Null();}}}
{{{AudioClip();}}}
<<<
Creates a null ~AudioClip.  ~AudioClip is a [[reference type|Reference Type]].
<<<

{{{AudioClip(AudioFormat format, SAMPLE_TYPE type = INT16);}}}
<<<
Create an ~AudioClip with the given [[formatting|AudioFormat]].

The most desirable values of{{{ format }}}are the format of the data source -- usually a file -- or that of the destination -- usually Audio.

{{{SAMPLE_TYPE }}}is ignored in version 0.2.0, and the standard 32-bit sample format will be used regardless.  This may aggravate memory concerns somewhat.
<<<

!!Member Methods

{{{operator bool() const;}}}
{{{bool null() const;}}}
<<<
Check whether the ~AudioClip is null.  It's a [[reference type|Reference Type]], so its internal data may be shared between multiple instances or not present at all.
<<<

{{{Ref<Player> player(bool loop = false);}}}
<<<
Creates a{{{ Player }}}which streams this AudioClip's contents.  If{{{ loop }}}is true, the sound will loop indefinitely; otherwise it will exhaust at the Clip's end and [[exhaust|Exhaustion]].
<<<

{{{float load(Sound source, float limit);}}}
<<<
Pull audio data from{{{ source }}}into this Clip, until the source [[exhausts|Exhaustion]] or{{{ limit }}}seconds of audio have been loaded -- whatever happens first.

If{{{ limit }}}is less than or equal to zero, no limit is imposed.  This may lead to application freezes if the source stream is non-exhausting -- you are advised to use a large number like 600 (ten minutes) instead.

This method will malfunction if the{{{ source }}}stream is one which is affected by the audio thread -- attempting to load from microphone input or a [[Splitter]] which also routes to audio output are two cases where this might occur.
<<<

//{{{//Ref<Player> record(Signal source, float limit = 0.0f);}}}
<<<
''Future feature'': This method will facilitate recording sounds in realtime, such as microphone input or master audio output.
<<<
{{{#include <plaid/audio/stream.h>}}}

An{{{ AudioFormat }}}describes the format of some sound being handled by the engine, in terms of its ''sample-rate'' and the number of ''channels''.  The ''sample format'' is fixed.

The [[Audio]] class has a{{{ format() }}}method which may be used to determine the output format.
All [[streams|AudioStream]] also have a{{{ format() }}}method which describes the audio they will produce.

Many classes require a format upon construction -- when in doubt, use that of the [[Audio]] module.

!!Members

{{{AudioFormat(Uint32 channels, Uint32 rate);}}}
<<<
Construct an ~AudioFormat with the given parameters.
<<<

{{{Uint32 channels;}}}
<<<
The number of channels specified by the format, as below.  Cannot exceed{{{ PG_MAX_CHANNELS}}}.
<<<

{{{Uint32 rate;}}}
<<<
The sample rate in hertz, as below.  Represents the number of samples per second per channel.
<<<

!!Concepts

''Sample Rate''
<<<
The number of audio samples per second.  An audio signal can only contain frequencies up to half of this value.

Common sampling rates in ~PCs are 48000 hz, 44100 hz, 96000 hz and 32000 hz.  Audio files streamed from the disk have their own sampling rates and often need to be [[transcoded|Transcoder]].
<<<

''Channel Count''
<<<
The number of separate "tracks" of audio within a stream.  For instance, left and right channels are used in stereo sound.

{{{<plaid/audio> }}}uses de-interleaved audio internally in order to simplify DSP programming.  By default, the framework supports up to 8 channels per stream, based on the{{{ PG_MAX_CHANNELS }}}macro.

Default behaviors for [[transcoding|Transcoder]] will ensure splitting of mono sounds and downmixing of multi-channel sounds where the number of channels in an audio source differs from the number used by the driver.  Explicit support for schemes beyond stereo is not yet mature.
<<<

''Sample Format''
<<<
{{{<plaid/audio> }}}encodes all runtime sound with 32-bit integers, where the bottom 24 bits form the standard amplitude range and the top 8 allow overflow.  The single format allows new ~DSPs to be written once and used on arbitrary platforms.  The format used was chosen as a balance between the high dynamic range of floating-point audio data and the computational efficiency of fixed-point formatting.
<<<
{{{#include <plaid/audio/stream.h>}}}

''AudioStream'' is the base type for all audio sources in{{{ <plaid/audio>}}}.

Instances of this class or its children may be handled by the{{{ Sound }}}type.

!!Extending

<<<
''Advanced users' topic'':  this is of interest mainly to programmers who are writing [[extensions|Extending the Library]] to{{{ <plaid/audio>}}}.
<<<

//Further documentation on the functions of this class will be available in future releases.  For now refer to the header file.//
The basic functionality of{{{ <plaid/audio> }}}is fairly simple to use.

Many common tasks can be achieved through use of the{{{ Sound }}}and{{{ Audio }}}types alone, using the latter's methods.

The type{{{ Sound }}}is used to refer to a sound of any type, such as the user's microphone or a file on the disk.
Don't sweat its details for now.

One instance of the [[Audio]] class needs to exist for your program to play sound, so create it at program startup and destroy it when you shut down.
You can use your Audio instance to{{{ play }}}and{{{ pause }}}sounds, such as those that you{{{ stream }}}from the disk or the{{{ microphone }}}.
Sounds from disk can{{{ loop }}}and you can easily change the{{{ volume }}}of individual sounds or the whole program.

Look at [[Audio's documentation|Audio]] for all the functions you need to know about to get started.


Once you get more comfortable, advance to the [[Overview]] section for the conceptual layout of the engine and [[API Reference]] for details on its many helpful classes.
A ''codec'' lets you read some set of filetypes from disk.

Presently a codec for ''ogg vorbis'' files is provided with the engine and can stream ''.ogg'' or ''.ogv'' file extensions.

To add a codec and enable a new sound format, simply drop its code into your project or compile it into your plaidaudio static library.

!Writing codecs
<<<
''Advanced users' topic'':  This section is of interest mainly to programmers who are writing [[extensions|Extending the Library]] to{{{ <plaid/audio>}}}.
<<<

//This section will eventually cover the process of writing a codec for the framework.  Until it does, try dissecting the provided one.//
If you're interested in contributing to{{{ <plaid/audio>}}}'s open-source development, send me an E-mail here:

[[balster.evan@gmail.com|mailto:balster.evan@gmail.com]]
config.options.txtUserName = "Evan";

// options for saving..
config.options.chkSaveBackups = false
config.options.chkAutoSave = true;
[[Welcome]]
A ''driver layer'' allows the engine access to the speakers and microphone through callbacks.
{{{<plaid/audio>}}} automatically detects driver layers that have been compiled with it and selects one to use at startup.

+++[what if no drivers are compiled with the library?]
If none are available, any [[Audio]] modules created will use a dummy driver which renders small amounts of sound every{{{ update }}}and produces no output.=== 

+++[why aren't drivers built-in?]
The library is designed to be as portable as possible.  Including a driver in it would limit it to just those platforms supported by that driver.
Additionally, some users may only want to analyze or process audio, with no need for realtime input or output.=== 

Presently a portaudio driver is provided with the library.

To add a driver to your project, simply add its code and any dependencies into your project or compile it into your plaidaudio static library.

!Writing driver layers
<<<
''Advanced users' topic'':  This section is of interest mainly to programmers who are writing [[extensions|Extending the Library]] to{{{ <plaid/audio>}}}.
<<<

//This section will eventually cover the process of writing a driver layer for the framework.  Until it does, try dissecting the provided one.//
{{{#include <plaid/audio/effects.h>}}}

An ''audio effect'' takes an input and changes it somehow.  Usually this is a single input but some effects might take more than one.

{{{<plaid/audio>}}} provides a [[base template|AudioEffect]] and a number of common effects in this header.

''Built-in effects:''
* [[Amp]] -- Makes things louder and quieter with smooth changes in volume.
* [[Pitch]] -- Changes the pitch and speed of the input stream, sliding smoothly.  Useful for simple musical code.
* [[Pan]] -- Always outputs stereo, and controls left/right balance of input sounds.
* [[Filter]] -- Performs a high-pass and/or a low-pass on input audio.  Can create "muffling" or "sweeping" effects.

''Non-functioning effects:''
* [[Reverb]] -- A simple delay-line reverb system.
{{{#include <plaid/audio/analysis.h>}}}

An ''envelope'' is an approximation of a signal's amplitude over time.  This one is computed by the simple method of applying a [[low-pass|Filter]] to the absolute value of the input signal.

Samplings of the amplitude can be returned from the audio thread and can be accessed.  This facilitates client-side analysis of microphone activity, for instance.

The signal produced by an envelope is a succession of (usually) positive numbers and is generally undesirable to play to audio.
The recommended method for analyzing a sound's amplitude is to route the sound through an envelope and play the envelope to the mixer at volume{{{ 0.0}}}.  If it is desirable for the source to be audible, it's necessary to use a [[Splitter]].
//(In the future the Envelope's output might be rendered useful by constructs like a signal-controlled Amp.)//

!!Constructor

{{{Envelope(Signal source, float frequency = 10.0f, Uint32 logLength = 0);}}}
<<<
Creates an Envelope from the given signal, with the given{{{ frequency }}}as below.

Supply a positive value for{{{ logLength }}}to enable access to envelope values with the below methods.
<<<

!!Member Methods

{{{float frequency(float f);}}}}
<<<
{{{frequency }}}is the cutoff in hertz of the [[low-pass filter|Filter]] used internally.  Higher values improve responsiveness, while lower ones produce a smoother envelope.
It should be several times lower than the lowest frequency present in the source audio, to reduce interference.
<<<

{{{float  amplitude();}}}
<<<
If logging is enabled, this function returns the newest available sample of the Envelope.
Its value generally ranges from{{{ 0.0 }}}to{{{ 1.0}}}, or possibly higher if the signal's amplitude exceeds 100%.  It will tend to be a fraction of the signal's actual loudness.
<<<

{{{Uint32 latency();}}}
<<<
Amplitude samples are returned asynchronously.  This method returns the age in frames of the latest sample.
<<<

{{{bool   pull(float &amplitude);}}}
<<<
This method pulls amplitude samples for each frame, one by one.
If a new sample is available, it will overwrite{{{ amplitude }}}with the new value and return{{{ true}}}.  Otherwise it will return{{{ false}}}.

If the number of un-pulled samples exceeds{{{ logLength}}}, the oldest samples will be discarded in order to make room.
<<<
''Evan Balster'' is the author of the{{{ <plaid/audio> }}}library.

He is at the time of this writing a ''freelance programmer'' specializing in audio.
He can be hired to extend the library, or do other sorts of audio programming.

He also does other things which are probably irrelevant to you, like playing the accordion, mandolin and oboe, programming and designing games, voice acting and writing about himself in the third person.

He can be contacted at{{{ balster.evan@gmail.com}}}.
An [[AudioStream]] is ''exhausted'' when it "runs out" of audio or otherwise decides to mark itself as such.
Most commonly the stream is data from a file which has been played to its end.

Exhaustion is a queue to certain other audio classes in the engine, which perform various actions in response.
* [[Mixer]]s will promptly drop any exhausted sound.
* [[Splicer]]s will note where the "cutoff" occurred and seamlessly splice the next in a sequence of sounds into place.
* [[Effects]] will "inherit" the exhaustion status of their source stream.

Exhausted streams are required to mark their cutoff point, output silence after it and begin returning{{{ true }}}from the{{{ exhausted() }}}method.

Many streams, including the [[Microphone]] and most [[Mixer]]s and [[Synths]], are "infinite" and will never exhaust.
<<<
''Advanced users' topic'':  this is of interest mainly to programmers who are writing [[extensions|Extending the Library]] to{{{ <plaid/audio>}}}.
<<<

This article will eventually cover the process of writing audio streams, file codecs and driver layers for the engine.

Related: [[Driver]], [[Codec]]

If you develop any interesting extensions, consider [[submitting them|Contribution]] for inclusion in the framework.
{{{#include <plaid/audio/effects.h>}}}

A ''Filter'' attenuates some set of frequencies in a signal while leaving others relatively unaffected.

This class presently supports three modes of filtering:
* [[Lowpass|http://en.wikipedia.org/wiki/Low-pass_filter]]: blocks sounds above a given frequency.  Produces a muffling effect, like the sound source is covered up.
* [[Highpass|http://en.wikipedia.org/wiki/High-pass_filter]]: blocks sounds below a given frequency.  Produces a fading effect, like the sound source is distant or coming through cheap speakers.
* [[Bandpass|http://en.wikipedia.org/wiki/Band-pass_filter]]: blocks sounds outside a range of frequencies.  Useful for making [[Multi-Band]] filters...

Currently only first-order filtering is supported; frequencies will be attenuated by a factor of 2 (3 dB) at the cutoff, and thereafter a factor of 4 (6 dB) for every octave by which they exceed the filter's range.

!!Constructor

{{{Filter(Signal source, float lowPass = 0.0f, float highPass = 0.0f);}}}
<<<
Creates a new Filter from the given source [[Signal]] and with the given initial cutoff frequencies for its lowpass and highpass, as below.
<<<

!!Member Methods

{{{void lowpass(float cutoff);}}}
<<<
Sets the filter to act as a first-order [[low-pass|http://en.wikipedia.org/wiki/Low-pass_filter]] with the given cutoff frequency.
<<<

{{{void highpass(float cutoff);}}}
<<<
Sets the filter to act as a first-order [[high-pass|http://en.wikipedia.org/wiki/High-pass_filter]] with the given cutoff frequency.
<<<

{{{void bandpass(float lowFreq, float highFreq);}}}
<<<
Sets the filter to act as a first-order [[band-pass|http://en.wikipedia.org/wiki/Band-pass_filter]].

Perhaps counter-intuitively,{{{ lowFreq }}}is the frequency of the high-pass filter, while{{{ highFreq }}}is the frequency of the low-pass filter.
This is because we want to pass signals higher than our low frequency and lower than our high frequency.
<<<

{{{void off();}}}
<<<
Sets the filter to neither low-pass nor high-pass its input signal.

Technically neither of these operations is shut off; when inactive, each is simply set to an extreme frequency which is expected to have no effect.
<<<



{{{void bandstop(float lowFreq, float highFreq);}}}
<<<
Sets the filter to act as a first-order [[band-stop|http://en.wikipedia.org/wiki/Band-stop_filter]].  ''This method currently has no effect.''

As a workaround, a band-stop effect may be achieved presently by applying a [[Splitter]], playing one copy of the signal to output, and playing a band-passed copy to output inverted (its volume should be negative the original's volume).
<<<
Glitches are non-fatal failures in audio rendering which are perceptible as artifacts in output audio.

Math errors, bugs and other undefined behaviors can cause audio to glitch.  The results can be exquisite, and potentially [[deafening|Safety]].

Some common types:
* ''Clipping'' -- When an output signal contains amplitudes too loud to be played, they'll be clamped to the range of the output device.
* ''Wrapping'' -- When a signal exceeds an integer range and no clipping occurs, it will wrap from positive to negative or vice versa, with a loud clicking or buzzing sound.
* ''Buffer underflow'' -- When the audio callback takes too long, the operating system's mixer or the sound card will fill the gap with... something.  It could be silence, or...
* ''Buffer remnant'' -- When an audio source fails to write data to part or all of a target buffer, the data that was there will be present instead.  Often produces a skipping, garbled sound.
* ''Splicing'' -- Suddenly starting or stopping sounds with no volume ramp tends to produce a popping sound.  This also happens when a [[Splitter]] or [[Microphone]] stream is mishandled.
* ''Math errors'' -- Use of over-large numbers, ~NaNs, degenerate formulae, and other oversights can create wildly incoherent audio data.
The latest version of the framework can be downloaded from its homepage [[here|http://interactopia.com/code/plaidaudio/]].

{{{<plaid/audio> }}}is a crossplatform library, but is in an early state.
At present, the only project files available are for Microsoft Visual C++, though the code builds just fine on OS X, Linux/Unix/POSIX, and iOS.

Users of other platforms will need to create makefiles or projects for themselves, or drop the library into their project.
Languages other than Visual C++ will require [[Bindings]] of some kind to be written.

If you're interested in maintaining a build system for language bindings for the library, [[contact me|Contribution]]!


''Visual Studio instructions''

Open{{{ plaidaudio.vcxproj }}}in your distribution of the library.  Compile it in debug and/or release mode.

This creates a static library in the "lib" subfolder, which contains all the "pure" code of the library, but no [[driver layer|Driver]] or [[audio file codecs|Codec]].

From here, you may follow the [[Tutorial]] to get a program running.
{{{<plaid/audio> }}}is ''zlib-licensed'', which means you can do pretty much whatever you want with it -- copy it, sell it, make commercial software, et cetera.
You don't need to pay anything, credit me or make any changes to the licensing of such software.
Why?  Because it's awesome and I've always loved libraries licensed this way.

You use it [[at your own peril|Safety]], however, and have no grounds to sue [[me|Evan]] if it makes you deaf in one ear, startles your cat, causes your fine china to explode or otherwise wreaks havoc and misfortune.

You are prohibited from claiming you wrote the software, though it is //totally// okay to make modified versions.

!Legal
{{{
<plaid/audio> standalone audio framework
Copyright (c) 2012-2013 Evan Balster, Interactopia LLC

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

   1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

   3. This notice may not be removed or altered from any source
   distribution.
}}}
A ''limiter'' is an audio effect that prevents audio from exceeding a certain volume, automatically "turning it down" when it does.

It is a wonderful feature for preventing clipping or hearing damage from loud sounds, and for creating an impressive "overpowering" effect for a loud sound as compared to the rest of the soundscape.

Unfortunately, {{{<plaid/audio>}}} does not yet include such a class.  However, it is possible to create a crude Limiter or Compressor by using a [[Splitter]], an [[Envelope]] and an [[Amp]] together.  Split the audio signal to the envelope and amp, play the envelope to output at zero volume, play the amp to output, and decrease the amplification when the envelope reports high amplitudes.  Creating a [[Multi-Band]] limiter will improve the quality of the effect further.
[[Installation]]
[[Tutorial]]
[[Basics]]
[[Overview]]
[[API Reference]]
-----
[[Extending the Library]]
[[Writing Codecs|Codec]]
[[Porting|Driver]]
-----
[[Version History]]
[[License]]
[[Health & Safety|Safety]]
The ''microphone'' is type of audio stream that can be created from the [[Audio]] module.

It produces an unending stream of sound from the driver's selected sound input, with the same [[AudioFormat]] as speaker output.
Since its flow rate is fixed, expect some erratic (but potentially amusing) behavior if you use a rate-changer like [[Pitch]] on it.

Any number of microphone streams can safely exist at the same time and will not affect one another's behavior.

Unlike many sources of audio, its class is hidden, so it offers no methods aside from those in [[AudioStream]].
{{{#include <plaid/audio/util.h>}}}

The{{{ Mixer }}}class adds audio streams together so as to make the sounds seem "simultaneous".

Designed for convenience, it provides basic volume functionality, allows sounds to be paused and automatically drops them when they [[exhaust|Exhaustion]].

The [[Audio]] module contains a Mixer, called the ''master mixer'', that routes directly to system output.

!!Constructor

{{{Mixer(AudioFormat format, bool exhaustible = false);}}}
<<<
Creates a Mixer that outputs in the given [[format|AudioFormat]].  Input sounds will be automatically [[transcoded|Transcoder]] if they do not match.

If{{{ exhaustible }}}is{{{ true}}}, the Mixer will [[exhaust|Exhaustion]] when it contains no sounds.  Most of the time this is undesirable.
<<<

!!Member Methods

{{{void play();}}}
{{{void pause();}}}
<<<
These functions will pause and un-pause all sounds in the Mixer.  While paused, the Mixer will output silence and all inputs will be deactivated.
<<<

{{{void  volume(float v);}}}
<<<
Controls the master volume of the mixer, affecting all input sounds.
{{{1.0}}} is 100%, {{{0.5}}} is 50%, {{{0.0}}} is silence.  It could be higher, like {{{1.5}}} for 150%, but [[be careful|Safety]]!
<<<

{{{void play(Sound s);}}}
{{{void play(Sound s, float volume);}}}
<<<
This method causes a [[Sound]] to begin playing from the mixer.
The second version allows you to set an initial volume, which works just like the{{{ volume }}}method below.
<<<

{{{void pause(Sound s);}}}
<<<
This causes a Sound to stop playing from the mixer, but it will not be dropped.  It can be easily resumed later with a call to{{{ play}}}.
The cutoff is sudden and may create a popping noise, which can be mitigated with a gradual volume change.

//Tip:  Mind that you{{{ stop }}}sounds you've left paused when their controlling objects are destroyed -- they will otherwise sit around in the mixer wasting resources.//
<<<

{{{void stop(Sound s);}}}
<<<
This causes a Sound to stop playing and be removed from the Mixer, releasing the Mixer's [[reference|Ref]] to it.

//Tip:  This command must be completed in the audio thread; the release is not instant.  Re-using an audio stream after such an unbinding is possible but rarely worth doing due to the wait involved.//
<<<

{{{float volume(Sound sound)}}}
{{{void  volume(Sound sound, float volume);}}}
<<<
Query or alter the volume factor of a sound.  Output volume is ''sound volume * master volume''.
Changes are instant and liable to create a popping noise, especially for large changes; they are also rounded to multiples of 1/256.

//Tip: For high-quality volume control, use an [[Amp]] effect.//
<<<

{{{bool playing(Sound sound);}}}
<<<
Returns whether the given sound is playing on this mixer.
This will be false for sounds which were never played, have been paused or stopped, or have [[exhausted|Exhaustion]].

//Tip:  It's possible for this to be "slow" in changing.  For instance, it may remain true for a frame or two after stopping a sound.  This is because it's based on feedback data from the audio thread.//
<<<

{{{bool has(Sound sound);}}}
<<<
This function works exactly like{{{ playing }}}but returns{{{ true }}}if the sound is paused.

//Tip:  If you ever need to add a Sound to the mixer without actually playing it, "pause" it and it will be bound.//
<<<
A ''multi-band effect'' is one which divides an audio signal into a series of bands, performs some transformation, and re-integrates the transformed bands into a final signal.

Generally the bands are mutually exclusive frequency ranges extracted by bandpass [[Filter]]s.

In{{{ <plaid/audio> }}}the general method for achieving a multi-band effect is to set up a pipeline like so:

''audio source'' -> ''splitter''

''splitter copy A'' -> ''bandpass range A'' -> ''transformation A'' -> ''mixer''
''splitter copy B'' -> ''bandpass range B'' -> ''transformation B'' -> ''mixer''
''splitter copy C'' -> ''bandpass range C'' -> ''transformation B'' -> ''mixer''

The output of the mixer is the completed signal.


Some "recipes" which involve multi-band filtering:

''Multi-band equalizer''
<<<
Use a set of Amps for the transformation.  Each one controls the power of its band.
<<<

''Band power analysis''
<<<
Use an Envelope for the transformation.  Make sure the output audio is played at zero volume.
Sample the various bands' envelopes in order to make a graph of different frequency ranges.
<<<

''Multi-band compressor/limiter''
<<<
Route the same audio to both ''band power analysis'' and ''multi-band equalizer''.
Decrease the volume of a band when its envelope reports high values, using a smooth compression curve.
<<<

''Vocoder''
<<<
Route the "voice" signal into a ''band power analysis'' setup, and the carrier signal into a ''multi-band equalizer''.
Control the equalizer's Amps with the power values of the corresponding bands in the voice signal.
(use a pulse train for the carrier signal and a microphone for the voice for a convincing Dalek impression!)
<<<
/***
|Name|NestedSlidersPlugin|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.9|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|show content in nest-able sliding/floating panels, without creating separate tiddlers for each panel's content|
!!!!!Documentation
>see [[NestedSlidersPluginInfo]]
!!!!!Configuration
<<<
<<option chkFloatingSlidersAnimate>> allow floating sliders to animate when opening/closing
>Note: This setting can cause 'clipping' problems in some versions of InternetExplorer.
>In addition, for floating slider animation to occur you must also allow animation in general (see [[AdvancedOptions]]).
<<<
!!!!!Revisions
<<<
2008.11.15 - 2.4.9 in adjustNestedSlider(), don't make adjustments if panel is marked as 'undocked' (CSS class).  In onClickNestedSlider(), SHIFT-CLICK docks panel (see [[MoveablePanelPlugin]])
|please see [[NestedSlidersPluginInfo]] for additional revision details|
2005.11.03 - 1.0.0 initial public release.  Thanks to RodneyGomes, GeoffSlocock, and PaulPetterson for suggestions and experiments.
<<<
!!!!!Code
***/
//{{{
version.extensions.NestedSlidersPlugin= {major: 2, minor: 4, revision: 9, date: new Date(2008,11,15)};

// options for deferred rendering of sliders that are not initially displayed
if (config.options.chkFloatingSlidersAnimate===undefined)
	config.options.chkFloatingSlidersAnimate=false; // avoid clipping problems in IE

// default styles for 'floating' class
setStylesheet(".floatingPanel { position:absolute; z-index:10; padding:0.5em; margin:0em; \
	background-color:#eee; color:#000; border:1px solid #000; text-align:left; }","floatingPanelStylesheet");

// if removeCookie() function is not defined by TW core, define it here.
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}

config.formatters.push( {
	name: "nestedSliders",
	match: "\\n?\\+{3}",
	terminator: "\\s*\\={3}\\n?",
	lookahead: "\\n?\\+{3}(\\+)?(\\([^\\)]*\\))?(\\!*)?(\\^(?:[^\\^\\*\\@\\[\\>]*\\^)?)?(\\*)?(\\@)?(?:\\{\\{([\\w]+[\\s\\w]*)\\{)?(\\[[^\\]]*\\])?(\\[[^\\]]*\\])?(?:\\}{3})?(\\#[^:]*\\:)?(\\>)?(\\.\\.\\.)?\\s*",
	handler: function(w)
		{
			lookaheadRegExp = new RegExp(this.lookahead,"mg");
			lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = lookaheadRegExp.exec(w.source)
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
			{
				var defopen=lookaheadMatch[1];
				var cookiename=lookaheadMatch[2];
				var header=lookaheadMatch[3];
				var panelwidth=lookaheadMatch[4];
				var transient=lookaheadMatch[5];
				var hover=lookaheadMatch[6];
				var buttonClass=lookaheadMatch[7];
				var label=lookaheadMatch[8];
				var openlabel=lookaheadMatch[9];
				var panelID=lookaheadMatch[10];
				var blockquote=lookaheadMatch[11];
				var deferred=lookaheadMatch[12];

				// location for rendering button and panel
				var place=w.output;

				// default to closed, no cookie, no accesskey, no alternate text/tip
				var show="none"; var cookie=""; var key="";
				var closedtext=">"; var closedtip="";
				var openedtext="<"; var openedtip="";

				// extra "+", default to open
				if (defopen) show="block";

				// cookie, use saved open/closed state
				if (cookiename) {
					cookie=cookiename.trim().slice(1,-1);
					cookie="chkSlider"+cookie;
					if (config.options[cookie]==undefined)
						{ config.options[cookie] = (show=="block") }
					show=config.options[cookie]?"block":"none";
				}

				// parse label/tooltip/accesskey: [label=X|tooltip]
				if (label) {
					var parts=label.trim().slice(1,-1).split("|");
					closedtext=parts.shift();
					if (closedtext.substr(closedtext.length-2,1)=="=")	
						{ key=closedtext.substr(closedtext.length-1,1); closedtext=closedtext.slice(0,-2); }
					openedtext=closedtext;
					if (parts.length) closedtip=openedtip=parts.join("|");
					else { closedtip="show "+closedtext; openedtip="hide "+closedtext; }
				}

				// parse alternate label/tooltip: [label|tooltip]
				if (openlabel) {
					var parts=openlabel.trim().slice(1,-1).split("|");
					openedtext=parts.shift();
					if (parts.length) openedtip=parts.join("|");
					else openedtip="hide "+openedtext;
				}

				var title=show=='block'?openedtext:closedtext;
				var tooltip=show=='block'?openedtip:closedtip;

				// create the button
				if (header) { // use "Hn" header format instead of button/link
					var lvl=(header.length>5)?5:header.length;
					var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,buttonClass,title);
					btn.onclick=onClickNestedSlider;
					btn.setAttribute("href","javascript:;");
					btn.setAttribute("title",tooltip);
				}
				else
					var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider,buttonClass);
				btn.innerHTML=title; // enables use of HTML entities in label

				// set extra button attributes
				btn.setAttribute("closedtext",closedtext);
				btn.setAttribute("closedtip",closedtip);
				btn.setAttribute("openedtext",openedtext);
				btn.setAttribute("openedtip",openedtip);
				btn.sliderCookie = cookie; // save the cookiename (if any) in the button object
				btn.defOpen=defopen!=null; // save default open/closed state (boolean)
				btn.keyparam=key; // save the access key letter ("" if none)
				if (key.length) {
					btn.setAttribute("accessKey",key); // init access key
					btn.onfocus=function(){this.setAttribute("accessKey",this.keyparam);}; // **reclaim** access key on focus
				}
				btn.setAttribute("hover",hover?"true":"false");
				btn.onmouseover=function(ev) {
					// optional 'open on hover' handling
					if (this.getAttribute("hover")=="true" && this.sliderPanel.style.display=='none') {
						document.onclick.call(document,ev); // close transients
						onClickNestedSlider(ev); // open this slider
					}
					// mouseover on button aligns floater position with button
					if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this,this.sliderPanel);
				}

				// create slider panel
				var panelClass=panelwidth?"floatingPanel":"sliderPanel";
				if (panelID) panelID=panelID.slice(1,-1); // trim off delimiters
				var panel=createTiddlyElement(place,"div",panelID,panelClass,null);
				panel.button = btn; // so the slider panel know which button it belongs to
				btn.sliderPanel=panel; // so the button knows which slider panel it belongs to
				panel.defaultPanelWidth=(panelwidth && panelwidth.length>2)?panelwidth.slice(1,-1):"";
				panel.setAttribute("transient",transient=="*"?"true":"false");
				panel.style.display = show;
				panel.style.width=panel.defaultPanelWidth;
				panel.onmouseover=function(event) // mouseover on panel aligns floater position with button
					{ if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this.button,this); }

				// render slider (or defer until shown) 
				w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
				if ((show=="block")||!deferred) {
					// render now if panel is supposed to be shown or NOT deferred rendering
					w.subWikify(blockquote?createTiddlyElement(panel,"blockquote"):panel,this.terminator);
					// align floater position with button
					if (window.adjustSliderPos) window.adjustSliderPos(place,btn,panel);
				}
				else {
					var src = w.source.substr(w.nextMatch);
					var endpos=findMatchingDelimiter(src,"+++","===");
					panel.setAttribute("raw",src.substr(0,endpos));
					panel.setAttribute("blockquote",blockquote?"true":"false");
					panel.setAttribute("rendered","false");
					w.nextMatch += endpos+3;
					if (w.source.substr(w.nextMatch,1)=="\n") w.nextMatch++;
				}
			}
		}
	}
)

function findMatchingDelimiter(src,starttext,endtext) {
	var startpos = 0;
	var endpos = src.indexOf(endtext);
	// check for nested delimiters
	while (src.substring(startpos,endpos-1).indexOf(starttext)!=-1) {
		// count number of nested 'starts'
		var startcount=0;
		var temp = src.substring(startpos,endpos-1);
		var pos=temp.indexOf(starttext);
		while (pos!=-1)  { startcount++; pos=temp.indexOf(starttext,pos+starttext.length); }
		// set up to check for additional 'starts' after adjusting endpos
		startpos=endpos+endtext.length;
		// find endpos for corresponding number of matching 'ends'
		while (startcount && endpos!=-1) {
			endpos = src.indexOf(endtext,endpos+endtext.length);
			startcount--;
		}
	}
	return (endpos==-1)?src.length:endpos;
}
//}}}
//{{{
window.onClickNestedSlider=function(e)
{
	if (!e) var e = window.event;
	var theTarget = resolveTarget(e);
	while (theTarget && theTarget.sliderPanel==undefined) theTarget=theTarget.parentNode;
	if (!theTarget) return false;
	var theSlider = theTarget.sliderPanel;
	var isOpen = theSlider.style.display!="none";

	// if SHIFT-CLICK, dock panel first (see [[MoveablePanelPlugin]])
	if (e.shiftKey && config.macros.moveablePanel) config.macros.moveablePanel.dock(theSlider,e);

	// toggle label
	theTarget.innerHTML=isOpen?theTarget.getAttribute("closedText"):theTarget.getAttribute("openedText");
	// toggle tooltip
	theTarget.setAttribute("title",isOpen?theTarget.getAttribute("closedTip"):theTarget.getAttribute("openedTip"));

	// deferred rendering (if needed)
	if (theSlider.getAttribute("rendered")=="false") {
		var place=theSlider;
		if (theSlider.getAttribute("blockquote")=="true")
			place=createTiddlyElement(place,"blockquote");
		wikify(theSlider.getAttribute("raw"),place);
		theSlider.setAttribute("rendered","true");
	}

	// show/hide the slider
	if(config.options.chkAnimate && (!hasClass(theSlider,'floatingPanel') || config.options.chkFloatingSlidersAnimate))
		anim.startAnimating(new Slider(theSlider,!isOpen,e.shiftKey || e.altKey,"none"));
	else
		theSlider.style.display = isOpen ? "none" : "block";

	// reset to default width (might have been changed via plugin code)
	theSlider.style.width=theSlider.defaultPanelWidth;

	// align floater panel position with target button
	if (!isOpen && window.adjustSliderPos) window.adjustSliderPos(theSlider.parentNode,theTarget,theSlider);

	// if showing panel, set focus to first 'focus-able' element in panel
	if (theSlider.style.display!="none") {
		var ctrls=theSlider.getElementsByTagName("*");
		for (var c=0; c<ctrls.length; c++) {
			var t=ctrls[c].tagName.toLowerCase();
			if ((t=="input" && ctrls[c].type!="hidden") || t=="textarea" || t=="select")
				{ try{ ctrls[c].focus(); } catch(err){;} break; }
		}
	}
	var cookie=theTarget.sliderCookie;
	if (cookie && cookie.length) {
		config.options[cookie]=!isOpen;
		if (config.options[cookie]!=theTarget.defOpen) window.saveOptionCookie(cookie);
		else window.removeCookie(cookie); // remove cookie if slider is in default display state
	}

	// prevent SHIFT-CLICK from being processed by browser (opens blank window... yuck!)
	// prevent clicks *within* a slider button from being processed by browser
	// but allow plain click to bubble up to page background (to close transients, if any)
	if (e.shiftKey || theTarget!=resolveTarget(e))
		{ e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); }
	Popup.remove(); // close open popup (if any)
	return false;
}
//}}}
//{{{
// click in document background closes transient panels 
document.nestedSliders_savedOnClick=document.onclick;
document.onclick=function(ev) { if (!ev) var ev=window.event; var target=resolveTarget(ev);

	if (document.nestedSliders_savedOnClick)
		var retval=document.nestedSliders_savedOnClick.apply(this,arguments);
	// if click was inside a popup... leave transient panels alone
	var p=target; while (p) if (hasClass(p,"popup")) break; else p=p.parentNode;
	if (p) return retval;
	// if click was inside transient panel (or something contained by a transient panel), leave it alone
	var p=target; while (p) {
		if ((hasClass(p,"floatingPanel")||hasClass(p,"sliderPanel"))&&p.getAttribute("transient")=="true") break;
		p=p.parentNode;
	}
	if (p) return retval;
	// otherwise, find and close all transient panels...
	var all=document.all?document.all:document.getElementsByTagName("DIV");
	for (var i=0; i<all.length; i++) {
		 // if it is not a transient panel, or the click was on the button that opened this panel, don't close it.
		if (all[i].getAttribute("transient")!="true" || all[i].button==target) continue;
		// otherwise, if the panel is currently visible, close it by clicking it's button
		if (all[i].style.display!="none") window.onClickNestedSlider({target:all[i].button})
		if (!hasClass(all[i],"floatingPanel")&&!hasClass(all[i],"sliderPanel")) all[i].style.display="none";
	}
	return retval;
};
//}}}
//{{{
// adjust floating panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel) {
	if (hasClass(panel,"floatingPanel") && !hasClass(panel,"undocked")) {
		// see [[MoveablePanelPlugin]] for use of 'undocked'
		var rightEdge=document.body.offsetWidth-1;
		var panelWidth=panel.offsetWidth;
		var left=0;
		var top=btn.offsetHeight; 
		if (place.style.position=="relative" && findPosX(btn)+panelWidth>rightEdge) {
			left-=findPosX(btn)+panelWidth-rightEdge; // shift panel relative to button
			if (findPosX(btn)+left<0) left=-findPosX(btn); // stay within left edge
		}
		if (place.style.position!="relative") {
			var left=findPosX(btn);
			var top=findPosY(btn)+btn.offsetHeight;
			var p=place; while (p && !hasClass(p,'floatingPanel')) p=p.parentNode;
			if (p) { left-=findPosX(p); top-=findPosY(p); }
			if (left+panelWidth>rightEdge) left=rightEdge-panelWidth;
			if (left<0) left=0;
		}
		panel.style.left=left+"px"; panel.style.top=top+"px";
	}
}
//}}}
//{{{
// TW2.1 and earlier:
// hijack Slider stop handler so overflow is visible after animation has completed
Slider.prototype.coreStop = Slider.prototype.stop;
Slider.prototype.stop = function()
	{ this.coreStop.apply(this,arguments); this.element.style.overflow = "visible"; }

// TW2.2+
// hijack Morpher stop handler so sliderPanel/floatingPanel overflow is visible after animation has completed
if (version.major+.1*version.minor+.01*version.revision>=2.2) {
	Morpher.prototype.coreStop = Morpher.prototype.stop;
	Morpher.prototype.stop = function() {
		this.coreStop.apply(this,arguments);
		var e=this.element;
		if (hasClass(e,"sliderPanel")||hasClass(e,"floatingPanel")) {
			// adjust panel overflow and position after animation
			e.style.overflow = "visible";
			if (window.adjustSliderPos) window.adjustSliderPos(e.parentNode,e.button,e);
		}
	};
}
//}}}
{{{#include <plaid/audio/synth.h>}}}

This synthesizer creates a simple waveform whose frequency can be controlled.

''Available waveforms:''
* {{{Oscillator::SINE}}} -- A gentle sine wave.  Regarded as the purest manifestation of a frequency.
* {{{Oscillator::SQUARE}}} -- A harsh square wave.  A common sound in devices of old, which often applied a [[low-pass|Filter]] to mellow the sound.
* {{{Oscillator::TRIANGLE}}} -- A triangle wave.  Provides a middle ground between the 
* {{{Oscillator::SAWTOOTH}}} -- A nasaly sawtooth wave.  If its amplitude is positive, it is an ascending wave, otherwise it is a descending wave.

''Supplementary sounds:''
* {{{Oscillator::KLAXON}}} -- An unpleasant waveform useful for alarm noises.  (It was a failed attempt at Taylor approximation of a sine wave.)

!!Constructor

{{{Oscillator(AudioFormat format, float frequency, Uint32 type = SINE, float amp = .25f, float phase = 0.0f);}}}
<<<
Create an oscillator which outputs in the given{{{ format }}}a wave of the given{{{ type}}},{{{ frequency }}}and{{{ amp}}}litude.

The initial{{{ phase }}}value is unlikely to have an audible effect, but is useful for creating constructive and destructive interference.
<<<

!!Member methods

{{{float frequency();}}}
{{{void  frequency(float freq);}}}
<<<
This [[Property]] represents the ''fundamental frequency'' of the Oscillator, in hertz.  Put differently, this is the number times the wave plays per second.

If you're interested in making music, a formula like{{{ 440.0f * Semitones( ... ) }}}is a good starting point.  (440 hz
<<<
!Design Rationale

{{{<plaid/audio> }}}is an API which focuses on low-level functionality while trying to allow for basic usage in a high-level style.

Great effort is taken to make it easy to use, especially for [[simple tasks|Basics]], but ultimately it's meant for advanced users who want the most from their game audio.
Audio jargon will be uncensored in the API and this documentation, though explanation may be available.

The library was designed as my personal playground for DSP, and opensourced to fill a gap in the set of free audio libraries presently available to game developers.
It is distinguished from the leading API, ''~OpenAL'', by its strongly consistent behavior between platforms.
It provides a free alternative to powerful commercial libraries like ''FMOD'' and ''irrKlang''.

^^* The audio systems mentioned in bold are trademarks of their respective vendors.^^

!General concepts

!!Reference Counting
<<<
Main article: [[Ref]]
<<<
Many of the classes in this library can be memory-managed easily by using the [[Ref<T>|Ref]] class, which acts as a reference-counted pointer.
Refer to its [[article|Ref]] for helpful information on its use.

!!Audio Module
<<<
Main article: [[Audio]]
<<<
{{{<plaid/audio> }}}is comprised of an [[Audio]] module which controls and schedules sound, and plays it through a [[Driver]] layer.
This module houses a default [[Mixer]] and you can attach [[sounds|Sound]] to that mixer to be played to output.
It also manages access to audio files (where [[supported|Codec]]) and the [[microphone|Microphone]] input.

!!Audio Streams
A sound in the engine takes the form of an audio stream, inheriting from the [[appropriate class|AudioStream]].

Many sounds, including [[Mixers|Mixer]] and [[Effects]], can take other sounds as input.
It's important to note that without some [[special mechanism|Splitter]], a Sound can only output to ''one'' destination.

Some sounds, such as non-looping audio clips, are not infinite and will eventually [[exhaust|Exhaustion]] or "run out".
This state will propagate through most kinds of [[Effects]] and causes the sound to be dropped from the [[Mixer]] playing it, freeing up resources.
It is possible to [[splice|Splicer]] a second Sound such that it begins to play precisely when the first stops; this is useful for sounds that "start up" and then loop.

!!Audio Format
<<<
Main article: [[AudioFormat]]
<<<
Any given audio stream has an output format consisting of its sampling rate and channel count.
Audio streams whose formats are incompatible with what is demanded by other audio streams will generally be automatically [[transcoded|Transcoder]].
Most streams that take another stream as input will assume the format of their input stream.

All audio data is encoded in 24-bit integral samples stored in 32-bit datapoints of type{{{ Sint32}}}.
This format allows for fast computation and safe overflow which can be later removed with a [[Limiter]], with a small memory cost as compared to 16-bit samples.
It is possible to [[store|AudioClip]] loaded audio data in smaller formats.

!!Scheduling
The engine's scheduling system breaks audio output into timeslices based on the intervals between calls to [[Audio::update()|Audio]].
This is done with game framerates of 30+ hz in mind.

Most audio classes are written to synchronize their state in each of these timeslices with the corresponding "frame" in the controlling thread.
Further, most audio classes will smoothly ramp their settings' values from one "frame" to the next.
This allows the [[Pitch]] of a motor, for instance, to assume a new value 60 times a second with clear and granular response in audio.

An additional benefit of this is that it's very easy to synchronize sounds, such as those in layer-based dynamic music systems.
Any sound which is played on a given frame will start at an exact time in the audio stream, and likewise for pausing/stopping.

!!Health and Safety

Refer to the [[Safety]] article for some important information on avoiding hearing damage.

!!Writing your own audio code

Refer to the [[Extending the Library]] article for information on writing audio streams, driver layers and file codecs.
{{{#include <plaid/audio/effects.h>}}}

A ''Pan'' unit always outputs stereo audio, regardless of input format.  It allows the input sound to be balanced between these two channels.

Presently the internal formula is thus:
{{{left  = level * max(min(1.0 - pan, 1.0), 0.0);}}}
{{{right= level * max(min(1.0 + pan, 1.0), 0.0);}}}
''This formula may be subject to change in future revisions.''


!!Constructor

{{{Pan(Sound source, float panning = 0.0f, float level = 1.0f);}}}
<<<
Creates a new Pan from the given source [[Signal]], with the given panning and volume level, as below.
<<<

!!Member Methods

{{{float pan();}}}
{{{void  pan(float p);}}}
<<<
This [[Property]] represents the stereo balance of the Pan.

The value of{{{ pan }}}ranges from{{{ -1.0 }}}(left only) to{{{ 1.0 }}}(right only).  A value of{{{ 0.0 }}}keeps the volume equal for both ears.
<<<

{{{float level();}}}
{{{void  level(float volume);}}}
<<<
This [[Property]] represents the volume of the Pan.  It is the volume of the louder channel.
<<<

{{{float left();}}}
{{{void  left(float volume);}}}
{{{float right();}}}
{{{void  right(float volume);}}}
<<<
These [[Properties|Property]] directly control the volume of the left and right channels.  {{{pan }}}and{{{ level }}}will change accordingly.
<<<

{{{void rampLinear();}}}
{{{void rampExponential();}}}
<<<
Set the ramping scheme for this Pan, which defaults to linear.  These are equivalent to [[Amp]]'s modes.
Should{{{ left }}}or{{{ right }}}cross zero, ramping is linear for that frame regardless.
<<<
{{{#include <plaid/audio/effects.h>}}}

A ''Pitch'' unit, known properly as a //rate-changing resampler//, is an [[effect|Effects]] makes things higher and faster or slower and deeper, with smooth changes in rate.

It supports ''rate'' and ''semitone'' measures of rate, and ramps between values exponentially.

//Tip:  Setting a Pitch object to a high rate means it will demand huge quantities of audio from its source, which may cause performance problems.
-- Where possible, look for a way to change pitch that doesn't involve producing extra data, such as [[AudioClip]]'s resampling feature.//

!!Constructor

{{{Pitch(Signal source, float rate = 1.0f);}}}
<<<
Creates a new Pitch from the given source [[Signal]] and with the given initial rate.

''Known bug:'' supplying zero or a negative value as the initial rate causes the Pitch to output only silence regardless of further state changes.
<<<

!!Member Methods

{{{float rate();}}}
{{{void  rate(float r);}}}
<<<
This [[Property]] represents the ''resampling rate'' of the Amp -- this multiplier scales the speed with which it plays audio.
Resampling rate is a linear scale, with 0.5 being half speed, 2.0 being double speed, and 1.0 being "normal" speed as if no Pitch was used.
Values equal to or less than zero are not allowed and ''cause a bug'' presently.
<<<

{{{float semitones();}}}
{{{void  semitones(float t);}}}
<<<
This [[Property]] represents the ''musical note'' of the Pitch -- this will move a sound up and down the diatonic scale.
Musical semitones are a logarithmic scale, with 0.0 being "normal" speed, -12.0 being one octave lower, 2.0 being two semitones higher, et cetera.
Setting {{{rate}}} to a value less than or equal to zero will cause calls to {{{semitones()}}} to return {{{-HUGE_VAL}}}.
<<<

{{{void resampling(Uint32 alg);}}}
<<<
Changes the resampling algorithm used internally.
Unfortunately, this ''doesn't do anything'' in the current version of the library; four-point third-order hermite resampling is used regardless.
<<<

!!Related Global Functions

{{{float Semitones(float tones);}}}
{{{float ToSemitones(float rate);}}}
<<<
These functions convert semitone offsets to linear rate and vice versa.
Mind that ~ToSemitones will return strange values for inputs less than or equal to zero.
<<<
A ''property'' is a value of a class which can be accessed with get/set logic.

''Property accessors'', which allow properties to mimic member variables, are a feature which is sorely missing from C++.  It makes [[this developer|Evan]] very sad indeed.

As a result, many classes in the engine expose their properties using this nomenclature:
''Get:''  {{{type propertyName();}}}
''Set:''  {{{void propertyName(type value);}}}

It departs from the standard getX/setX nomenclature as a matter of my own taste, as I originally wrote the library for my own use.  Apologies for any toes this steps on.
{{{#include <plaid/util/ref.h>}}}

The{{{ Ref<T> }}}class is a ''reference-counted pointer'' template used to handle many audio classes in{{{ <plaid/audio>}}}.

It behaves like a regular C++ pointer of type{{{ T* }}}in most regards, but additionally manages a ''reference count'', increasing the count by one with each Ref created or copied and decreasing it whenever a Ref is overwritten or destroyed.  When no more references exist, the count reaches zero and the object is deleted.

This scheme works very well when it is possible for all references to the object to be Refs, with the exception being circumstances where ''cyclic references'' can arise.  The simplest example of this is when one object has a Ref to a second object and the second holds a Ref back to the first.  Thankfully this is not possible with most of the classes in this library -- avoid routing a sound's output directly or indirectly into its input and you are completely safe.

Usage of{{{ Ref<T> }}}requires the managed class (T) to inherit from{{{ RefCounted }}}so it may contain its own reference count.
(The [[Audio]] module and all [[AudioStream]]s inherit from RefCounted.)

A second class,{{{ AutoRef<T>}}}, may be used to manage any other type, but is less safe -- since ~AutoRef must create a reference count separately, it has no way to know if another ~AutoRef is already managing a given object.  Careless use may lead to multiple reference counts, premature destruction of the object and subsequent crashes when trying to access it.  Thus care must be taken that ''only one'' ~AutoRef be constructed from a pointer, and others are copied from that first one.  For this reason, ~AutoRefs will not implicitly construct or cast from pointers; this design choice sacrifices convenience for code safety.

{{{<plaid/audio> }}}makes no use of ~AutoRef objects internally.

//Further documentation on the functions of this class will be available in future releases.  For now refer to the header file.//
{{{#include <plaid/util/ref.h>}}}

A class must inherit from{{{ RefCounted }}}in order to be safely managed by [[Ref]] objects.  If this requirement is cumbersome, however, it may be bypassed by using [[AutoRef|Ref]] objects instead.

Upon creation, a{{{ RefCounted }}}has a reference count of zero.  When a{{{ Ref }}}is bound to it, its reference count increases by one.  When a bound{{{ Ref }}}is destroyed, its reference count decreases by one and, if it returns to zero, the object is{{{ delete}}}d.


!!Advanced Usage
//While they should generally be unnecessary, three methods are available for manual control over and insight into this process.//


{{{RefCount_refCount();}}}
<<<
Returns the current reference count of the object as an unsigned integer.
Assuming no usage of the below functions, this is the number of{{{ Ref }}}pointers currently bound.
<<<

{{{void _retain();}}}
<<<
Increases the reference count by one.
It is occasionally useful to call this when a RefCounted object is stored by value, to ensure bound Refs do not attempt to delete it.
<<<

{{{void _release();}}}
<<<
Decreases the reference count by one and, if it is zero afterwards, deletes the object.
If the reference count was already zero, there is no effect.
<<<
This framework's notion of a ''Reference Type'' is a programming idiom I use to emulate native reference types in Java and C#.

The reference type has an inner class, generally private and called Data.  Data extends [[RefCounted]], and contains all datamembers.

The main class contains a [[Ref<Data>|Ref]] pointer, which may be null, or shared among many instances.

Generally the main class contains a few methods to check its null-ness, or to explicitly create a null instance.
<<<
''Defunct'': This class has been rendered non-functional and will have no effect on audio.
It may be subject to major refactoring in future releases; specifically, the name may be changed to "Delay".
<<<

{{{#include <plaid/audio/effects.h>}}}

The ''Reverb'' class provides spartan delay-line functionality which can be used for reverberation, echo, and comb filter effects.  +++[advanced]
Delay lines are a classical technique in audio engineering and can produce impressive effects such as flange in the hands of a [[knowledgeable|https://ccrma.stanford.edu/~dattorro/EffectDesignPart2.pdf]] user.
Unfortunately this class isn't yet well-suited to these advanced uses.  Keep an eye open for changes in future updates.=== 

!!Constructor

{{{Reverb(Signal source, float dry=1.0f, float wet=.5f, float depth=30.0f);}}}
<<<
Creates a new Reverb from the given source [[Signal]] and with the given initial reverb model, as below.
<<<

!!Automatic Setup

{{{float reverb(float dry=1.0f, float wet=.5f, float depth=30.0f);}}}
<<<
A crass reverberation model which gives charming ambiances ranging from "bathtub drain" to "plastic helmet" to "stone courtyard". +++[reverberation model?]
This method's code calls other methods in the class to set up a reverb effect:
{{{
	clearDelays();
	addDelaySamples(0, dry);

	float baseDelay = depth / 343.0f;

	addDelaySeconds(baseDelay * .14286f, -.2f * wet);
	addDelaySeconds(baseDelay * .40138f, +.3f * wet);
	addDelaySeconds(baseDelay * .38797f, +.1f * wet);
	addDelaySeconds(baseDelay * .67191f, -.4f * wet);
	addDelaySeconds(baseDelay, .1f * wet);
}}}
=== 

{{{dry }}}is the volume of the original signal.  Lower values will tend to make the sound seem more distant or indirect.
{{{wet }}}modulates the volume of the delay lines, and controls the power of the reverberations.
{{{depth }}}changes the apparent size, in meters, of the reverberant space.  Don't expect a great deal of realism.

''This model may be subject to later revision'' -- if you should manage fall in love with it, I suggest making your own copy of the class or setting your delay lines up manually.
<<<

{{{void echo(float distance, float decay);}}}
<<<
Creates a simple repeating echo effect, with the echo coming from the given{{{ distance }}}in meters and being attenuated by{{{ decay }}}each time.

Values with a magnitude somewhat less than{{{ 1.0 }}}are strongly recommended.  If the echoes are not quieter than the original, things will get [[very loud|Safety]].
<<<

!!Manual Setup

{{{void clearDelays();}}}
<<<
Erases all delay lines in the Reverb and resets it.
<<<

{{{void addDelaySeconds(float seconds, float amp);}}}
<<<
<<<

{{{void addDelaySamples(Uint32 samples, float amp);}}}
Bad audio code can be ''bad for your ears'' -- something that might not occur to the first-time audio programmer.

Too much sound delivered through headphones can cause tinnitus, damage the bones of the inner ear and do all sorts of other awful things.
Don't write bad audio code, or you might find yourself or your users ripping your headphones off in pain and surprise.
This library [[cannot be held liable|License]] for any such misfortune.

!Tips

+ Always ''turn your volume down'' when testing new code, and //especially// when writing [[your own DSPs|Extending the Library]].  A buffer overflow or degenerate math function [[sounds neat|Glitches]] but not when your ears are bleeding.

+ Your primary enemy is too much ''amplitude'', but it's also important to know that some ''frequencies'' will sound louder than others -- any given speaker or microphone has a different frequency spectrum, and even the human ear is much more sensitive to some frequencies than others (maxing out around 3700 hz).

+ Almost all forms of amplification in the library are ''unbounded'', meaning you can make sounds louder than 100%.  Be careful that the numbers you're sending the engine don't get out of control.

+ It might not be a loud sound but ''too many'' small sounds that cause problems.  The [[Mixer]] class places no limit on how many sounds can be played so this can happen easily.  Too many sound sources in one place or the mistake of playing a sound every frame are likely causes.

+ Consider using a [[Limiter]] as a failsafe against volume explosions.
A ''Scheduler'' is used internally by the [[Audio]] module to perform time-slicing of the audio stream and synchronization with the controlling thread.
It is the consumer of the master mixer and ultimately handles all audio input from and output to the [[Driver]].

!Writing schedulers
<<<
''Advanced users' topic'':  This section is of interest mainly to programmers who are writing [[extensions|Extending the Library]] to{{{ <plaid/audio>}}}.
<<<

//This section will eventually cover the process of writing a scheduler for the framework.  Until it does, try dissecting the provided one.//
<<tabs txtMainTab "Tags" "All tags" TabTags "All" "All tiddlers" TabAll "More" "More lists" TabMore "Timeline" "Timeline" TabTimeline>>
{{{#include <plaid/audio/stream.h>}}}

This class is used by audio effects, [[schedulers|Scheduler]] and any other processes which need to pull audio data from an [[AudioStream]].
It reserves the stream -- only one consumer may pull from a stream at a time -- and possibly attaches a [[Transcoder]] in order to change the stream's [[format|AudioFormat]] to a desirable one.

!!Usage

<<<
''Advanced users' topic'':  this is of interest mainly to programmers who are writing [[extensions|Extending the Library]] to{{{ <plaid/audio>}}}.
<<<

//Further documentation on the functions of this class will be available in future releases.  For now refer to the header file.//
<<<
Silence is golden.  Duct tape is silver.
<<<

{{{#include <plaid/audio/synth.h>}}}

A simple synth which is useful in certain situations.  Generates an endless stream of zero samples and never [[exhausts|Exhaustion]].

!!Constructor

{{{Silence(AudioFormat format);}}}
<<<
Creates a Silence generator with the given output [[format|AudioFormat]].

The only real importance of the specified format is to avoid the unnecessary overhead of attaching a [[Transcoder]].
<<<
{{{0.2.0 }}}-- a free, portable and powerful software audio framework -- written by Evan Balster
{{{<plaid/audio>}}}
{{{#include <plaid/audio/stream.h>}}}

The ''Sound'' type can be used to refer to and memory-manage any type of sound class written in{{{ <plaid/audio> }}}.

It's actually just a C++ type-alias, though:{{{ typedef Ref<AudioStream> Sound; }}}is its declaration.

See the [[Ref]] article and optionally the [[AudioStream]] article for more information on their meanings.
{{{#include <plaid/audio/util.h>}}}

A ''Splicer'' allows sounds to be sequenced precisely, such that when one [[exhausts|Exhaustion]] the next begins.  This is useful in a wide variety of situations, including music which has an "intro" track and a "loop" track.

When its supply of Sounds runs out, a Splicer will itself [[exhaust|Exhaustion]].

!!Constructor

{{{Splicer(AudioFormat format);}}}
<<<
Create an empty Splicer with the given [[format|AudioFormat]].
<<<

{{{Splicer(Sound first);}}}
<<<
Create a splicer with the given first sound -- this sound's [[format|AudioFormat]] will be the output format of the splicer.
<<<

{{{Splicer(Sound first, Sound second);}}}
<<<
Splice two sounds together -- the first Sound's [[format|AudioFormat]] is used.
<<<

!!Member methods

{{{void add(Sound source);}}}
<<<
Adds a Sound to the end of this Splicer's list.
<<<
{{{#include <plaid/audio/util.h>}}}

An [[AudioStream]]'s output must be bound using a [[Signal]] object when a consumer -- usually another stream -- wants to use it.  Only one such binding can exist at a given time.
A ''Splitter'' allows this rule to be bypassed under favorable conditions -- it can be copied so as to share data between multiple consumers.

Splitters are essential in the creation of [[Multi-Band]] effects.

In order to safely use a Splitter, a few conditions need to be met.  It is up to the user to ensure the following:
* All consumers stem from the same [[process|Scheduler]].  For instance, if one copy of a Splitter is played to the speakers, all other copies should be fed to consumers that ultimately route to the speakers.
* All consumers pull audio at the same rate.  Doubling the pitch -- and thus the consumption rate -- of one copy of a Splitter will put it at odds with other copies which output at the normal rate, and unpleasant (though non-fatal) [[Glitches]] will ensue.
* No consumer will in a single pull request more audio than fits in the Splitter's{{{ capacity}}}.  Failing this, non-fatal [[Glitches]] will occur.

Despite the gravity of these warnings, it's generally quite easy to use Splitters safely.

!!Constructor

{{{Splitter(Signal source, Uint32 capacity = 12000);}}}
<<<
Create a new Splitter from the given source and with the given capacity in samples per channel.  The default value tends to suffice.
<<<

{{{Splitter(Splitter *other);}}}
<<<
Splits{{{ other}}}, producing a new copy of the stream which may be given to another consumer.
<<<

!!Member Methods

{{{Splitter *copy();}}}
<<<
Splits this Splitter, producing a new copy of the stream which may be fed to another consumer.
<<<
.viewer {font-size:1.1em;}

hr.postbreaker {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.tagged li, .tagged ul {display:inline;}

.viewer code {font-size:1.3em; line-height:1.2em;}

.subtitle {float:right; opacity:0.5;}
{{{#include <plaid/audio/synth.h>}}}

An ''audio synth'' creates sound data from scratch, using an algorithm of some kind.

{{{<plaid/audio> }}} provides a [[base template|AudioSynth]] and a number of common synths in this header.

''Built-in synths:''
* [[Silence]] -- ...
* [[Oscillator]] -- Creates a tone whose frequency and waveform can be changed.

''Non-functioning synths:''
* //Noise// -- Forthcoming.  Will generate pink and white noise.
* //Impulse// -- Forthcoming.  Will generate sonic impulses, audible as clicks and pops.
A ''TiddlyWiki'' is a weird sort of thing -- a wiki contained in a single HTML file that can be easily distributed.
It requires a relatively modern browser to use.

Its habit of opening new pages without closing the old and forming a column can be a bit off-putting at first but becomes more agreeable with use.

Also, for some reason the pages are called "Tiddlers", which is an immensely bizarre word.
{{{#include <plaid/audio/util.h>}}}

In all likelihood, ''Transcoder''s will be used in your sound system whether you reference them or not.  Their purpose is to change audio from one [[format|AudioFormat]] to another, and this is done automatically whenever a [[Signal]] is bound to an output format other than that of the stream it's pulling from.

Transcoders transform audio data in two ways:  They change the number of channels by splitting or downmixing them, and they change the sampling rate by resampling.  The latter is done using a [[Pitch]] effect.

!!Constructor

{{{Transcoder(Signal source, AudioFormat dest);}}}
<<<
Create a transcoder which transforms the{{{ source }}}stream into the{{{ dest}}}ination format.  This generally happens automatically.
<<<
Let's get you started with your first{{{ <plaid/audio> }}}program!
This tutorial assumes the user is using Windows, OS X or some kind of Unix.

First, you'll need to get set up to compile the library into your program.

''Proper build setup:''
# Follow the [[Installation]] instructions to build a static library.
# Set your project up to link with the static library you built and one of the libs from the{{{ portaudio }}}folder.*
# Place the{{{ plaid }}}and{{{ portaudio }}}folders from your distibution in your include path.
# Copy the{{{ imp-portaudio }}}and{{{ codec_stb}}} directories into your project folder.  ^^(These are a [[driver layer|Driver]] and an ogg [[audio codec|Codec]])^^
# Add the contents of these folders to your project as source files.


Great!  You're ready to get coding.  Copy this code into a new file in your project:

{{{
#include <iostream>
#include <plaid/audio.h>
#include <plaid/audio/synth.h>

using namespace plaid;

int main(int argc, char **argv)
{
    //Create an audio engine with default settings.
    Audio audio;

    //Create a sine wave Oscillator and store it in a Ref.
    Ref<Oscillator> oscillator = new Oscillator(audio.format(), 440.0f, Oscillator::SINE, .05f);

    //Play the oscillator
    audio.play(oscillator);

    while (true)
    {
        //Update the audio system so that changes to our audio are applied.
        //Ideally this should happen regularly, for example every frame of a game.
        audio.update();

        //Prompt the user for a new frequency, and quit on invalid input.
        int freq = 0;
        std::cout << "Enter new frequency:" << std::endl;
        std::cin >> freq;
        if (freq == 0) break;
        oscillator->frequency(freq);
    }
}
}}}

A piece of advice:  It's good to [[turn your volume down|Safety]] before you test out new audio code.  That oscillator might be louder than you expect!

If all has been done correctly the program should build and run!
Beginner users should proceed to the [[Basics]] article.
Advanced users can skip to [[Overview]] and [[API Reference]].


^^* The supplied portaudio lib for Windows contains support for ASIO, a non-free audio API which may have unpleasant licensing implications on software which supports it.  You will likely want to build your own version of portaudio for the purpose of your software development.^^
{{{#include <plaid/audio/util.h>}}}

The classes collected here perform a host of useful general-purpose audio rendering functions.

''Classes:''
* [[Mixer]] -- Mixes any number of streams together, and facilitates pausing and volume adjustment.
* [[Splicer]] -- Plays sounds in sequence, starting each as the previous one [[exhausts|Exhaustion]].  Useful for intro-loop behaviors.
* [[Splitter]] -- Allows a signal to be sent to several destinations at once.  Useful for [[Multi-Band]] effects and analysis.
* [[Transcoder]] -- Resamples a signal to a different [[format|AudioFormat]].  Often created automatically.

''Advanced'':
* [[HackStream]] -- Used in custom DSP programming to trick an [[AudioStream]] into processing data in-place.
!0.2.0 -- June 02, 2013
This release added documentation to the library.  Good documentation is a //lot of work//, which is why it took so long.

!!API
* The [[AudioClip]] class is now usable, though incomplete.
* Changed [[Ref]]<T> class to be easier to use, allowing implicit conversion from pointers.  It now works only with [[RefCounted|Ref]] subclasses, with [[AutoRef|Ref]]<T> replacing it for use with other classes.
* Changed the constructor of [[Mixer]] to have an ''exhaustible'' option -- if enabled, the mixer will [[exhaust|Exhaustion]] like a sound clip does when it is no longer playing any streams.
* Refactored the ''Bandpass'' class into the [[Filter]] class, with several changes to its interface.
* Added the fabulously useful [[Splitter]] class.
* Fixed the issues in [[Oscillator]].
* Added {{{analysis.h}}} and the [[Envelope]] stream.
* Added {{{scratch.h}}} to facilitate manual audio rendering.

!!Bugfixes
* Fixed a critical bug which caused the mixer to freeze when scratch memory was running low.
* Fixed various behavior bugs in Mixer.
* Configured the provided MSVC project to build a static library and separated the example program into a separate project.
* Fixed a bug which caused audio to fuzz out when the Mixer's oldest sound was set to volume zero.

!!Portability
* Improved the Ref<T> code for compatibility with clang (Xcode).

!0.1.0 -- December 04, 2012

First standalone version of plaid/audio.
Includes portaudio implementation and stb_vorbis.c codec.

Includes: [[Pitch]], [[Amp]], [[Pan]], ''Bandpass'', [[Mixer]], [[Splicer]], [[Oscillator]], [[AudioClip]], among a few other utility classes.

[[AudioClip]] is presently functional but incomplete.
[[Oscillator]] is presently functional but just awful at anything besides sines.
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span></div>
<div class='tagging' macro='tagging'></div>
<br>
<div class='viewer' macro='view text wikified'></div>
<br>
<div class='tagged' macro='tags'></div>
<br>
<hr class='postbreaker'>
<div class='tagClear'></div>
<!--}}}-->
<<<
''Advanced users' topic'':  this is of interest mainly to programmers who are writing [[extensions|Extending the Library]] to{{{ <plaid/audio>}}}.
<<<

''Waiting'' is when an irregular event of some kind causes an unusual delay in the audio stream, particularly when the delay involves waiting on other code through mechanisms such as locking mutexes, but also due to occasional expensive operations such as vector resizing, memory allocation or large-buffer fourier transforms.  If these delays approach or exceed the amount of time allotted to the audio callback they will cause glitches.
It is ''bad news'' for realtime audio and should be a point of caution.

For now please refer to [[Ross Bencina's excellent writeup on this topic|http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing]].

Note that the included OGG codec presently breaks one of these rules by streaming file data from disk without buffering.  How horrifying!
In practice this hasn't been problematic except on mobile platforms.
!!!!Welcome to the {{{<plaid/audio>}}} docs!
{{{<plaid/audio>}}} is a portable, extensible C++ framework for realtime audio processing.
It is designed chiefly for use in games and other media-intensive software.
This HTML file is a self-contained TiddlyWiki covering the usage of the library.

If it's your first time here, you might need to [[compile|Installation]] the library or check its [[license|License]].

Once that's done, you'll probably want to [[get it running|Tutorial]] in your program and [[learn the basics|Basics]] of its use.

After that, you can acquaint yourself with its [[design|Overview]] and [[classes|API Reference]].

And if its capabilities aren't enough for you, you might want to [[extend|Extending the Library]] the library or find [[someone|Evan]] who can.


//(Tired of this article sitting around?  Use the "close" button at the top right to banish it!)//
Most likely this user is [[Evan]] and he simply forgot to enter his name at the start of a doc-writing session.
Type the text for 'excludeLists'
Type the text for 'excludeSearch'
Type the text for 'systemConfig'