summaryrefslogtreecommitdiff
path: root/extsnd.html
diff options
context:
space:
mode:
authorAlessio Treglia <quadrispro@ubuntu.com>2009-10-19 09:55:11 +0200
committerAlessio Treglia <quadrispro@ubuntu.com>2009-10-19 09:55:11 +0200
commit5cd66eecc95be11cacc5aaf4db8c67a499bb2d4d (patch)
treef9fe35437c9a69b886676bbdeff692ebc728bec2 /extsnd.html
Imported Upstream version 11
Diffstat (limited to 'extsnd.html')
-rw-r--r--extsnd.html13944
1 files changed, 13944 insertions, 0 deletions
diff --git a/extsnd.html b/extsnd.html
new file mode 100644
index 0000000..871e1e5
--- /dev/null
+++ b/extsnd.html
@@ -0,0 +1,13944 @@
+<html>
+<head>
+<title>Snd Customization and Extension</title>
+<style type="text/css">
+<!--
+ EM.red {color:red; font-style: normal}
+ EM.error {color:chocolate; font-style: normal}
+ EM.narg {color:chocolate; font-style: normal}
+ EM.typing {color:maroon; font-style: normal}
+ EM.listener {color:darkblue; font-style: normal}
+ H1 {text-align: center}
+ UL {list-style-type: none}
+ EM.emdef {font-weight: bold; font-style: normal}
+
+ A {text-decoration:none}
+ A:hover {text-decoration:underline}
+ A.quiet {color:black; text-decoration:none}
+ A.quiet:hover {text-decoration:underline}
+ A.def {font-weight: bold; font-style: normal; text-decoration:none; text-color:black}
+-->
+</style>
+</head>
+
+<!-- other possible tooltips: file-exists? delete-file procedure-with-setter define* list-set! load-from-path
+ delete-file system remove-hook! throw copy-file
+ ruby examples?
+ sndscm.html: normalize-partials
+ add-main-pane
+-->
+
+<body bgcolor=white>
+
+<script language=JavaScript type="text/javascript" src="wz_tooltip.js"></script>
+<script language=JavaScript type="text/javascript" src="wz_data.js"></script>
+
+<!-- I'm using A NAME (i.e caps) where the entity should be ignored by the indexer (index.cl) -->
+
+<A NAME="extsndcontents"></a>
+<table border=0 bordercolor="lightgreen" width=100% cellpadding=2 cellspacing=0><tr><td bgcolor="lightgreen">
+<table width="100%" border=0><tr>
+<td bgcolor="beige" align="center" valign="middle"><h1>Snd Customization and Extension</h1></td>
+</tr></table>
+</td></tr></table>
+<br>
+
+<center>
+<table bgcolor="aliceblue" border=0 cellspacing=8><tr>
+<td><small>related documentation:</small></td>
+<td><small><a href="snd.html" onmouseout="UnTip()" onmouseover="Tip(snd_html_tip)">snd.html</a></small></td>
+<td><small><a href="grfsnd.html" onmouseout="UnTip()" onmouseover="Tip(grfsnd_html_tip)">grfsnd.html</a></small></td>
+<td><small><a href="sndscm.html" onmouseout="UnTip()" onmouseover="Tip(sndscm_html_tip)">sndscm.html</a></small></td>
+<td><small><a href="sndclm.html" onmouseout="UnTip()" onmouseover="Tip(sndclm_html_tip)">sndclm.html</a></small></td>
+<td><small><a href="fm.html" onmouseout="UnTip()" onmouseover="Tip(fm_html_tip)">fm.html</a></small></td>
+<td><small><a href="sndlib.html" onmouseout="UnTip()" onmouseover="Tip(sndlib_html_tip)">sndlib.html</a></small></td>
+<td><small><a href="libxm.html" onmouseout="UnTip()" onmouseover="Tip(libxm_html_tips extension language')">libxm.html</a></small></td>
+<td><small><a href="s7.html" onmouseout="UnTip()" onmouseover="Tip(s7_html_tip)">s7.html</a></small></td>
+<td><small><a href="index.html" onmouseout="UnTip()" onmouseover="Tip(index_html_tip)">index.html</a></small></td>
+</tr></table>
+</center>
+
+
+<table border=0 cellpadding=5 vspace=10 hspace=20>
+<tr><th>this file:</th><th>grfsnd.html:</th></tr>
+<tr><td width="40%">
+<ul>
+<li><a href="#lisplistener">Introduction</a>
+<li><a href="#etc">Snd Programming</a>
+ <ul>
+ <li><a href="#behavior">Customizing Snd's behavior</a>
+ <ul>
+ <li><a href="#sndglobalvars">Global variables</a>
+ <li><a href="#sndgenericfuncs">Generic functions</a>
+ <li><a href="#sndhooks" onmouseout="UnTip()" onmouseover="Tip('callbacks')">Hooks</a>
+ </ul>
+ <li><a href="#sndobjects">Snd's objects</a>
+ <ul>
+ <li><a href="#samplers" onmouseout="UnTip()" onmouseover="Tip('sound data iterators', WIDTH, 200)">Samplers</a>
+ <li><a href="#Vcts" onmouseout="UnTip()" onmouseover="Tip('real arrays', WIDTH, 100)">Vcts</a>
+ <li><a href="#sndsounddata" onmouseout="UnTip()" onmouseover="Tip('arrays of vcts for multichannel data')">Sound-data</a>
+ <li><a href="#extsndlib" onmouseout="UnTip()" onmouseover="Tip('the underlying library that handles sound data and files')">Sndlib</a>
+ <li><a href="#sndmarks" onmouseout="UnTip()" onmouseover="Tip('location markers in sound data')">Marks</a>
+ <li><a href="#sndmixes" onmouseout="UnTip()" onmouseover="Tip('mixed sounds and groups of mixed sounds')">Mixes</a>
+ <li><a href="#sndregions" onmouseout="UnTip()" onmouseover="Tip('selected or saved portions of sound data')">Regions and Selections</a>
+ <li><a href="#sndsounds" onmouseout="UnTip()" onmouseover="Tip('editing functions, per-channel display decisions, etc')">Sounds and channels</a>
+ <ul>
+ <li><a href="#customcontrols" onmouseout="UnTip()" onmouseover="Tip('a set of common sound effects below the main graph')">the control panel</a>
+ <li><a href="#editlists" onmouseout="UnTip()" onmouseover="Tip('current edit sequence', WIDTH, 200)">edit lists</a>
+ </ul>
+ <li><a href="#sndtransforms" onmouseout="UnTip()" onmouseover="Tip('Fourier transform, wavelets, autocorelation, etc')">Transforms</a>
+ <li><a href="#snddialogs" onmouseout="UnTip()" onmouseover="Tip('customizing the built-in dialogs, etc')">Dialogs and Other Widgets</a>
+ <li><a href="#sndmisc" onmouseout="UnTip()" onmouseover="Tip('bind-key, exit, etc')">Miscellaneous functions</a>
+ <li><a href="#sndconstants">Constants</a>
+ <li><a href="#snderrors">Errors and Debugging</a>
+ </ul>
+ <li><a href="#appearance">Customizing Snd's appearance</a>
+ <ul>
+ <li><a href="#colors">Colors</a>
+ <li><a href="#fonts">Fonts</a>
+ <li><a href="#graphics" onmouseout="UnTip()" onmouseover="Tip('write your own sound display functions or customize Snd\'s')">Graphics</a>
+ </ul>
+ </ul>
+</ul>
+</td><td width="40%">
+
+<ul>
+<li><a href="grfsnd.html#startup">Snd Startup</a>
+ <ul>
+ <li><a href="grfsnd.html#sndswitches" onmouseout="UnTip()" onmouseover="Tip('startup switches such as -l and -p')">Snd invocation flags</a>
+ <li><a href="grfsnd.html#sndinitfile" onmouseout="UnTip()" onmouseover="Tip('~/.snd, ~/.snd_guile, ~/.snd_prefs_guile, etc')">The initialization file</a>
+ <li><a href="grfsnd.html#sndresources" onmouseout="UnTip()" onmouseover="Tip('X resources: Xdefaults, gtkrc')">Snd resources</a>
+ <li><a href="grfsnd.html#sndconfigurationswitches" onmouseout="UnTip()" onmouseover="Tip('this refers to the configure script that prepares a makefile to build Snd from its sources')">Configuration choices</a>
+ <li><a href="grfsnd.html#sndenvvars" onmouseout="UnTip()" onmouseover="Tip('mostly related to audio hardware choices')">Environment variables</a>
+ </ul>
+<li><a href="grfsnd.html#snddynamic">Runtime modules and external programs</a>
+ <ul>
+ <li><a href="grfsnd.html#emacssnd" onmouseout="UnTip()" onmouseover="Tip('Use Emacs as the listener')">Snd as an Emacs subjob</a>
+ <li><a href="grfsnd.html#dynamic" onmouseout="UnTip()" onmouseover="Tip('Load your own C code into Snd')">Dynamically loaded modules</a>
+ <li><a href="grfsnd.html#programs" onmouseout="UnTip()" onmouseover="Tip('Use independent programs to perform editing operations')">External Programs</a>
+ <li><a href="grfsnd.html#sndaswidget" onmouseout="UnTip()" onmouseover="Tip('Embed Snd in some other program')">Snd as a Widget</a>
+ <li><a href="grfsnd.html#sndwithclm" onmouseout="UnTip()" onmouseover="Tip('CLM is built into Snd')">Snd and CLM</a>
+ <li><a href="grfsnd.html#sndwithcm" onmouseout="UnTip()" onmouseover="Tip('CM is Rick Taube\'s composition environment')">Snd and Common Music</a>
+ <li><a href="grfsnd.html#sndwithpd" onmouseout="UnTip()" onmouseover="Tip('PD is Miller Puckette\'s synthesis and composition program')">Snd and Pd</a>
+ <li><a href="grfsnd.html#sndwithmotif" onmouseout="UnTip()" onmouseover="Tip('Motif extensions from xm.c')">Snd and Motif</a>
+ <li><a href="grfsnd.html#sndwithgtk" onmouseout="UnTip()" onmouseover="Tip('Gtk extensions from xg.c')">Snd and Gtk</a>
+ <li><a href="grfsnd.html#sndwithnogui">Snd with no GUI and as script engine</a>
+ <li><a href="grfsnd.html#sndandruby" onmouseout="UnTip()" onmouseover="Tip('Ruby is a scripting/extension language somewhat like Python')">Snd with Ruby</a>
+ <li><a href="grfsnd.html#sndandforth" onmouseout="UnTip()" onmouseover="Tip('Forth is a postfix extension language')">Snd with Forth</a>
+ <li><a href="grfsnd.html#sndands7" onmouseout="UnTip()" onmouseover="Tip('s7 is yet-another Scheme extension language')">Snd with s7</a>
+ <li><a href="grfsnd.html#sndandguile" onmouseout="UnTip()" onmouseover="Tip('Guile is yet-another Scheme extension language')">Snd with Guile</a>
+ <li><a href="grfsnd.html#sndandladspa" onmouseout="UnTip()" onmouseover="Tip('This is a Linux-based sound-effects plugin system')">Snd and LADSPA plugins</a>
+ <li><a href="grfsnd.html#sndandalsa" onmouseout="UnTip()" onmouseover="Tip('This is the no-longer-very-new Linux audio library')">Snd and ALSA</a>
+ <li><a href="grfsnd.html#sndandjack" onmouseout="UnTip()" onmouseover="Tip('This is the Jack audio library')">Snd and Jack</a>
+ <li><a href="grfsnd.html#sndandx" onmouseout="UnTip()" onmouseover="Tip('other programs can control Snd through window properties')">Driving Snd remotely</a>
+ <li><a href="grfsnd.html#sndandgl" onmouseout="UnTip()" onmouseover="Tip('OpenGL (Mesa) extensions via gl.c')">Snd and OpenGL</a>
+ <li><a href="grfsnd.html#sndandgsl" onmouseout="UnTip()" onmouseover="Tip('include some special functions from GSL')">Snd and GSL</a>
+ <li><a href="grfsnd.html#sndandgmp" onmouseout="UnTip()" onmouseover="Tip('build s7 with gmp, mpfr, mpc')">Snd and multiprecision arithmetic</a>
+ </ul>
+<li><a href="index.html">Index</a>
+</ul>
+</td></tr></table>
+<br><br>
+
+<table border=0 bordercolor="lightgreen" width=100% cellpadding=1 cellspacing=0><tr><td bgcolor="lightgreen">
+<table width="100%" border=0><tr><td bgcolor="beige" align="center" valign="middle"><h2>Introduction</h2></td></tr></table>
+</td></tr></table>
+
+<A NAME="lisplistener"></a>
+
+<p>Snd is a highly customizable, extensible program.
+I've tried to bring out to the extension language nearly every portion
+of Snd, both the signal-processing functions and
+much of the user interface. You can, for example,
+add your own menu choices, editing operations,
+or graphing alternatives.
+Nearly everything in Snd can be set in an initialization
+file, loaded at any time from a text file of program code, or specified in a <a href="snd.html#savedstate">saved state</a> file.
+It can also be set
+via inter-process communication or from stdin
+from any other program (CLM and Emacs in particular),
+embedded in a keyboard macro, or typed in the
+listener.
+</p>
+<p>
+The syntax used throughout this documentation is Scheme (a form of lisp) as implemented by s7.
+You can also use Ruby or Forth, but need to make various minor <a href="grfsnd.html#sndandruby">changes</a>.
+I'm slowly adding parallel Forth and Ruby examples.
+</p>
+
+<p>
+The easiest way to get acquainted
+with this aspect of Snd is to open the listener
+(via the View:Open listener menu option), and type
+experiments in its window. Its prompt is "&gt;". So,
+say we've opened the listener (my typing is
+in <em class=typing>this color</em> and Snd's responses
+are in <em class=listener>this color</em>):
+</p>
+
+<table border=0 cellspacing=10>
+<tr><th bgcolor="#f2f4ff" align=left>Scheme</th><th></th><th bgcolor="beige" align=left>Ruby</th><th></th><th bgcolor="lightgreen" align=left>Forth</th></tr>
+
+<tr>
+<td bgcolor="#fbfbff"><pre>
+&gt;<em class=typing>(+ 1 2)</em>
+<em class=listener>3</em>
+</pre></td><td width=60></td>
+
+<td bgcolor="#FdFdf2"><pre>
+&gt;<em class=typing>1+2</em>
+<em class=listener>3</em>
+</pre></td><td width=60></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>1 2 +</em>
+<em class=listener>3</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+<tr>
+<td bgcolor="#fbfbff" onmouseout="UnTip()" onmouseover="Tip('this opens oboe.snd; the &quot;0&quot; returned is the new sound\'s \'index\'')"><pre>
+&gt;<em class=typing>(open-sound "oboe.snd")</em>
+<em class=listener>#&lt;sound 0&gt;</em>
+</pre></td><td></td>
+
+<td bgcolor="#FdFdf2"><pre>
+&gt;<em class=typing>open_sound("oboe.snd")</em>
+<em class=listener>0</em>
+</pre></td><td></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>"oboe.snd" open-sound</em>
+<em class=listener>0</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+<tr>
+<td bgcolor="#fbfbff" onmouseout="UnTip()" onmouseover="Tip('#t = true, #f = false in Scheme and Forth')"><pre>
+&gt;<em class=typing>(auto-resize)</em>
+<em class=listener>#t</em>
+</pre></td><td></td>
+
+<td bgcolor="#FdFdf2"><pre>
+&gt;<em class=typing>auto_resize</em>
+<em class=listener>true</em>
+</pre></td><td></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>auto-resize</em>
+<em class=listener>#t</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+<tr>
+<td bgcolor="#fbfbff"><pre>
+&gt;<em class=typing>(set! (auto-resize) #f)</em>
+<em class=listener>#f</em>
+</pre></td><td></td>
+
+<td bgcolor="#FdFdf2"><pre>
+&gt;<em class=typing>set_auto_resize false</em>
+<em class=listener>false</em>
+</pre></td><td></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>#f set-auto-resize</em>
+<em class=listener>#f</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+<tr>
+<td bgcolor="#fbfbff"><pre>
+&gt;<em class=typing>(set! (x-bounds) '(0.0 1.0))</em>
+<em class=listener>(0.0 1.0)</em>
+</pre></td><td></td>
+
+<td bgcolor="#FdFdf2" onmouseout="UnTip()" onmouseover="Tip('Ruby runs array elements together in printout: &quot;0.01.0&quot; should be &quot;0.0 1.0&quot;')"><pre>
+&gt;<em class=typing>set_x_bounds([0.0, 1.0])</em>
+<em class=listener>0.01.0</em>
+</pre></td><td></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>'( 0.0 1.0 ) set-x-bounds</em>
+<em class=listener>'( 0.0 1.0 )</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+<tr>
+<td bgcolor="#fbfbff" onmouseout="UnTip()" onmouseover="Tip('this is Scheme\'s way of saying the previous evaluation returned no newsworthy result.')"><pre>
+&gt;<em class=typing>(load "bird.scm")</em>
+<em class=listener>make-birds</em>
+</pre></td><td></td>
+
+<td bgcolor="#FdFdf2"><pre>
+&gt;<em class=typing>load "bird.rb"</em>
+<em class=listener>true</em>
+</pre></td><td></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>"bird.fs" file-eval</em>
+<em class=listener>0</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+<tr>
+<td bgcolor="#fbfbff"><pre>
+&gt;<em class=typing>(map-channel (lambda (y) (* y 2)))</em>
+<em class=listener>0</em>
+</pre></td><td></td>
+
+<td bgcolor="#FdFdf2"><pre>
+&gt;<em class=typing>map_channel(lambda do |y| y * 2 end)</em>
+<em class=listener>-0.0015869140625</em>
+</pre></td><td></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>lambda: &lt;{ y }&gt; y 2.0 f* ; map-channel</em>
+<em class=listener>-0.00158691</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+<tr>
+<td bgcolor="#fbfbff"><pre>
+&gt;<em class=typing>(define (plus a b) (+ a b))</em>
+<em class=listener>plus</em>
+</pre></td><td></td>
+
+<td bgcolor="#FdFdf2"><pre>
+&gt;<em class=typing>def plus(a, b) a+b end</em>
+
+</pre></td><td></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>: plus ( a b -- sum ) { a b } a b + ;</em>
+<em class=listener>nil</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+<tr>
+<td bgcolor="#fbfbff"><pre>
+&gt;<em class=typing>(set! (basic-color) (make-color 1 0 0))</em>
+<em class=listener>(Pixel 16711680)</em>
+</pre></td><td></td>
+
+<td bgcolor="#FdFdf2"><pre>
+&gt;<em class=typing>set_basic_color make_color(1, 0, 0)</em>
+<em class=listener>[:Pixel, 16711680]</em>
+</pre></td><td></td>
+
+<td bgcolor="#EefdEe"><pre>
+&gt;<em class=typing>1 0 0 make-color set-basic-color</em>
+<em class=listener>#&lt;XmRaw: Pixel 0x9d3b430&gt;</em>
+</pre></td>
+</tr>
+<!-- ------------ -->
+
+</table>
+
+<p>Another quick way to check out the extension language is to go to the
+Preferences dialog (in the Options menu), choose some items, then
+save them. The saved file (~/.snd_prefs_s7 for example) is a text file, a program in the current
+extension language, that initializes Snd to use whatever items you chose.
+</p>
+
+<blockquote>
+<p><small>If the listener is active, and some sound
+is selected, any characters typed while in the sound
+graph which it can't handle are passed to the
+listener; to exit the listener without using the
+mouse, type C-g. This is also the way to get back to
+the listener prompt if it appears to be hung; normally
+in this situation,
+it's actually waiting for a close paren; if you put the
+cursor just past the close paren you're interested in
+and type return,
+Snd will flash the unbalanced open paren (if any) briefly.
+In any case, whenever the cursor is just past a close paren,
+the matching open paren is underlined.
+</small></p>
+</blockquote>
+
+<br>
+
+<table border=0 bordercolor="lightgreen" width=100% cellpadding=1 cellspacing=0><tr><td bgcolor="lightgreen">
+<table width="100%" border=0><tr><td bgcolor="beige" align="center" valign="middle"><h2><A NAME="etc">Snd Programming</a></h2></td></tr></table>
+</td></tr></table>
+
+<p>Snd is organized as a list of sounds, each with a list of channels,
+each channel containing lists of edits, marks, mixes, etc.
+There are other objects such as colors, vcts (an optimization
+of vectors), and regions; the currently active region is
+called the selection. I originally presented all the
+functions and variables in an enormous alphabetical
+list, but that finally became unmanageable. In the following
+sections, each of the basic entities is treated in a separate
+section with cross-references where needed. The <a href="index.html">index</a>
+provides alphabetical entry.</p>
+
+<p>There are many examples in <a href="sndscm.html#exampdoc">examp.scm, examp.rb, examp.fs</a>,
+and <a href="sndscm.html#sndtestdoc">snd-test.scm</a>.
+Extensions to Snd can be found in:
+</p>
+
+
+<table border=8 bordercolor="lightsteelblue" cellpadding=6 hspace=20><tr><td>
+<table border=0 cellspacing=0 cellpadding=2>
+<tr><th colspan=2 bgcolor="beige">Contents</th></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#analogfilterdoc">analog-filter</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(analog_filter_doc_tip)">standard IIR filters</td></tr>
+
+<tr><td><a href="sndscm.html#animalsdoc">animals</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(animals_doc_tip)">a bunch of animals</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#autosavedoc">autosave</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(autosave_doc_tip)">auto-save (edit backup) support</td></tr>
+
+<tr><td><a href="sndscm.html#bessdoc">bess</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(bess_doc_tip)">FM demo</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#birddoc">bird</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(bird_doc_tip)">North-American birds</td></tr>
+
+<tr><td><a href="sndscm.html#cleandoc">clean</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(clean_doc_tip)">noise reduction</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#clminsdoc">clm-ins, clm23</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(clm_ins_doc_tip)">various CLM instruments</td></tr>
+
+<tr><td><a href="sndscm.html#dlocsigdoc">dlocsig</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(dlocsig_doc_tip)">moving sounds (Michael Scholz)</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#drawdoc">draw</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(draw_doc_tip)">graphics additions</td></tr>
+
+<tr><td><a href="sndscm.html#dspdoc">dsp</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(dsp_doc_tip)">various DSP-related procedures</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#dotsnd">edit123.scm, snd_conffile.scm, snd_frg.scm</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(dot_snd_doc_tip)">.snd examples (Tom Roth, Kjetil S. Matheussen, Olivier Doare)</td></tr>
+
+<tr><td><a href="sndscm.html#envdoc">env</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(env_doc_tip)">envelope functions</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#enveddoc">enved</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(enved_doc_tip)">envelope editor</td></tr>
+
+<tr><td><a href="sndscm.html#exampdoc">examp</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(examp_doc_tip)">many examples</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#extensionsdoc">extensions</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(extensions_doc_tip)">various generally useful Snd extensions</td></tr>
+
+<tr><td><a href="sndscm.html#fadedoc">fade</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(fade_doc_tip)">frequency-domain cross-fades</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#framedoc">frame</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(frame_doc_tip)">frames, vcts, sound-data objects</td></tr>
+
+<tr><td><a href="sndscm.html#freeverbdoc">freeverb</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(freeverb_doc_tip)">a reverb</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndclm.html#othergenerators">generators</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(generators_doc_tip)">a bunch of generators</td></tr>
+
+<tr><td><a href="sndscm.html#granidoc">grani</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(grani_doc_tip)">CLM's grani (Fernando Lopez-Lezcano and Mike Scholz)</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#heartdoc">heart</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(heart_doc_tip)">use Snd with non-sound (arbitrary range) data</td></tr>
+
+<tr><td><a href="sndscm.html#hooksdoc">hooks</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(hooks_doc_tip)">functions related to hooks</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#indexdoc">index</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(index_doc_tip)">snd-help extension</td></tr>
+
+<tr><td><a href="sndscm.html#dotemacs">inf-snd.el, DotEmacs</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(inf_snd_doc_tip)">Emacs subjob support (Michael Scholz, Fernando Lopez-Lezcano)</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#jcrevdoc">jcrev</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(jcrev_doc_tip)">John Chowning's ancient reverb</td></tr>
+
+<tr><td><a href="sndscm.html#ladspadoc">ladspa.scm, ladspa-help.scm, gui.scm</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(ladspa_doc_tip)">Kjetil S. Matheussen's LADSPA GUI-builder and previewer.</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#maracadoc">maraca</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(maraca_doc_tip)">Perry Cook's maraca physical model</td></tr>
+
+<tr><td><a href="sndscm.html#marksdoc">marks</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(marks_doc_tip)">functions related to marks</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#maxfdoc">maxf</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(maxf_doc_tip)">Max Mathews resonator</td></tr>
+
+<tr><td><a href="sndscm.html#menusdoc">menus</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(menus_doc_tip)">additional menus</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#mixdoc">mix</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(mix_doc_tip)">functions related to mixes</td></tr>
+
+<tr><td><a href="sndscm.html#mixerdoc">mixer</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(mixer_doc_tip)">functions related to linear algebra</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#moogdoc">moog</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(moog_doc_tip)">Moog filter</td></tr>
+
+<tr><td><a href="sndscm.html#musglyphs">musglyphs</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(musglyphs_doc_tip)">Music notation symbols (from CMN)</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#nbdoc">nb</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(nb_doc_tip)">Popup File info etc</td></tr>
+
+<tr><td><a href="sndscm.html#noisedoc">noise</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(noise_doc_tip)">noise maker</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#numericsdoc">numerics</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(numerics_doc_tip)">various numerical functions</td></tr>
+
+<tr><td><a href="sndscm.html#oscopedoc">oscope</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(oscope_doc_tip)">an oscilloscope/spectrum analysis dialog</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#peakenvdoc">peak-env</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(peak_env_doc_tip)">peak envelope support</td></tr>
+
+<tr><td><a href="sndscm.html#peakphasesdoc">peak-phases</a></td>
+ <td>phases for the unpulse-train</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#pianodoc">piano</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(piano_doc_tip)">piano physical model</td></tr>
+
+<tr><td><a href="sndscm.html#playdoc">play</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(play_doc_tip)">play-related functions</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#polydoc">poly</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(poly_doc_tip)">polynomial-related stuff</td></tr>
+
+<tr><td><a href="sndscm.html#popupdoc">popup, gtk-popup</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(popup_doc_tip)">Popup menu specializations</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#prc95doc">prc95</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(prc95_doc_tip)">Perry Cook's physical model examples</td></tr>
+
+<tr><td><a href="sndscm.html#pvocdoc">pvoc</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(pvoc_doc_tip)">phase-vocoder</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#rgbdoc">rgb</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(rgb_doc_tip)">color names</td></tr>
+
+<tr><td><a href="sndscm.html#rtexdoc">rt-examples and friends</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(rtex_doc_tip)">hard real-time support</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#rtiodoc">rtio</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(rtio_doc_tip)">real-time stuff</td></tr>
+
+<tr><td><a href="sndscm.html#rubberdoc">rubber</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(rubber_doc_tip)">rubber-sound</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#selectiondoc">selection</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(selection_doc_tip)">functions acting on the current selection</td></tr>
+
+<tr><td><a href="sndscm.html#singerdoc">singer</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(singer_doc_tip)">Perry Cook's vocal-tract physical model</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#sndolddoc">snd6|7|8|9|10.scm</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(sndold_doc_tip)">Backwards compatibility</td></tr>
+
+<tr><td><a href="sndscm.html#snddiffdoc">snddiff</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(snddiff_doc_tip)">sound difference detection</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#sndgldoc">snd-gl</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(snd_gl_doc_tip)">OpenGL examples (gl.c)</td></tr>
+
+<tr><td><a href="sndscm.html#sndmotifdoc">snd-motif, snd-gtk, snd-xm</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(snd_motif_doc_tip)">Motif/Gtk module (xm.c, xg.c)</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#sndtestdoc">snd-test</a></td>
+ <td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip(snd_test_doc_tip)">Snd regression tests</td></tr>
+
+<tr><td><a href="sndscm.html#sndwarpdoc">sndwarp</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(sndwarp_doc_tip)">Bret Battey's sndwarp instrument</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#spectrdoc">spectr</a></td>
+ <td bgcolor="#f2f4ff">instrument steady state spectra</td></tr>
+
+<tr><td><a href="sndscm.html#stochasticdoc">stochastic</a></td>
+ <td>Bill Sack's dynamic stochastic synthesis</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#straddoc">strad</a></td>
+ <td bgcolor="#f2f4ff">string physical model (from CLM)</td></tr>
+
+<tr><td><a href="sndscm.html#vdoc">v</a></td>
+ <td>fm-violin</td></tr>
+
+<tr><td bgcolor="#f2f4ff"><a href="sndscm.html#wsdoc">ws</a></td>
+ <td bgcolor="f2f4ff" onmouseout="UnTip()" onmouseover="Tip(ws_doc_tip)">with-sound</td></tr>
+
+<tr><td><a href="sndscm.html#zipdoc">zip</a></td>
+ <td onmouseout="UnTip()" onmouseover="Tip(zip_doc_tip)">the zipper (the anti-cross-fader)</td></tr>
+
+</table>
+</td></tr></table>
+
+<br><br>
+<table width="80%" border=0><tr><td bgcolor="lightsteelblue" valign="middle"><h3><A NAME="behavior">Customizing Snd's behavior</a></h3></td></tr></table>
+
+<p>Most of Snd's behavior can be customized. For example,
+when a sound is saved, some people want to be warned if
+a pre-existing sound is about to be destroyed; others (Snd's
+author included) grumble "just do it". There are two ways
+this kind of situation is handled in Snd; through global variables and hooks.
+A hook is a list of callbacks invoked whenever its associated
+event happens. When Snd exits, for example, any functions found
+on the <a href="#beforeexithook">before-exit-hook</a> list are evaluated; if any of them returns #t,
+Snd does not exit.</p>
+
+<table border=0 cellpadding=5 hspace=20>
+<tr><td><pre>
+(define <A NAME="unsavededitsp">(unsaved-edits? lst)</A>
+ (if (not (null? lst))
+ (if (&gt; (car (<a class=quiet href="#edits" onmouseout="UnTip()" onmouseover="Tip(extsnd_edits_tip)">edits</a> (car lst))) 0)
+ (begin
+ (<a class=quiet href="#reportinminibuffer" onmouseout="UnTip()" onmouseover="Tip(extsnd_reportinminibuffer_tip)">report-in-minibuffer</a> "there are unsaved edits")
+ #t)
+ (unsaved-edits? (cdr lst)))
+ #f))
+
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>before-exit-hook</em> (lambda () (unsaved-edits? (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+</pre></td></tr></table>
+
+<p>Now when Snd is told to exit, it checks before-exit-hook, runs
+unsaved-edits?, and if the latter returns #t, if prints
+a worried message in the minibuffer, and refuses to
+exit. Similar hooks customize actions such as closing
+a sound (<a href="#closehook">close-hook</a>), clicking a mark (<a href="#markclickhook">mark-click-hook</a>),
+pressing a key (<a href="#keypresshook">key-press-hook</a>), and so on.</p>
+
+<br>
+<table width="60%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h4><A NAME="sndglobalvars">Global variables</a></h4></td></tr></table>
+
+<p>The global variables handle various customizations that aren't callback-oriented.
+For example,
+as sounds come and go, Snd's overall size may change (this is
+partly determined by the window manager, but is also
+up to Snd). Many people find this distracting &mdash; they would rather that the
+overall window stick to one size. The Snd variable associated
+with this is "auto-resize"; it can be accessed as:
+</p>
+<pre>
+ Scheme: (auto-resize)
+ Ruby: auto_resize()
+ Forth: auto-resize
+</pre>
+<p>and set via:</p>
+<pre>
+ Scheme: (set! (auto-resize) #f)
+ Ruby: set_auto_resize(false)
+ Forth: #f set-auto-resize
+</pre>
+<p>
+The variables are presented as a special kind of function, rather than as bare variables, mainly
+to ensure that Snd's response to the assignment is immediate.
+The statement <code>(set! (auto-resize) #f)</code> can be placed in your ~/.snd initialization file
+to make it the default setting for your version of Snd, or placed
+in a separate file of Scheme code and loaded at any time via the load
+function. </p>
+
+<p>The variables affecting Snd's overall behavior are:
+</p>
+
+<!-- -------------------------------- GLOBAL VARIABLE TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6>
+
+<tr><td width=30></td><td width=220></td><td></td></tr>
+
+<!-- ask-before-overwrite -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="askbeforeoverwrite">ask-before-overwrite</a></code></td>
+<td bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip('in this table, the default value of the given variable is listed after the variable name,<br>so ask-before-overwrite defaults to false')"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+ask-before-overwrite determines whether Snd asks before overwriting an existing file:
+<code>(set! (ask-before-overwrite) #t)</code>
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- audio-input-device -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="audioinputdevice">audio-input-device</a></code></td>
+<td bgcolor="#f2f4ff"><code>mus-audio-default</code></td></tr><tr><td></td><td colspan=2>
+This is the recorder's input device: <code>(set! (audio-input-device) mus-audio-microphone)</code>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- audio-output-device -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="audiooutputdevice">audio-output-device</a></code></td>
+<td bgcolor="#f2f4ff"><code>mus-audio-default</code></td></tr><tr><td></td><td colspan=2>
+This is the audio output device for the play button.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- auto-resize -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="autoresize">auto-resize</a></code></td>
+<td bgcolor="#f2f4ff"><code>#t</code></td></tr><tr><td></td><td colspan=2>
+auto-resize determines whether the Snd window should be resized
+when a sound is opened or closed.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- auto-update -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="autoupdate">auto-update</a></code></td>
+<td bgcolor="#f2f4ff"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+auto-update determines whether Snd should <a href="snd.html#updatefile">update</a> a file automatically
+if it (the file) changes on disk due to some other process.
+If Snd's view of a sound doesn't match the on-disk version of the sound,
+a bomb icon warns you that there are two conflicting versions of the sound.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- auto-update-interval -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="autoupdateinterval">auto-update-interval</a></code></td>
+<td bgcolor="#f2f4ff"><code>60</code></td></tr><tr><td></td><td colspan=2>
+This is the time (in seconds) between background checks for a changed file on
+disk (see <a href="#autoupdate">auto-update</a>). If auto-update-interval is 0.0, the auto-update background process
+is turned off.
+If the file alternation monitor is running (the default if you have libfam or libgamin), auto-update-interval is ignored
+since in that case the check happens instantly.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- clipping -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="clipping">clipping</a></code></td>
+<td bgcolor="#f2f4ff"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+If clipping is #t, output values are clipped to fit the current sndlib sample
+representation's notion of -1.0 to just less than 1.0. The default (#f)
+can cause wrap-around (if writing integer sound data) which makes the out-of-range values very obvious.
+To control this action more closely, use <a href="#cliphook">clip-hook</a>.
+To get completely confused, see <a href="#musclipping">mus-clipping</a> and <a href="#musfileclipping">mus-file-clipping</a>:
+this has become as messed up as the sampling rate settings!
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- cursor-location-offset -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="cursorlocationoffset">cursor-location-offset</a></code></td>
+<td bgcolor="#f2f4ff"><code>0.05</code></td></tr><tr><td></td><td colspan=2>
+cursor-location-offset is the offset in samples between Snd's notion of the location of the tracking cursor
+(<a href="#withtrackingcursor">with-tracking-cursor</a> in Snd jargon) and the actual (DAC-relative) location.
+Since, in general, Snd can't tell how many samples of buffering there are between itself
+and the speakers (audio cards have varying amounts), its notion of where to place the
+tracking cursor can be wrong by an almost arbitrary amount. If you have some idea
+of the buffering amount, you can correct this error via cursor-location-offset.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- cursor-update-interval -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="cursorupdateinterval">cursor-update-interval</a></code></td>
+<td bgcolor="#f2f4ff"><code>0.05</code></td></tr><tr><td></td><td colspan=2>
+This is the time in seconds between
+cursor redisplays if playing a sound with <a href="#withtrackingcursor">with-tracking-cursor</a> #t.
+If this number is too small, you may clicks during playback.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- dac-combines-channels -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="dacfolding">dac-combines-channels</a></code></td>
+<td bgcolor="#f2f4ff"><code>#t</code></td></tr><tr><td></td><td colspan=2>
+If dac-combines-channels is #t, and the current sound has more channels than are
+supported by the available audio hardware, Snd mixes the extra channels into the available channels during audio output.
+This provides a way to hear 4-channel sounds when you only have a stereo audio card.
+If dac-combines-channels is #f, extra channels are not played.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- dac-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="dacsize">dac-size</a></code></td>
+<td bgcolor="#f2f4ff"><code>256</code></td></tr><tr><td></td><td colspan=2>
+dac-size is the audio output buffer size; it is not always meaningful. See <a href="sndscm.html#playwithenvs">play-with-envs</a> in enved.scm or
+<a href="sndscm.html#playsound">play-sound</a> in play.scm. When you change the control panel settings during playback, the snappiness of the
+response is set, to some extent, by the dac-size. The default of 256 gives a stair-case effect in many
+cases, whereas 2048 is smoother. This also affects the resampling smoothness of playback while dragging the
+mark play triangle. Some audio choices, ALSA in particular, may ignore dac-size.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- default-output-chans -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="defaultoutputchans">default-output-chans</a></code></td>
+<td bgcolor="#f2f4ff"><code>1</code></td></tr><tr><td></td><td colspan=2>
+default-output-chans is the default number of channels when a new or temporary file is created,
+or a save dialog is opened.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- default-output-data-format -->
+<tr><td colspan=2 bgcolor="#f2f4ff" onmouseout="UnTip()" onmouseover="Tip('I originally intended the names to be &quot;header-format&quot; and &quot;data-type&quot;<br>but somehow things got bollixed up and I didn\'t notice the confusion until years later')"><code><a class=def name="defaultoutputdataformat">default-output-data-format</a></code></td>
+<td bgcolor="#f2f4ff"><code>mus-bfloat</code></td></tr><tr><td></td><td colspan=2>
+default-output-data-format is the default data format when a new or temporary file is created,
+or a save dialog is opened. (The default, <code>mus-bfloat</code>, is from sndlib, standing for 32-bit big-endian floating point data).
+Use <a href="#musoutformat">mus-out-format</a> for fastest IO.
+The available output data formats are (b=big-endian, l=little, u=unsigned, short=16 bits, byte=8 bits, int = 32 bits):
+<pre onmouseout="UnTip()" onmouseover="Tip('mus-bshort: big-endian (au-style) 16-bit ints, doubles are 64-bit floats,<br>alaw and mulaw are compression schemes, mus-b24int is a 3-byte (24-bit) format;<br>each header type has restrictions on the kinds of data it can accommodate.')">
+ mus-bshort mus-lshort mus-mulaw mus-alaw mus-byte mus-ubyte mus-bfloat
+ mus-lfloat mus-bint mus-lint mus-b24int mus-l24int mus-bdouble mus-ldouble
+ mus-ubshort mus-ulshort
+</pre>
+There are also "unscaled" versions of the floating point types, and "normalized" versions of the integers.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- default-output-header-type -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="defaultoutputheadertype">default-output-header-type</a></code></td>
+<td bgcolor="#f2f4ff"><code>mus-next</code></td></tr><tr><td></td><td colspan=2>
+This is the default header type when a new file is created,
+or a save dialog is opened. (The default, <code>mus-next</code>, stands for the NeXT/Sun sound file header).
+The available output header-types are:
+<pre onmouseout="UnTip()" onmouseover="Tip('mus-riff is our name for Microsoft wav,<br>mus-rf64 is the EBU 64-bit RIFF-replacement header,<br>mus-nist refers to NIST-SPHERE files,<br>mus-next and mus-sun are the same,<br>mus-aiff is the obsolete predecessor to mus-aifc,<br>mus-bicsf and mus-ircam are extensions of mus-next headers,<br>mus-raw means &quot;headerless&quot;,<br>mus-soundfont refers to Emu\'s extension of mus-riff files,<br>mus-voc refers to Creative Voice File,<br>mus-svx refers to 8SVX headers.<br>Many other headers are supported read-only.')">
+ mus-next mus-aifc mus-riff mus-rf64 mus-nist mus-raw mus-ircam mus-aiff
+ mus-soundfont mus-bicsf mus-voc mus-svx mus-caff
+</pre>
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- default-output-srate -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="defaultoutputsrate">default-output-srate</a></code></td>
+<td bgcolor="#f2f4ff"><code>44100</code></td></tr><tr><td></td><td colspan=2>
+This is the default sampling rate when a new or temporary file is created,
+or a save dialog is opened.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- eps-bottom-margin -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="epsbottommargin">eps-bottom-margin</a></code></td>
+<td bgcolor="#f2f4ff"><code>0.0</code></td></tr><tr><td></td><td colspan=2>
+eps-bottom-margin is the bottom margin used in snd.eps, created by the File:Print dialog, or the <a href="#graphtops">graph-&gt;ps</a> function.
+PostScript units are 1/72 of an inch (a "point" in printer jargon);
+an inch is 2.54 cm:
+
+<table border=0 cellpadding=5 vspace=10 hspace=20><tr><td>
+
+<table border=0 cellpadding=5><tr><td><pre>
+Scheme:
+
+(define (inches-to-ps inches)
+ (* inches 72))
+
+(define (cm-to-ps cm)
+ (* cm (/ 72.0 2.54)))
+</pre></td></tr></table>
+
+</td><td>
+
+<table border=0 cellpadding=5><tr><td bgcolor="Beige"><pre>
+Ruby:
+def inches_to_ps(inches)
+ inches * 72
+end
+def cm_to_ps(cm)
+ cm * 72.0 / 2.54
+end
+</pre></td></tr></table>
+
+</td><td>
+
+<table border=0 cellpadding=5><tr><td bgcolor="LightGreen"><pre>
+Forth:
+: inches-to-ps { inches }
+ inches 72 f*
+;
+: cm-to-ps { cm }
+ cm 2.54 f/ 72 f*
+;
+</pre></td></tr></table>
+</td></tr></table>
+
+In the resulting .eps file, you'll find a <code>concat</code> statement near the
+top of the file; the first and fourth numbers are scale factors on
+the entire graph, the fifth is the left margin, and the sixth is the
+bottom margin.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- eps-file -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="epsfile">eps-file</a></code></td>
+<td bgcolor="#f2f4ff"><code>"snd.eps"</code></td></tr><tr><td></td><td colspan=2>
+This is the default name of the Postscript file produced by the File:Print dialog, or the <a href="#graphtops">graph-&gt;ps</a> function.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- eps-left-margin -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="epsleftmargin">eps-left-margin</a></code></td>
+<td bgcolor="#f2f4ff"><code>0.0</code></td></tr><tr><td></td><td colspan=2>
+eps-left-margin is the left margin used in snd.eps, created by the File:Print dialog, or the <a href="#graphtops">graph-&gt;ps</a> function.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- eps-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="epssize">eps-size</a></code></td>
+<td bgcolor="#f2f4ff"><code>1.0</code></td></tr><tr><td></td><td colspan=2>
+eps-size is the scaler used to set the overall picture size in snd.eps,
+created by the File:Print dialog, or the <a href="#graphtops">graph-&gt;ps</a> function,
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- graph-cursor -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="graphcursor">graph-cursor</a></code></td>
+<td bgcolor="#f2f4ff"><code>XC_crosshair (34)</code></td></tr><tr><td></td><td colspan=2>
+graph-cursor is the kind of cursor displayed following the mouse in the data graph.
+It can be any of the cursors provided by X or Gtk+: <code>(set! (graph-cursor) 22)</code>.
+The X/Motif cursors are declared in /usr/include/X11/cursorfont.h or some such file;
+gtk versions are in gdkcursor.h. Some useful choices are:
+
+<table border=0 cellpadding=6 vspace=10><tr><td>
+<table border=0 cellspacing=4 cellpadding=4>
+<tr><th bgcolor="beige"><small>Motif</small></th><th bgcolor="beige"><small>Gtk+</small></th><th bgcolor="beige"><small>value</small></th></tr>
+<tr><td><small>XC_arrow</small></td><td><small>GDK_ARROW</small></td><td><small>2</small></td></tr>
+<tr><td><small>XC_center_ptr</small></td><td><small>GDK_CENTER_PTR</small></td><td><small>22</small></td></tr>
+<tr><td><small>XC_cross</small></td><td><small>GDK_CROSS</small></td><td><small>30</small></td></tr>
+<tr><td><small>XC_crosshair</small></td><td><small>GDK_CROSSHAIR</small></td><td><small>34</small></td></tr>
+<tr><td><small>XC_left_ptr</small></td><td><small>GDK_LEFT_PTR</small></td><td><small>68</small></td></tr>
+<tr><td><small>XC_plus</small></td><td><small>GDK_PLUS</small></td><td><small>90</small></td></tr>
+<tr><td><small>XC_right_ptr</small></td><td><small>GDK_RIGHT_PTR</small></td><td><small>94</small></td></tr>
+<tr><td><small>XC_tcross</small></td><td><small>GDK_TCROSS</small></td><td><small>130</small></td></tr>
+<tr><td><small>XC_xterm</small></td><td><small>GDK_XTERM</small></td><td><small>152</small></td></tr>
+</table>
+</td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- html-dir -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="htmldir">html-dir</a></code></td>
+<td bgcolor="#f2f4ff"><code>"."</code></td></tr><tr><td></td><td colspan=2>
+html-dir is the directory to search for documentation if an HTML reader is in use.
+See the function html in index.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- html-program -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="htmlprogram">html-program</a></code></td>
+<td bgcolor="#f2f4ff"><code>"firefox"</code></td></tr><tr><td></td><td colspan=2>
+This is the program to use to read HTML files.
+On the Mac, you need to give the full path to the executable image: "/Applications/Safari.app/Contents/MacOS/Safari".
+See the function html in index.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- just-sounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="justsounds">just-sounds</a></code></td>
+<td bgcolor="#f2f4ff"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+In Motif and in Gtk versions 2.3 or later,
+if just-sounds is #t,
+the file lists displayed by the file selection dialogs are filtered to show just
+sound files (see <a href="#addsoundfileextension">add-sound-file-extension</a>).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- ladspa-dir -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="ladspadir">ladspa-dir</a></code></td>
+<td bgcolor="#f2f4ff"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+LADSPA is a way of managing plug-ins in Linux. I consider it very old-fashioned, but
+there are a bunch of ladspa libraries, and they're easy to load. so...
+ladspa-dir is the
+name of the directory to search for LADSPA plugin libraries (it can override or replace LADSPA_PATH).
+See <a href="grfsnd.html#sndandladspa">Snd and LADSPA</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- log-freq-start -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="logfreqstart">log-freq-start</a></code></td>
+<td bgcolor="#f2f4ff"><code>32.0</code></td></tr><tr><td></td><td colspan=2>
+log-freq-start is the start (lowest) frequency used in the log freq display (ffts). Since the log display emphasizes the lower
+frequencies, but the lowest are all inaudible, it seemed more informative to squash the lowest 30Hz or so
+into a single point (0 Hz) on the log freq graphs; otherwise the audible data starts about 1/4 of the way
+down the x axis, wasting valuable screen space! But it also seemed a bother to have to set/reset the
+<a href="#spectrumstart">spectrum-start</a> variable every time you wanted to flip between log and linear
+displays. log-freq-start to the rescue? For other ideas along these lines, see <a href="sndscm.html#displaybarkfft">display-bark-fft</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- max-regions -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="maxregions">max-regions</a></code></td>
+<td bgcolor="#f2f4ff"><code>16</code></td></tr><tr><td></td><td colspan=2>
+This sets the maximum size of the region list, the number of regions that are accessible.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- max-virtual-ptrees -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="maxvirtualptrees">max-virtual-ptrees</a></code></td>
+<td bgcolor="#f2f4ff"><code>3</code></td></tr><tr><td></td><td colspan=2>
+This sets the maximum number of parse-trees (see <a href="#ptreechannel">ptree-channel</a>) that the
+virtual editor will allow in any virtual edit (once the maximum is reached, the operation is handled
+locally, not via a virtual edit).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- minibuffer-history-length -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="minibufferhistorylength">minibuffer-history-length</a></code></td>
+<td bgcolor="#f2f4ff"><code>8</code></td></tr><tr><td></td><td colspan=2>
+This sets the maximum length of the minibuffer and listener M-p/M-n history lists.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mus-max-malloc -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musmaxmalloc">mus-max-malloc</a></code></td>
+<td bgcolor="#f2f4ff"><code>67108864</code></td></tr><tr><td></td><td colspan=2>
+This sets the maximum memory allocation (in bytes).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mus-max-table-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musmaxtablesize">mus-max-table-size</a></code></td>
+<td bgcolor="#f2f4ff"><code>20971520</code></td></tr><tr><td></td><td colspan=2>
+This sets the maximum table size (delay line length in samples, etc).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- open-file-dialog-directory -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="openfiledialogdirectory">open-file-dialog-directory</a></code></td>
+<td bgcolor="#f2f4ff"><code>"."</code></td></tr><tr><td></td><td colspan=2>
+open-file-dialog-directory is the name of the initial open file dialog directory (normally ".").
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- optimization -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="optimization">optimization</a></code></td>
+<td bgcolor="#f2f4ff"><code>6</code></td></tr><tr><td></td><td colspan=2>
+optimization affects optimization levels in Scheme.
+If non-zero, it causes Snd to try to optimize simple lambda forms passed to the searches and so forth.
+This depends partly on the optargs module, and
+applies only to s7 and Guile.
+The actual values of the optimization switch are:
+<pre>
+ 0: no optimization (use the standard Scheme parser/evaluator)
+ 1: optimize simple stuff (if complex result possible, give up)
+ 2: assume nothing will return a complex number
+ 3: if an undefined variable is encountered, try to guess its type
+ 4: make questionable assumptions about variable types
+ 5: make dangerous assumptions about variable locations (for set!)
+ 6: try to splice in user-defined functions
+</pre>
+
+Currently, the optimizer is able to speed up Scheme code by factors between
+8 and 20; see run.c for what is implemented, what the major limitations are, and so on.
+If you set the optimization-hook to print out whatever its argument is, you can
+find out what the optimizer found confusing:
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#optimizationhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_optimizationhook_tip)">optimization-hook</a> (lambda (n) (display (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "opt: ~A~%" n))))
+</pre>
+See also <a href="#maxvirtualptrees">max-virtual-ptrees</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- print-length -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="printlength">print-length</a></code></td>
+<td bgcolor="#f2f4ff"><code>12</code></td></tr><tr><td></td><td colspan=2>
+For objects such as vcts, print-length sets the number of elements printed.
+In S7, this also sets *vector-print-length*.
+<pre>
+ <em class=listener>&gt;</em><em class=typing>(set! (print-length) 3)</em>
+ <em class=listener>3</em>
+ <em class=listener>&gt;</em><em class=typing>(make-vct 10 .1)</em>
+ <em class=listener>#&lt;vct[len=10]: 0.100 0.100 0.100 ...&gt;</em>
+</pre>
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- save-dir -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="savedir">save-dir</a></code></td>
+<td bgcolor="#f2f4ff"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+save-dir is the name of the directory for saved-state files.
+<br><br>
+These files are written when you call <a href="#savestate">save-state</a> or
+choose the Options:Save session menu item. If any of the current sounds has
+an edit that requires saved data, it is written as a separate sound file, and
+that file is reloaded automatically when you restart the saved session. To keep such
+files safe, or at least separate from others, you can set up separate
+directory for them.
+<span onmouseout="UnTip()" onmouseover="Tip('<pre>Ruby: set_save_dir(&quot;/tmp&quot;), Forth: &quot;/tmp&quot; set-save-dir</pre>')"><code>(set! (<a class=quiet href="#savedir" onmouseout="UnTip()" onmouseover="Tip(extsnd_savedir_tip)">save-dir</a>) "/tmp")</code></span>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- save-state-file -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="savestatefile">save-state-file</a></code></td>
+<td bgcolor="#f2f4ff"><code>"saved-snd.scm"</code></td></tr><tr><td></td><td colspan=2>
+This is the <a href="snd.html#savedstate">saved state</a> file name.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- selection-creates-region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectioncreatesregion">selection-creates-region</a></code></td>
+<td bgcolor="#f2f4ff"><code>#t</code></td></tr><tr><td></td><td colspan=2>
+If selection-creates-region is #t, a region is created whenever a selection is made. If you're editing very large sounds
+and using selections, the region temp files can use up a lot of disk space (and the time to write
+them); if you're not using regions anyway, this switch can turn them off.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- show-indices -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="showindices">show-indices</a></code></td>
+<td bgcolor="#f2f4ff"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+If show-indices is #t, each sound's name is preceded by its index in the sound pane.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- show-selection-transform -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="showselectiontransform">show-selection-transform</a></code></td>
+<td bgcolor="#f2f4ff"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+If show-selection-transform is #t, Snd displays the transform of the current active selection, if any.
+The sonogram and spectrogram displays ignore this flag because they assume their time axis
+matches that of the time domain graph.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- sinc-width -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sincwidth">sinc-width</a></code></td>
+<td bgcolor="#f2f4ff"><code>10</code></td></tr><tr><td></td><td colspan=2>
+sinc-width is the width in samples of the sampling rate conversion sinc interpolation.
+<br><br>
+The higher this number, the better the src low-pass filter, but the slower
+src runs. If you use too low a setting, you can sometimes hear high
+frequency whistles leaking through. To hear these on purpose, make
+a sine wave at (say) 55 Hz, then <code>(<a class=quiet href="#srcsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_srcsound_tip)">src-sound</a> '(0 3 1 1))</code> with sinc-width at 4.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- snd-version -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sndversion">snd-version</a></code></td>
+<td bgcolor="#f2f4ff"><code>"1-Jun-06" etc</code></td></tr><tr><td></td><td colspan=2>
+This is a string giving the current Snd version, normally a date.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- temp-dir -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="tempdir">temp-dir</a></code></td>
+<td bgcolor="#f2f4ff"><code>#f</code></td></tr><tr><td></td><td colspan=2>
+temp-dir is the directory to use for temporary files; if it is #f, Snd uses whatever the system default is, usually "/tmp" or "/var/tmp".
+See also <a href="#sndtempnam">snd-tempnam</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- trap-segfault -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="trapsegfault">trap-segfault</a></code></td>
+<td bgcolor="#f2f4ff"><code>#t</code></td></tr><tr><td></td><td colspan=2>
+If trap-segfault is #t, Snd tries to catch segfaults and continue anyway. This normally gives you
+a chance to save your current work, but please also send bil@ccrma.stanford.edu a bug report!
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- window-height -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="windowheight">window-height</a></code></td>
+<td bgcolor="#f2f4ff"><code>0</code></td></tr><tr><td></td><td colspan=2>
+window-height is the current Snd window height in pixels.
+This is the same as <br>
+<pre>
+ Scheme: (cadr (<a class=quiet href="#widgetsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_widgetsize_tip)">widget-size</a> (cadr (<a class=quiet href="#mainwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_mainwidgets_tip)">main-widgets</a>))))
+
+ Ruby: widget_size(main_widgets.cadr).cadr
+
+ Forth: main-widgets cadr widget-size cadr
+</pre>
+except at startup when the window-height function and friends defer the assignment until after the main widgets
+have been created. If Snd becomes confused about screen size, it can make its main window so large that
+you can't get at any of the decorations for resizing the window; in this emergency you can
+<code>(set! (window-height) 300)</code> or some such number.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- window-width -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="windowwidth">window-width</a></code></td>
+<td bgcolor="#f2f4ff"><code>0</code></td></tr><tr><td></td><td colspan=2>
+This is the current Snd window width in pixels.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- window-x -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="windowx">window-x</a></code></td>
+<td bgcolor="#f2f4ff"><code>-1</code></td></tr><tr><td></td><td colspan=2>
+This is the current Snd window left side position in pixels (-1 means unset).
+This is (usually) the same as
+<pre>
+ (car (<a class=quiet href="#widgetposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_widgetposition_tip)">widget-position</a> (cadr (<a class=quiet href="#mainwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_mainwidgets_tip)">main-widgets</a>))))
+</pre>
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- window-y -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="windowy">window-y</a></code></td>
+<td bgcolor="#f2f4ff"><code>-1</code></td></tr><tr><td></td><td colspan=2>
+This is the current Snd window upper side position in pixels (X numbering starts at 0 at the top, -1 means unset).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- with-background-processes -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="withbackgroundprocesses">with-background-processes</a></code></td>
+<td bgcolor="#f2f4ff"><code>#t</code></td></tr><tr><td></td><td colspan=2>
+with-background-processes determines whether Snd should use background (idle time) processes for ffts and so forth.
+It is intended primarily for auto-testing.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- with-file-monitor -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="withfilemonitor">with-file-monitor</a></code></td>
+<td bgcolor="#f2f4ff"><code>#t</code></td></tr><tr><td></td><td colspan=2>
+If with-file-monitor is #t (the default), the file alteration monitor is active. There are still bugs
+in this library that can cause Snd to hang &mdash; I haven't tracked down what the problem is yet; in the meantime,
+set this switch to #f to disable the monitor. (One such bug was fixed in gamin 1.8.0).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- with-relative-panes -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="withrelativepanes">with-relative-panes</a></code></td>
+<td bgcolor="#f2f4ff"><code>#t</code></td></tr><tr><td></td><td colspan=2>
+If with-relative-panes is #t in the Motif
+version of Snd, a multichannel sound tries to retain the relative channel graph sizes
+when the outer sash (the overall sound size sash) changes.
+Mono sounds and the listener are not affected (perhaps they should be?).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- zoom-focus-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="zoomfocusstyle">zoom-focus-style</a></code></td>
+<td bgcolor="#f2f4ff"><code>zoom-focus-active</code></td></tr><tr><td></td><td colspan=2>
+This determines what a zoom action focuses (centers) on. The choices are
+<code>zoom-focus-left</code>, <code>zoom-focus-right</code>, <code>zoom-focus-active</code>, <code>zoom-focus-middle</code>,
+or a function of 6 arguments. The function should return the new window left edge as a float.
+Its arguments are the current sound, channel number, zoom slider value (0.0 to 1.0), time domain window left and right
+edges in seconds, and the current total x axis size (seconds) corresponding to a slider value
+of 1.0.
+<pre>
+ (set! (zoom-focus-style) (lambda (snd chn zx x0 x1 range) (- x1 (* zx range))))
+</pre>
+mimics zoom-focus-right. <code>zoom-focus-active</code> tries to focus on some object in the view: the cursor, a mix or mark, etc.
+See also <a href="snd.html#zoomoption">Zoom options</a>.
+</td></tr>
+</table>
+<br><br>
+
+
+
+<!-- ---------------------------------------- GENERIC FUNCTIONS ---------------------------------------- -->
+<table width="60%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h4><A NAME="sndgenericfuncs">Generic functions</a></h4></td></tr></table>
+
+<p>Several functions in Snd are "generic" in the sense that they can handle a wide
+variety of objects. The length function, for example, applies to strings and vectors,
+as well as lists.
+</p>
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+
+<!-- channels -->
+<!-- INDEX genericchannels:channels (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>channels</a> (:optional obj)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericchannels">channels</A> handles strings (<a href="#mussoundchans">mus-sound-chans</a>), <a href="#regionchans">region-chans</a>,
+<a href="#sounddatachans">sound-data-chans</a>, <a href="sndclm.html#genericfunctions">mus-channels</a>,
+<a href="#sndmixes">mixes</a>, <a href="#Vcts">vcts</a>, and vectors (always 1 channel), and
+<a href="#sndsounds">sounds</a> (as objects or as integers).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- copy -->
+<!-- INDEX genericcopy:copy (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>copy</a> (obj)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericcopy">copy</A> returns a copy of its argument (s7 only, and not fully implemented yet).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- file-name -->
+<!-- INDEX genericfilename:file-name (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>file-name</a> (:optional obj)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericfilename">filename</A> can replace <a href="#musexpandfilename">mus-expand-filename</a>,
+<a href="sndclm.html#genericfunctions">mus-file-name</a>, and (s7 scheme's) port-filename,
+as well as handling mixes, regions, samplers, and the regular sound-oriented <a href="#filename">file-name</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- fill! -->
+<!-- INDEX genericfill:fill! (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>fill!</a> (obj val)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericfill">fill!</A> fills obj with val (s7 only, and not fully implemented yet).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- frames -->
+<!-- INDEX genericframes:frames (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>frames</a> (:optional obj chn edpos)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericframes">frames</A> returns the number of "frames" in an object, that is,
+the number of samples per channel. The frames function overlaps
+the <a href="#genericlength">length</a> function, but length of a string is string-length, whereas frames of a string
+treats the string as a sound file name and returns <a href="#mussoundframes">mus-sound-frames</a>. frames can replace
+<a href="#mussoundframes">mus-sound-frames</a>, <a href="sndclm.html#genericfunctions">mus-length</a>,
+<a href="#mixlength">mix-length</a>, <a href="#regionframes">region-frames</a>,
+<a href="#vctlength">vct-length</a>, <a href="#sounddatalength">sound-data-length</a>,
+and the regular <a href="#frames">frames</a> function that handles sound objects and integers as sound indices.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- length -->
+<!-- INDEX genericlength:length (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>length</a> (obj)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericlength">length</A> handles list length, string-length, vector-length, <a href="s7.html#s7doc">hash-table-size</a>,
+<a href="#vctlength">vct-length</a>, <a href="#frames">frames</a> (sound length),
+<a href="sndclm.html#genericfunctions">mus-length</a> (generators), <a href="#sounddatalength">sound-data-length</a>,
+<a href="#mixlength">mix-length</a>, and <a href="#regionframes">region-frames</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- maxamp -->
+<!-- INDEX genericmaxamp:maxamp (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>maxamp</a> (obj)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericmaxamp">maxamp</A> can handle a sound (via the regular <a href="#maxamp">maxamp</a> function),
+string (treated as a sound file name, <a href="#mussoundmaxamp">mus-sound-maxamp</a>),
+generator (maxamp of the mus-data vct, if any),
+sound-data (<a href="#sounddatamaxamp">sound-data-maxamp</a>),
+vct (<a href="#vctpeak">vct-peak</a>),
+region (<a href="#regionmaxamp">region-maxamp</a>),
+vector, list, or mix object.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- srate -->
+<!-- INDEX genericsrate:srate (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>srate</a> (:optional obj)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericsrate">srate</A> handles strings (treated as file names: <a href="#mussoundsrate">mus-sound-srate</a>),
+regions (<a href="#regionsrate">region-srate</a>), and <a href="#sndsounds">sounds</a> (as objects or as integers).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- sync -->
+<!-- INDEX genericsync:sync (generic) -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>sync</a> (obj)</code>
+</td></tr><tr><td></td><td>
+<A NAME="genericsync">sync</A> accesses the '<a href="#sync">sync</a>' field of a sound, mark, or mix.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+
+
+</table>
+
+<br><br>
+
+
+
+<!-- ---------------------------------------- HOOKS ---------------------------------------- -->
+<!-- INDEX sndhooks:Hooks -->
+<table width="60%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h4><A NAME="sndhooks">Hooks</a></h4></td></tr></table>
+
+<p>When some user-interface action takes place, code is called that responds to that action;
+these functions are sometimes called callbacks; the variable that holds a list of such
+callbacks is known as a hook.
+A hook provides
+a way to customize user-interface
+actions.
+The hook itself is list of functions. The function add-hook! adds a function to a hook's
+list, remove-hook! removes a function, and reset-hook! clears out the list.
+For example, the hook that is checked when you click the sound's name in the minibuffer is
+name-click-hook. We can cause that action to print "hi":</p>
+
+<pre>
+ Scheme: (add-hook! <a class=quiet href="#nameclickhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_nameclickhook_tip)">name-click-hook</a> (lambda (snd) (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> "hi") #t))
+
+ Ruby: $name_click_hook.add_hook!("print") do |snd| snd_print("hi"); true end
+
+ Forth: name-click-hook lambda: &lt;{ snd }&gt; "hi" snd-print drop #t ; add-hook!
+</pre>
+
+<p>
+If there is more than one function attached to a hook, some of the hooks
+"or" the functions together (marked <b>[or]</b> below); that is they
+run through the list of functions, and if any function returns something other than #f, the
+hook invocation eventually returns the last such non-#f value. A few hooks are "cascade"
+hooks; that is, each function gets the result of the previous function, and
+the final function's value is returned.
+In the other
+cases ("progn", the name coming from Common Lisp), the result returned by the hook is the result of the last function in the list.
+Whatever the hook combination choice, all the functions on the hook list are run
+on each invocation. There are a variety of hook-related functions in hooks.scm.
+</p>
+<p>There are several basic actions that involve a bunch of hooks. Here is a schematic view of
+some of these sequences.
+</p>
+
+<pre>
+ Open filename
+ bad header?: <a class=quiet href="#badheaderhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_badheaderhook_tip)">bad-header-hook</a> &mdash; can cancel request
+ no header?: <a class=quiet href="#openrawsoundhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openrawsoundhook_tip)">open-raw-sound-hook</a> &mdash; can cancel request
+ file ok:
+ <a class=quiet href="#openhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openhook_tip)">open-hook</a> &mdash; can change filename
+ file opened (no data read yet)
+ <a class=quiet href="#duringopenhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_duringopenhook_tip)">during-open-hook</a> (can set prescaling etc)
+ data read, no graphics yet
+ <a class=quiet href="#afteropenhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_afteropenhook_tip)">after-open-hook</a>
+ <a class=quiet href="#initialgraphhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_initialgraphhook_tip)">initial-graph-hook</a>
+
+
+ Save current sound
+ <a class=quiet href="#beforesaveashook" onmouseout="UnTip()" onmouseover="Tip(extsnd_beforesaveashook_tip)">before-save-as-hook</a> &mdash; can cancel the request or set its output parameters
+ <a class=quiet href="#savehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_savehook_tip)">save-hook</a>
+ sound saved
+ if any sample is clipped during save, <a class=quiet href="#cliphook" onmouseout="UnTip()" onmouseover="Tip(extsnd_cliphook_tip)">clip-hook</a>
+ <a class=quiet href="#aftersaveashook" onmouseout="UnTip()" onmouseover="Tip(extsnd_aftersaveashook_tip)">after-save-as-hook</a>
+
+
+ Play sound
+ when a play request occurs: <a class=quiet href="#startplayinghook" onmouseout="UnTip()" onmouseover="Tip(extsnd_startplayinghook_tip)">start-playing-hook</a> &mdash; can cancel the request, also <a class=quiet href="#startplayingselectionhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_startplayingselectionhook_tip)">start-playing-selection-hook</a>
+ (any number of sounds can be playing at once)
+ as each buffer is sent to the audio device: <a class=quiet href="#playhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_playhook_tip)">play-hook</a> and <a class=quiet href="#dachook" onmouseout="UnTip()" onmouseover="Tip(extsnd_dachook_tip)">dac-hook</a>
+ as each sound ends: <a class=quiet href="#stopplayinghook" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopplayinghook_tip)">stop-playing-hook</a>, <a class=quiet href="#stopplayingselectionhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopplayingselectionhook_tip)">stop-playing-selection-hook</a>
+ close audio device: <a class=quiet href="#stopdachook" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopdachook_tip)">stop-dac-hook</a>
+
+
+ Close sound
+ <a class=quiet href="#beforeclosehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_beforeclosehook_tip)">before-close-hook</a> &mdash; can cancel close
+ <a class=quiet href="#closehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_closehook_tip)">close-hook</a> (sound is still open)
+ sound closed
+
+
+ Save current Snd ("session") state
+ <a class=quiet href="#savestatehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_savestatehook_tip)">save-state-hook</a> &mdash; can change output filename (crummy name is an historical artifact)
+ output save-state file opened
+ <a class=quiet href="#beforesavestatehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_beforesavestatehook_tip)">before-save-state-hook</a>
+ Snd saves its state
+ <a class=quiet href="#aftersavestatehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_aftersavestatehook_tip)">after-save-state-hook</a>
+ output closed
+
+
+ Exit Snd
+ <a class=quiet href="#beforeexithook" onmouseout="UnTip()" onmouseover="Tip(extsnd_beforeexithook_tip)">before-exit-hook</a> &mdash; can cancel exit request
+ <a class=quiet href="#exithook" onmouseout="UnTip()" onmouseover="Tip(extsnd_exithook_tip)">exit-hook</a>
+ Snd cleans up and exits
+</pre>
+
+
+<p>
+You can find out what's on a given hook with the following (which is mostly adding carriage returns to the
+printout from hook-&gt;list):
+</p>
+<table border=0 cellpadding=5 hspace=20><tr><td><pre>
+(define (describe-hook hook)
+ (for-each
+ (lambda (n)
+ (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~A~%" n)))
+ (reverse (<em class=red>hook-&gt;list</em> hook))))
+</pre></td></tr></table>
+
+<p>Here's the Ruby version of some of the hook-related functions:
+</p>
+<pre>
+ $var_hook.remove_hook!("proc_name")
+ $var_hook.reset_hook!
+ $var_hook.run_hook do |prc| prc.call(1, 2, 3) end
+ $var_hook.call(1, 2, 3) # calls all procedures
+
+ require 'hooks'
+ $var_hook.show # prints the code of the procedure(s)
+ $va_hook.to_a
+</pre>
+
+<p>And some Forth examples, taken from Mike Scholz's documentation:
+</p>
+<pre>
+ open-hook ' open-buffer 1 make-proc add-hook!
+ open-hook "open-buffer" remove-hook!
+ open-hook reset-hook!
+ open-hook hook-&gt;list
+
+ 2 "A simple hook." create-hook my-new-hook
+ my-new-hook ' + 2 make-proc add-hook!
+ my-new-hook '( 2 3 ) run-hook
+ help my-new-hook
+</pre>
+
+
+<p>These hooks are extremely easy to add; if there's some user-interface action
+you'd like to specialize in some way, send me a note.
+hooks.scm has snd-hooks and reset-all-hooks, as well as other
+useful hook-related functions.
+</p>
+
+<!-- -------------------------------- HOOK TABLE -------------------------------- -->
+
+<p>
+In the following list of hooks, the arguments after the hook name refer to the arguments to the functions invoked by
+the hook. That is, <code>after-apply-controls-hook (snd)</code> means that the functions on the
+<a class=quiet href="#afterapplycontrolshook" onmouseout="UnTip()" onmouseover="Tip(extsnd_afterapplycontrolshook_tip)">after-apply-controls-hook</a> list each take one argument, a sound.
+If the argument list is followed by some
+indication such as "[or]", that means the various hook function values are or-d together.
+</p>
+
+
+<table border=0 cellspacing=4 cellpadding=6>
+
+<!-- after-apply-controls-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="afterapplycontrolshook">after-apply-controls-hook</a> (snd)</code>
+</td></tr><tr><td width=30></td><td colspan=2>
+This hook is called when <a href="#applycontrols">apply-controls</a> finishes.
+<a href="sndscm.html#addampcontrols">add-amp-controls</a> in snd-motif.scm uses this hook to
+reset any added amplitude sliders to 1.0.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- after-graph-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="aftergraphhook">after-graph-hook</a> (snd chn)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called after a graph is updated or redisplayed; see <a href="#displaysampsinred">display-samps-in-red</a>,
+<a href="sndscm.html#showsmptelabel">draw-smpte-label</a> in snd-motif.scm, or <a href="#addcomment">add-comment</a>.
+This is the hook to use when adding your own finishing touches to the display; if added earlier they risk
+being erased by Snd as it redraws graphs.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- after-lisp-graph-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="afterlispgraphhook">after-lisp-graph-hook</a> (snd chn)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called after a "lisp" graph is updated or redisplayed. The <a href="#lispgraphhook">lisp-graph-hook</a> functions
+are called before the actual graph is displayed, so if you want to add to a graph in some way, you need to
+use after-lisp-graph-hook.
+<a href="sndscm.html#displaybarkfft">display-bark-fft</a> in dsp.scm uses it to draw the x axis labels and
+ticks for various frequency scales.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- after-open-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="afteropenhook">after-open-hook</a> (snd)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called just before a newly opened sound's window is displayed.
+This provides a way to set various sound-specific defaults.
+For example, the following causes Snd to default to locally
+sync'd channels (that is, each sound's channels are sync'd
+together but are independent of any other sound), united channels (all chans in one graph),
+and filled graphs (not line segments or dots, etc):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>after-open-hook</em>
+ (lambda (snd)
+ (if (&gt; (<a class=quiet href="#channels" onmouseout="UnTip()" onmouseover="Tip(extsnd_channels_tip)">channels</a> snd) 1)
+ (begin
+ (set! (<a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> snd) (+ 1 snd)) ; 0 = #f
+ (set! (<a class=quiet href="#channelstyle" onmouseout="UnTip()" onmouseover="Tip(extsnd_channelstyle_tip)">channel-style</a> snd) <a class=quiet href="#channelstyle" onmouseout="UnTip()" onmouseover="Tip(extsnd_channelstyle_tip)">channels-combined</a>)
+ (set! (<a class=quiet href="#graphstyle" onmouseout="UnTip()" onmouseover="Tip(extsnd_graphstyle_tip)">graph-style</a> snd) <a class=quiet href="#graphstyle" onmouseout="UnTip()" onmouseover="Tip(extsnd_graphstyle_tip)">graph-filled</a>)))))
+</pre></td></tr></table>
+
+See also <a href="sndscm.html#xbopen">C-x b</a> support in examp.scm,
+<a href="sndscm.html#remembersoundstate">remember-sound-state</a> in extensions.scm,
+enved.scm, and various examples in snd-motif.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- after-save-as-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="aftersaveashook">after-save-as-hook</a> (index filename from-dialog)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called after File:Save as. See <a href="sndscm.html#emacsstylesaveas">emacs-style-save-as</a> in snd7.scm
+which closes the current sound and opens the newly created one to mimic Emacs.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- after-save-state-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="aftersavestatehook">after-save-state-hook</a> (filename)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called after Snd has saved its state (<a href="#savestate">save-state</a>). 'filename' is the (otherwise complete) saved state
+program. See <a href="sndscm.html#wssavestate">ws-save-state</a> in ws.scm
+or <a href="sndscm.html#remembersoundstate">remember-sound-state</a> in extensions.scm. Both use this sequence:
+<br>
+<pre>
+(lambda (filename)
+ (let ((fd (open filename (logior O_RDWR O_APPEND)))) ; open to write at the end
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> fd "~%~%;;; save-state stuff here ~%")
+ ...
+ (close fd)))
+</pre>
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- after-transform-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="aftertransformhook">after-transform-hook</a> (snd chn scaler)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called just after an FFT (or spectrum) is calculated.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<A NAME="fftpeak">report-fft-peak</A> snd chn scale)
+ (if (and (<a class=quiet href="#transformgraphp" onmouseout="UnTip()" onmouseover="Tip(extsnd_transformgraphp_tip)">transform-graph?</a>)
+ (= (<a class=quiet href="#transformgraphtype" onmouseout="UnTip()" onmouseover="Tip(extsnd_transformgraphtype_tip)">transform-graph-type</a>) <a class=quiet href="#transformgraphtype" onmouseout="UnTip()" onmouseover="Tip(extsnd_transformgraphtype_tip)">graph-once</a>))
+ (<a class=quiet href="#reportinminibuffer" onmouseout="UnTip()" onmouseover="Tip(extsnd_reportinminibuffer_tip)">report-in-minibuffer</a>
+ (number-&gt;string (/ (* 2 (<a class=quiet href="#vctpeak" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctpeak_tip)">vct-peak</a> (<a class=quiet href="#transformtovct" onmouseout="UnTip()" onmouseover="Tip(extsnd_transformtovct_tip)">transform-&gt;vct</a> snd chn)))
+ (<a class=quiet href="#transformsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_transformsize_tip)">transform-size</a> snd chn))))))
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>after-transform-hook</em> report-fft-peak)
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- bad-header-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="badheaderhook">bad-header-hook</a> (filename)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called if a file has a bogus-looking header (that is,
+a header with what appear to be bad values such as a negative number of channels).
+If a hook function returns #t, Snd does not try to open the file.
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> bad-header-hook (lambda (n) #t)) ; don't open bogus-looking files
+</pre>
+If no header is found, <a href="#openrawsoundhook">open-raw-sound-hook</a> is invoked instead ("raw" = "headerless").
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- before-close-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="beforeclosehook">before-close-hook</a> (snd) </code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a file is about to be closed. If a hook function returns #t, the file is not closed (see
+<a href="sndscm.html#checkforunsavededits">check-for-unsaved-edits</a> in extensions.scm).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- before-exit-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="beforeexithook">before-exit-hook</a> ()</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon a request to exit Snd.
+If a hook function returns #t, Snd does not exit. This can be used to check
+for unsaved edits (see above or extensions.scm: <a href="#unsavededitsp">unsaved-edits?</a>).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- before-save-as-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="beforesaveashook">before-save-as-hook</a> (index filename selection srate header-type data-format comment)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called before <a href="#savesoundas">save-sound-as</a> or File:Save as.
+If a hook function returns something other than #f, the
+save is not performed. This hook provides a way to do last minute fixups (srate conversion for example)
+just before a sound is saved. The arguments to the hook function describe the requested attributes of the saved sound;
+'index' is the to-be-saved sound's index; 'filename' is the output file's name; 'selection' is #t if
+we're saving the selection.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>before-save-as-hook</em>
+ (lambda (index filename selection sr type format comment)
+ (if (not (= sr (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> index)))
+ (let ((chns (<a class=quiet href="#chans" onmouseout="UnTip()" onmouseover="Tip(extsnd_chans_tip)">channels</a> index)))
+ (do ((i 0 (+ 1 i)))
+ ((= i chns))
+ (<a class=quiet href="#srcchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_srcchannel_tip)">src-channel</a> (exact-&gt;inexact (/ (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> index) sr)) 0 #f index i))
+ (<a class=quiet href="#savesoundas" onmouseout="UnTip()" onmouseover="Tip(extsnd_savesoundas_tip)">save-sound-as</a> filename index :header-type type :data-format format :srate sr :comment comment)
+ ;; hook won't be invoked recursively
+ (do ((i 0 (+ 1 i)))
+ ((= i chns))
+ (<a class=quiet href="#undo" onmouseout="UnTip()" onmouseover="Tip(extsnd_undo_tip)">undo</a> 1 index i))
+ #t) ; tell Snd that the sound is already saved
+ #f)))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- before-save-state-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="beforesavestatehook">before-save-state-hook</a> (filename)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called before Snd saves its state (<a href="#savestate">save-state</a>). 'filename' is the saved state
+file. If the hook functions return #t, the save state file is opened in append mode (rather than create/truncate),
+so you can write preliminary stuff via this hook, then instruct Snd not to clobber it during the save process.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>before-save-state-hook</em>
+ (lambda (name)
+ (<span onmouseout="UnTip()" onmouseover="Tip('io-open-write in Forth (see fs.fs); File.open in Ruby (I think &mdash; see extensions.rb)')">with-output-to-file name</span>
+ (lambda ()
+ (display (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f ";this comment will be at the top of the saved state file.~%~%"))
+ #t))))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- before-transform-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="beforetransformhook">before-transform-hook</a> (snd chn)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called just before an FFT (or spectrum) is calculated. If a hook function returns
+an integer, that value is used as the starting point (sample number) of the fft. Normally,
+the fft starts from the left window edge. To have it start at mid-window:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>before-transform-hook</em>
+ (lambda (snd chn) ; 0.5 * (left + right) = midpoint
+ (inexact-&gt;exact (round (* 0.5 (+ (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a> snd chn) (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> snd chn)))))))
+</pre></td></tr></table>
+
+The following
+somewhat brute-force code shows a way to have the fft reflect the position
+of a moving mark:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define fft-position #f)
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>before-transform-hook</em> (lambda (snd chn) fft-position))
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#markdraghook" onmouseout="UnTip()" onmouseover="Tip(extsnd_markdraghook_tip)">mark-drag-hook</a> (lambda (id)
+ (set! fft-position (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> id))
+ (<a class=quiet href="#updatetransformgraph" onmouseout="UnTip()" onmouseover="Tip(extsnd_updatetransformgraph_tip)">update-transform-graph</a>)))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- clip-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="cliphook">clip-hook</a> (clipping-value) </code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called whenever a sample is about to be clipped while writing out a sound file.
+The hook function can return the new value.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- close-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="closehook">close-hook</a> (snd)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a file is closed (before the actual close, so the index 'snd' is still valid).
+
+<table border=0><tr><td>
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>close-hook</em>
+ (lambda (snd)
+ (system "sndplay wood16.wav")))
+</pre></td></tr></table>
+
+</td><td width=30></td><td>
+
+<table border=0 cellpadding=5 vspace=10><tr><td bgcolor="Beige"><pre>
+<em class=red>$close_hook</em>.add_hook!("play") do |snd|
+ system("aplay wood16.wav")
+end
+</pre></td></tr></table>
+
+</td></tr></table>
+close-hook is used in <a href="sndscm.html#autosavedoc">autosave.scm</a>,
+the <a href="sndscm.html#xbopen">C-x b</a> support in examp.scm,
+<a href="sndscm.html#remembersoundstate">remember-sound-state</a> in extensions.scm,
+the <a href="sndscm.html#peakenvdoc">peak env</a> support in peak-env.scm, and
+many other places.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- color-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="colorhook">color-hook</a> () </code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called whenever one of the variables associated with the color dialog changes.
+See <a href="sndscm.html#startwaterfall">start-waterfall</a> in snd-gl.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- dac-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="dachook">dac-hook</a> (data) </code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called just before data is sent to DAC; 'data' is a <a href="#sndsounddata">sound-data</a> object.
+See <a href="sndscm.html#withlevelmeters">with-level-meters</a> in snd-motif.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- draw-mark-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="drawmarkhook">draw-mark-hook</a> (mark)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called before a mark is drawn (in XOR mode except in cairo). If the hook function returns #t, the mark is not drawn.
+<a href="sndscm.html#marksynccolor">mark-sync-color</a>
+in snd-motif.scm uses this hook to draw sync'd marks in some other color than the current <a href="#markcolor">mark-color</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- draw-mix-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="drawmixhook">draw-mix-hook</a> (mix old-x old-y x y)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called before a mix tag is drawn. If the hook function returns either #t or a list, the mix tag is not drawn by Snd (the
+assumption is that the hook function drew something). old-x and old-y are the previous mix tag positions (in case
+you're using draw-mix-hook to draw your own mix tag as in musglyphs.scm). x and y give the current position.
+If the hook function returns a list, its two elements (integers) are treated as the mix's tag x and y locations
+for subsequent mouse click hit detection.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- drop-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="drophook">drop-hook</a> (filename) </code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time Snd receives a drag-and-drop event, passing the hook functions the dropped filename.
+If the hook functions return #t, the file is not opened by Snd. Normally if you drag a file icon to the menubar,
+Snd opens it as if you had called <a href="#opensound">open-sound</a>. If you drag the icon to a particular channel,
+Snd mixes it at the mouse location in that channel. To get Snd to
+mix the dragged file even from the menubar:
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>drop-hook</em> (lambda (filename) (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> filename) #t)) ; return #t = we already dealt with the drop
+</pre>
+snd-motif.scm has examples that add a drop callback to an arbitrary widget, or
+change an existing callback (to pass the sound and channel number to the drop callback function, bypassing drop-hook).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- during-open-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="duringopenhook">during-open-hook</a> (fd name reason)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called after file is opened, but before data has been read.
+This provides an opportunity to set sndlib prescaling values:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>during-open-hook</em>
+ (lambda (fd name reason)
+ (if (= (<a class=quiet href="#mussoundheadertype" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundheadertype_tip)">mus-sound-header-type</a> name) <a class=quiet href="#headertype" onmouseout="UnTip()" onmouseover="Tip(extsnd_musraw_tip)">mus-raw</a>)
+ (set! (<a href="#musfileprescaler" onmouseout="UnTip()" onmouseover="Tip(extsnd_musfileprescaler_tip)">mus-file-prescaler</a> fd) 500.0))))
+</pre></td></tr></table>
+
+The prescaling affects only sound data made up of floats or doubles. 'reason' is an integer indicating why this file is being opened:
+<pre>
+ 0: reopen a temporarily closed file (internal to Snd &mdash; normally invisible)
+ 1: sound-open, File:open etc &mdash; the normal path to open a sound
+ 2: copy reader &mdash; another internal case; this happens if a sound is played and edited at the same time
+ 3: insert sound (File:Insert etc)
+ 4: re-read after an edit (file changed, etc &mdash; an invisible editing case)
+ 5: open temp file after an edit (another invisible editing case)
+ 6: mix sound (File:Mix etc)
+</pre>
+So, to restrict the hook action to the normal case where Snd is opening a file for the first time,
+check that 'reason' is 1, or perhaps 1, 3, or 6 (these read the external form of the data).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- enved-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="envedhook">enved-hook</a> (env pt new-x new-y reason)</code> [<b>cascade</b>]
+</td></tr><tr><td></td><td colspan=2>
+Each time a breakpoint is changed in the envelope editor, this hook
+is called; if it returns a list, that list defines the new envelope,
+otherwise the breakpoint is moved (but not beyond the neighboring
+breakpoint), leaving other points untouched. The kind of change that triggered the hook callback
+is indicated by the argument 'reason'. It can be <code>enved-move-point</code>, <code>enved-delete-point</code>,
+or <code>enved-add-point</code>. This hook makes it possible to define attack
+and decay portions in the envelope editor, or use functions such as
+<a href="sndscm.html#stretchenvelope">stretch-envelope</a> from env.scm:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>enved-hook</em>
+ (lambda (env pt x y reason)
+ (if (= reason enved-move-point)
+ (if (and (&gt; x 0.0) (&lt; x (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(sndscm_envelopelastx_tip)">envelope-last-x</a> env))) ; from env.scm
+ (let* ((old-x (list-ref env (* pt 2)))
+ (new-env (<em class=red>stretch-envelope</em> env old-x x)))
+ (list-set! new-env (+ (* pt 2) 1) y)
+ new-env)
+ env)
+ #f)))
+</pre></td></tr></table>
+
+If there are several functions on the hook, each gets the envelope
+result of the preceding function (if a function returns #f, the envelope
+is not changed). A math-type would call this a "function composition"
+method combination; a filter-type would say "cascade";
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- exit-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="exithook">exit-hook</a> ()</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon exit.
+It can be used
+to perform cleanup activities; in <a href="sndscm.html#peakenvdoc">peak-env.scm</a>, for example, we save peak-env info upon exit:
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>exit-hook</em> (lambda () (for-each <a class=quiet href="sndscm.html#peakenvdoc" onmouseout="UnTip()" onmouseover="Tip(sndscm_savepeakenvinfo_tip)">save-peak-env-info</a> (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+</pre>
+For more examples, see extensions.scm and autosave.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- graph-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="graphhook">graph-hook</a> (snd chn y0 y1) </code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time a graph is updated or redisplayed.
+If its hook functions return #t, the display is not updated.
+See examp.scm for many examples. If you want to add your own graphics to the display, use <a href="#aftergraphhook">after-graph-hook</a>.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>graph-hook</em>
+ (lambda (snd chn y0 y1)
+ "set the dot size depending on the number of samples being displayed"
+ (let ((dots (- (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a> snd chn) (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> snd chn))))
+ (if (&gt; dots 100)
+ (set! (<a class=quiet href="#dotsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_dotsize_tip)">dot-size</a> snd chn) 1)
+ (if (&gt; dots 50)
+ (set! (<a class=quiet href="#dotsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_dotsize_tip)">dot-size</a> snd chn) 2)
+ (if (&gt; dots 25)
+ (set! (<a class=quiet href="#dotsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_dotsize_tip)">dot-size</a> snd chn) 3)
+ (set! (<a class=quiet href="#dotsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_dotsize_tip)">dot-size</a> snd chn) 5))))
+ #f)))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- help-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="helphook">help-hook</a> (subject help-string)</code> [<b>cascade</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called from <a href="#sndhelp">snd-help</a> with the current help subject and default help-string.
+Say we want the index.scm
+procedure <a href="sndscm.html#html">html</a> called any time snd-help is called (from C-? for example):
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>help-hook</em> (lambda (subject help) (<a class=quiet href="sndscm.html#html" onmouseout="UnTip()" onmouseover="Tip(sndscm_html_function_tip)">html</a> subject) #f))
+</pre>
+If there is more than one hook function, each function's result is passed as input to the next function.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- initial-graph-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="initialgraphhook">initial-graph-hook</a> (snd chn dur) </code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called the first time a given channel is displayed (when the sound is first opened).
+If the hook function returns a list, the list's contents are interpreted as:
+<pre>
+ (list x0 x1 y0 y1 label ymin ymax)
+</pre>
+(all trailing values are optional), where these numbers set the
+initial x and y axis limits and the x axis label.
+The default (an empty hook) is equivalent to:
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>initial-graph-hook</em> (lambda (snd chn dur) (list 0.0 0.1 -1.0 1.0 "time" -1.0 1.0)))
+</pre>
+The 'dur' argument is the total length in seconds of the displayed portion of the channel, so to cause the
+entire sound to be displayed initially:
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>initial-graph-hook</em> (lambda (snd chn dur) (list 0.0 dur)))
+</pre>
+To get other the data limits (rather than the default y axis limits of -1.0 to 1.0), you can use <a href="#mussoundmaxamp">mus-sound-maxamp</a>,
+but if that sound's maxamp isn't already known, it can require a long process of reading the file. The following hook procedure
+uses the maxamp data if it is already available or the file is short:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>initial-graph-hook</em>
+ (lambda (snd chn dur)
+ (if (or (<a class=quiet href="#mussoundmaxampexists" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundmaxampexists_tip)">mus-sound-maxamp-exists?</a> (<a class=quiet href="#filename" onmouseout="UnTip()" onmouseover="Tip(extsnd_filename_tip)">file-name</a> snd))
+ (&lt; (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd chn) 10000000))
+ (let* ((amp-vals (<a class=quiet href="#mussoundmaxamp" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundmaxamp_tip)">mus-sound-maxamp</a> (<a class=quiet href="#filename" onmouseout="UnTip()" onmouseover="Tip(extsnd_filename_tip)">file-name</a> snd)))
+ (max-val (max 1.0 (list-ref amp-vals (+ (* chn 2) 1)))))
+ ;; max amp data is list: (sample value sample value ...)
+ (list 0.0 dur (- max-val) max-val)) ; these are the new y-axis limits
+ (list 0.0 dur -1.0 1.0)))) ; max amp unknown, so use defaults
+</pre></td></tr></table>
+
+A similar problem affects the 'dur' argument. If the file is very long, Snd starts
+a background process reading the file's data to get an overall amplitude envelope,
+and this envelope is what it actually displays when you zoom out to look at the entire
+sound. If you set 'x1' to 'dur', you effectively get two such processes
+contending for access to the data. One way around this is to save the envelope as
+a "peak envelope" in Snd's nomenclature;
+load <a href="sndscm.html#peakenvdoc">peak-env.scm</a> to make this process automatic.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- key-press-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="keypresshook">key-press-hook</a> (snd chn key state)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon key press while the mouse is in the lisp graph (the third graph,
+to the right of the time and fft graphs).
+If its function returns #t, the key press is not passed to the main handler.
+'state' refers to the control, meta, and shift keys.
+<a href="sndscm.html#enveddoc">start-enveloping</a> in enved.scm uses this hook to add C-g and C-. support to the
+channel-specific envelope editors.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- lisp-graph-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="lispgraphhook">lisp-graph-hook</a> (snd chn)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called just before the lisp graph is updated or redisplayed (see <a href="#displaydb">display-db</a>).
+If its function returns a list of pixels (xm style), these are used in order by the list of graphs (if any), rather than Snd's default set
+(this makes it possible to use different colors for the various graphs).
+If it returns a function (of no arguments), that function is called rather than the standard graph routine:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>lisp-graph-hook</em>
+ (lambda (snd chn)
+ (lambda ()
+ (<a class=quiet href="#drawstring" onmouseout="UnTip()" onmouseover="Tip(extsnd_drawstring_tip)">draw-string</a> "hi"
+ (<a class=quiet href="#xtoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_xtoposition_tip)">x-&gt;position</a> 0.5 snd chn <a class=quiet href="#ytoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_lispgraph_tip)">lisp-graph</a>)
+ (<a class=quiet href="#ytoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_ytoposition_tip)">y-&gt;position</a> 0.0 snd chn <a class=quiet href="#ytoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_ytoposition_tip)">lisp-graph</a>)
+ snd chn))))
+</pre></td></tr></table>
+
+For a fancy example, see <a href="sndscm.html#displaybarkfft">display-bark-fft</a> in dsp.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- listener-click-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="listenerclickhook">listener-click-hook</a> (textpos)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a click occurs in the listener; the 'textpos' argument is the position in the text
+(a character number) where the click occurred.
+See <a href="sndscm.html#clickforlistenerhelp">click-for-listener-help</a> in draw.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mark-click-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="markclickhook">mark-click-hook</a> (mark)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a mark is clicked; return #t to squelch the default minibuffer mark identification. The following
+hook function is used in <a href="sndscm.html#withmarkedsound">with-marked-sound</a> in ws.scm to display arbitrary info about a mark.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mark-click-hook</em>
+ (lambda (n)
+ (if (not (defined? 'mark-properties)) (load "marks.scm"))
+ (<a class=quiet href="#infodialog" onmouseout="UnTip()" onmouseover="Tip(extsnd_infodialog_tip)">info-dialog</a> "Mark Help"
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "Mark ~A~A:~% sample: ~D = ~,3F secs~A~A"
+ n
+ (let ((name (<a class=quiet href="#markname" onmouseout="UnTip()" onmouseover="Tip(extsnd_markname_tip)">mark-name</a> n)))
+ (if (&gt; (string-length name) 0)
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f " (~S)" name)
+ ""))
+ (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> n)
+ (/ (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> n) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> (car (<a class=quiet href="#markhome" onmouseout="UnTip()" onmouseover="Tip(extsnd_markhome_tip)">mark-home</a> n))))
+ (if (not (= (<a class=quiet href="#marksync" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksync_tip)">mark-sync</a> n) 0))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~% sync: ~A" (<a class=quiet href="#marksync" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksync_tip)">mark-sync</a> n))
+ "")
+ (let ((props (<a class=quiet href="sndscm.html#markproperties" onmouseout="UnTip()" onmouseover="Tip(sndscm_markproperties_tip)">mark-properties</a> n)))
+ (if (and (list? props)
+ (not (null? props)))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~% properties: '~A" props)
+ ""))))
+ #t))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mark-drag-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="markdraghook">mark-drag-hook</a> (mark)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a mark is dragged.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (report-mark-location id)
+ ;; print current mark location in minibuffer
+ (let ((samp (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> id))
+ (sndchn (<a class=quiet href="#markhome" onmouseout="UnTip()" onmouseover="Tip(extsnd_markhome_tip)">mark-home</a> id)))
+ (<a class=quiet href="#reportinminibuffer" onmouseout="UnTip()" onmouseover="Tip(extsnd_reportinminibuffer_tip)">report-in-minibuffer</a>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "mark ~A: sample: ~D (~,3F) ~A[~D]: ~,3F"
+ id samp
+ (/ samp (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> (car sndchn)))
+ (<a class=quiet href="#shortfilename" onmouseout="UnTip()" onmouseover="Tip(extsnd_shortfilename_tip)">short-file-name</a> (car sndchn))
+ (cadr sndchn)
+ (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> samp (car sndchn) (cadr sndchn))))))
+
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mark-drag-hook</em> report-mark-location)
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mark-drag-triangle-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="markdragtrianglehook">mark-drag-triangle-hook</a> (mark x time dragged-before)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a mark play triangle is dragged. The smoothness of the response to the drag motion is
+largely determined by <a href="#dacsize">dac-size</a>.
+'dragged-before' is #f when the drag starts and #t thereafter. 'x' is the mouse x location in the current
+graph. 'time' is the uninterpreted (graphics toolkit) time at which the drag event was reported. If the hook function returns #t,
+Snd takes no further action. To set up to play, then interpret the motion yourself, return #f on the first call,
+and #t thereafter:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(let ((first-x 0))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mark-drag-triangle-hook</em>
+ (lambda (id x time dragged-before)
+ (if (not dragged-before)
+ (set! first-x x)
+ (set! (<a class=quiet href="#speedcontrol" onmouseout="UnTip()" onmouseover="Tip(extsnd_speedcontrol_tip)">speed-control</a>) (/ (- x first-x) 16.0)))
+ dragged-before)))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mark-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="markhook">mark-hook</a> (mark snd chn reason)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a mark is added, deleted, or moved (but not while moving).
+'reason' can be 0: add, 1: delete, 2: move (via set! mark-sample), 3: delete all marks, 4: release (after drag).
+In the "release" case, the hook is called upon button release before any edits (control-drag of mark) or sorting (simple drag),
+and if the <a href="#marksync">mark-sync</a> is not 0, the hook is called on each syncd mark.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<A NAME="snpmark">snap-mark-to-beat</a>)
+ ;; when a mark is dragged, its end position is always on a beat
+ (let ((mark-release 4))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mark-hook</em>
+ (lambda (mrk snd chn reason)
+ (if (= reason mark-release)
+ (let* ((samp (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> mrk))
+ (bps (/ (<a class=quiet href="#beatsperminute" onmouseout="UnTip()" onmouseover="Tip(extsnd_beatsperminute_tip)">beats-per-minute</a> snd chn) 60.0))
+ (sr (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> snd))
+ (beat (floor (/ (* samp bps) sr)))
+ (lower (inexact-&gt;exact (/ (* beat sr) bps)))
+ (higher (inexact-&gt;exact (/ (* (+ 1 beat) sr) bps))))
+ (set! (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> mrk)
+ (if (&lt; (- samp lower) (- higher samp))
+ lower
+ higher))))))))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mix-click-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mixclickhook">mix-click-hook</a> (mix)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a mix tag is clicked; return #t to omit the default action which is to print the mix id in
+the minibuffer. A more informative version is <a href="sndscm.html#mixclickinfo">mix-click-info</a> in mix.scm.
+Here's an example that sets a mix's amps to 0 if you click it (see <a href="sndscm.html#mixclicksetsamp">mix-click-sets-amp</a>
+in mix.scm for a fancier version):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mix-click-hook</em>
+ (lambda (n)
+ (set! (<a class=quiet href="#mixamp" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixamp_tip)">mix-amp</a> n) 0.0)
+ #t))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mix-drag-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mixdraghook">mix-drag-hook</a> (mix x y)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a mix is dragged.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mix-drag-hook</em>
+ (lambda (n x y)
+ (<a class=quiet href="#reportinminibuffer" onmouseout="UnTip()" onmouseover="Tip(extsnd_reportinminibuffer_tip)">report-in-minibuffer</a>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "mix ~A at ~D: ~,3F"
+ n (<a class=quiet href="#mixposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixposition_tip)">mix-position</a> n)
+ (exact->inexact (/ (<a class=quiet href="#mixposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixposition_tip)">mix-position</a> n) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>)))))))
+</pre></td></tr></table>
+
+A neat example is to set up an empty sound with a 1.0 in sample 0, mix in a vct containing one element of 0.5, then set
+up this mix-drag-hook:
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> mix-drag-hook (lambda (id x y) (<a class=quiet href="#updatetransformgraph" onmouseout="UnTip()" onmouseover="Tip(extsnd_updatetransformgraph_tip)">update-transform-graph</a>)))
+</pre>
+and turn on the FFT graph. As you drag the mix, you can see the spectral effect of that
+moving value as a comb filter.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mix-release-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mixreleasehook">mix-release-hook</a> (mix samps)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called after a mix has been dragged by the mouse to a new position.
+'samps' is the number of samples moved during the drag. If its function returns #t, the final position
+of the mix is
+hook's responsibility. See <a href="sndscm.html#snapmarktobeat">snap-mix-to-beat</a> in mix.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-click-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mouseclickhook">mouse-click-hook</a> (snd chn button state x y axis) </code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon a mouse button release or click (with various exceptions). If its function returns #t, the click is ignored by Snd.
+See the <a href="sndscm.html#makecurrentwindowdisplay">current-window-location</a> function in draw.scm. Here's an example:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (click-to-center snd chn button state x y axis)
+ ;; if mouse click in time domain graph, set cursor as normally, but also center the window
+ (if (= axis <a class=quiet onmouseout="UnTip()" onmouseover="Tip(extsnd_time_graph_tip)">time-graph</a>)
+ (let ((samp (inexact-&gt;exact (* (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> snd) (<a class=quiet href="#positiontox" onmouseout="UnTip()" onmouseover="Tip(extsnd_positiontox_tip)">position-&gt;x</a> x snd chn)))))
+ (set! (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a> snd chn) samp)
+ (set! (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a> snd chn)
+ (- samp (inexact-&gt;exact (* .5 (- (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> snd chn) (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a> snd chn))))))
+ (<a class=quiet href="#updatetimegraph" onmouseout="UnTip()" onmouseover="Tip(extsnd_updatetimegraph_tip)">update-time-graph</a>)
+ #t)
+ #f))
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mouse-click-hook</em> click-to-center)
+
+;;; this example disables button 2 -&gt; insert selection
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mouse-click-hook</em>
+ (lambda (snd chn button state x y axis)
+ (and (= axis <a class=quiet onmouseout="UnTip()" onmouseover="Tip(extsnd_time_graph_tip)">time-graph</a>) (= button 2))))
+</pre></td></tr></table>
+
+The mouse scroll wheel is sometimes reported as buttons 4 and 5; in the next example,
+turning the wheel zooms the graph in or out:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mouse-click-hook</em>
+ (lambda (snd chn button state x y axis)
+ (if (and (= axis <a class=quiet onmouseout="UnTip()" onmouseover="Tip(extsnd_time_graph_tip)">time-graph</a>)
+ (or (= button 4) (= button 5))) ; mouse scroll wheel
+ (let ((midpoint (* 0.5 (apply + (<a class=quiet href="#xbounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_xbounds_tip)">x-bounds</a>))))
+ (dur (/ (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>)))
+ (range (if (= button 4)
+ (* -0.25 (apply - (<a class=quiet href="#xbounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_xbounds_tip)">x-bounds</a>))) ; zoom in
+ (abs (apply - (<a class=quiet href="#xbounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_xbounds_tip)">x-bounds</a>)))))) ; zoom out
+ (set! (<a class=quiet href="#xbounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_xbounds_tip)">x-bounds</a>) (list (max 0.0 (- midpoint range))
+ (min dur (+ midpoint range))))))
+ #f))
+</pre></td></tr></table>
+
+Here is a Forth example:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+mouse-click-hook lambda: &lt;{ snd chn button state x y axis -- }&gt;
+ axis time-graph = if
+ $" freq: %.3f" '( snd chn #f cursor snd chn spot-freq ) string-format
+ snd #f report-in-minibuffer
+ else
+ #f
+ then
+; add-hook!
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-drag-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mousedraghook">mouse-drag-hook</a> (snd chn button state x y)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse is dragged within the lisp graph (see enved.scm or rtio.scm).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-enter-graph-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mouseentergraphhook">mouse-enter-graph-hook</a> (snd chn)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse enters a channel's drawing area (graph pane).
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mouse-enter-graph-hook</em>
+ (lambda (snd chn)
+ (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~A[~A]" (<a class=quiet href="#shortfilename" onmouseout="UnTip()" onmouseover="Tip(extsnd_shortfilename_tip)">short-file-name</a> snd) chn))))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-enter-label-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mouseenterlabelhook">mouse-enter-label-hook</a> (type position label)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse enters a file viewer or region label.
+The 'type' is 1 for view files list, and 2 for regions.
+The 'position' is the scrolled list position of the label.
+The label itself is 'label'. We can use the <a href="sndscm.html#finfo">finfo</a> procedure in examp.scm
+to popup file info as follows:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mouse-enter-label-hook</em>
+ (lambda (type position name)
+ (if (not (= type 2))
+ (<a class=quiet href="#infodialog" onmouseout="UnTip()" onmouseover="Tip(extsnd_infodialog_tip)">info-dialog</a> name (finfo name)))))
+</pre></td></tr></table>
+
+See also <a href="sndscm.html#nbdoc">files-popup-info</a> in nb.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-enter-listener-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mouseenterlistenerhook">mouse-enter-listener-hook</a> (widget)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse enters the listener pane. This hook, along with the parallel graph hook
+makes it possible to set up Snd to behave internally like a window manager with pointer focus. That is, to
+ensure that the pane under the mouse is the one that receives keyboard input, we can define the following
+hook procedures:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mouse-enter-graph-hook</em>
+ (lambda (snd chn)
+ (if (<a class=quiet href="#soundp" onmouseout="UnTip()" onmouseover="Tip(extsnd_soundp_tip)">sound?</a> snd) (<a class=quiet href="#focuswidget" onmouseout="UnTip()" onmouseover="Tip(extsnd_focuswidget_tip)">focus-widget</a> (car (<a class=quiet href="#channelwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_channelwidgets_tip)">channel-widgets</a> snd chn))))))
+
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mouse-enter-listener-hook</em>
+ (lambda (widget)
+ (<a class=quiet href="#focuswidget" onmouseout="UnTip()" onmouseover="Tip(extsnd_focuswidget_tip)">focus-widget</a> widget)))
+</pre></td></tr></table>
+
+I much prefer this style of operation.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-enter-text-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mouseentertexthook">mouse-enter-text-hook</a> (widget)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse enters a text widget (this is the third of the pointer focus hooks).
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mouse-enter-text-hook</em>
+ (lambda (w)
+ (<a class=quiet href="#focuswidget" onmouseout="UnTip()" onmouseover="Tip(extsnd_focuswidget_tip)">focus-widget</a> w)))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-leave-graph-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mouseleavegraphhook">mouse-leave-graph-hook</a> (snd chn)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse leaves a channel's drawing area (graph pane).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-leave-label-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mouseleavelabelhook">mouse-leave-label-hook</a> (type position name)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse exits one of the labels covered by <a href="#mouseenterlabelhook">mouse-enter-label-hook</a>.
+See <a href="sndscm.html#nbdoc">nb.scm</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-leave-listener-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mousleavelistenerhook">mouse-leave-listener-hook</a> (widget)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse leaves the listener pane.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-leave-text-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mousleavetexthook">mouse-leave-text-hook</a> (widget)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the mouse leaves a text widget.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mouse-press-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="mousepresshook">mouse-press-hook</a> (snd chn button state x y)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon a mouse button press within the lisp graph (see enved.scm). The 'x' and 'y' values are
+relative to the lisp graph axis (as if the raw mouse pixel position was passed through
+<a href="#positiontox">position-&gt;x</a> and <a href="#positiontoy">position-&gt;y</a>).
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- mus-error-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="muserrorhook">mus-error-hook</a> (error-type error-message)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon mus-error.
+If its functions return #t, Snd ignores the error (it assumes you've handled it via the hook).
+This hook is used in <a href="sndscm.html#playsound">play-sound</a> in play.scm to flush an error message
+that the Snd ALSA support code generates (or used to generate).
+Both mus_error and mus_print run this hook; in the mus_print case, the 'type' is mus-no-error (0).
+You can redirect mus_print output from stderr (the default) to stdout via:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>mus-error-hook</em>
+ (lambda (typ msg)
+ (and (= typ 0) ; it's mus_print, not mus_error
+ (display msg)))) ; display returns some non-#f result, I assume
+</pre></td></tr></table>
+
+To decode the 'error-type' argument, see <a href="#muserrortypetostring">mus-error-type-&gt;string</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- name-click-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="nameclickhook">name-click-hook</a> (snd)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the sound name is clicked (in the label in the minibuffer region of the sound's pane).
+If the function returns #t, the usual highly informative minibuffer babbling is squelched.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>name-click-hook</em>
+ (lambda (snd) ; toggle read-only
+ (set! (<a class=quiet href="#readonly" onmouseout="UnTip()" onmouseover="Tip(extsnd_readonly_tip)">read-only</a> snd) (not (<a class=quiet href="#readonly" onmouseout="UnTip()" onmouseover="Tip(extsnd_readonly_tip)">read-only</a> snd)))
+ #t))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- new-sound-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="newsoundhook">new-sound-hook</a> (filename)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called whenever a new sound file is being created. <a href="sndscm.html#sound-let">sound-let</a> in ws.scm uses
+this hook to keep track of newly created temporary sounds so that it can delete them once they are no longer needed.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- new-widget-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="newwidgethook">new-widget-hook</a> (widget)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time a dialog or a new set of channel or sound widgets is created.
+This is used in misc.scm (paint-all) to
+make sure all newly created widgets have the same background pixmaps.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- open-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="openhook">open-hook</a> (filename)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called before a sound file is opened.
+If the function returns #t, or the sound is not readable (bad header, etc) the file is not opened
+and any corresponding <a href="#afteropenhook">after-open-hook</a> functions are not called.
+If it returns a string (a filename), that file is opened instead of the original one.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>open-hook</em>
+ (lambda (filename)
+ (if (= (<a class=quiet href="#mussoundheadertype" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundheadertype_tip)">mus-sound-header-type</a> filename) <a class=quiet href="#headertype" onmouseout="UnTip()" onmouseover="Tip(extsnd_headertype_tip)">mus-raw</a>)
+ ;; check for "OggS" first word, if found, translate to something Snd can read
+ (if (call-with-input-file filename
+ (lambda (fd)
+ (and (char=? (read-char fd) #\O)
+ (char=? (read-char fd) #\g)
+ (char=? (read-char fd) #\g)
+ (char=? (read-char fd) #\S))))
+ (let ((aufile (string-append filename ".au")))
+ (if (file-exists? aufile) (delete-file aufile))
+ (system (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "ogg123 -d au -f ~A ~A" aufile filename))
+ aufile) ; now open-sound will read the new .au file
+ #f)
+ #f)))
+</pre></td></tr></table>
+See also <a href="sndscm.html#openbuffer">open-buffer</a> in examp.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- open-raw-sound-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="openrawsoundhook">open-raw-sound-hook</a> (filename current-choices)</code> [<b>cascade</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time <a href="#opensound">open-sound</a> encounters a headerless file.
+Its result can be a list describing the raw file's attributes (thereby bypassing the Raw File Dialog and so on):
+<code>(list chans srate data-format data-location data-length)</code> where trailing elements can
+be omitted ('data-location' defaults to 0, and 'data-length' defaults to the file length in bytes).
+If there is more than one function on the hook list, functions after the first get the
+on-going list result (if any) as the 'current-choices' argument (the empty list is the default).
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>open-raw-sound-hook</em> (lambda (file choices) (list 1 44100 <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_dataformat_tip)">mus-lshort</a>)))
+</pre>
+Return '() to accept all the current raw header defaults; return #f to fallback on the Raw File Dialog.
+The raw header defaults are stereo, 44100 Hz, big endian short data; these values can be changed in the
+Raw File Dialog, by calling <a href="#openrawsound">open-raw-sound</a> with explicit arguments,
+or via <a href="#musheaderrawdefaults">mus-header-raw-defaults</a>.
+If the hook function returns #t, the <a href="#opensound">open-sound</a> returns without opening.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- optimization-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="optimizationhook">optimization-hook</a> (message)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time the optimizer hits something it can't handle; 'message' tries to give some information about the situation.
+<pre>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>optimization-hook</em> (lambda (n) (display (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~A~%" n))))
+</pre>
+Normally, if the optimizer fails for some reason, it falls back silently on the Scheme evaluator, so
+the code simply runs slower. This hook gives you a way to find out why the optimizer gave up.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- orientation-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="orientationhook">orientation-hook</a> () </code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called whenever one of the variables associated with the orientation dialog changes.
+See <a href="sndscm.html#startwaterfall">start-waterfall</a> in snd-gl.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- output-comment-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="outputcommenthook">output-comment-hook</a> (str)</code> [<b>cascade</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called in the Save-As dialog to set the default output comment value. 'str' is the current sound's comment.
+If there is more than one hook function, each function's result is passed as input to the next function in the list.
+
+<table border=0 cellpadding=5 vspace=10><tr><td>
+<pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>output-comment-hook</em>
+ (lambda (str) ; append a time-stamp
+ (string-append str ": written " (strftime "%a %d-%b-%Y %H:%M %Z" (localtime (current-time))))))
+
+ ;; in Ruby: format("%s: written %s", str, Time.new.localtime.strftime("%d-%b %H:%M %Z"))
+</pre>
+</td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- output-name-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="outputnamehook">output-name-hook</a> (current-name)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called in the New File dialog. If it returns a filename, that name is presented in the New File dialog,
+making it slightly easier to set default output names.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(let ((file-ctr -1))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>output-name-hook</em>
+ (lambda (ignored-name)
+ (set! file-ctr (+ file-ctr 1))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~A-~D.snd" ; make new file name based on date and file-ctr: "Jun-01-23.snd"
+ (strftime "%b-%d" (localtime (current-time)))
+ file-ctr))))
+</pre></td></tr></table></td></tr>
+<tr><td colspan=3 height=16></td></tr>
+
+
+<!-- peak-env-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="peakenvhook">peak-env-hook</a> (snd chn)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon completion of a new peak envelope.
+See <a href="sndscm.html#makecurrentwindowdisplay">make-current-window-display</a> in draw.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- play-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="playhook">play-hook</a> (samps)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time a buffer is about to be
+filled for the DAC. The buffer size is 'samps'.
+See <a href="sndscm.html#enveddoc">enved.scm</a> and <a href="sndscm.html#marksdoc">marks.scm</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- print-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="printhook">print-hook</a> (text)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time some Snd-generated response ('text') is about to be appended to the listener.
+If the function returns some non-#f result, Snd assumes you've sent the text out yourself, as well as any needed prompt.
+The prompt is important! Snd uses it to find the current form to evaluate, so if your print hook function
+forgets to include it, you can end up with a comatose listener. To get out of this state, include
+the prompt by hand (i.e. type in the shell that Snd started in, "&gt;(reset-hook! print-hook)").
+This is intended to make it possible to
+distinguish Snd responses from user-typing, or add arbitrarily fancy prompts, but both should be handled
+in some other way &mdash; I should rewrite this part of Snd.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>print-hook</em>
+ (lambda (msg)
+ (if (char=? (string-ref msg 0) #\newline)
+ (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> msg)
+ (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~A~%[~A]~%~A" ;need newline just before listener-prompt
+ msg
+ (strftime "%d-%b %H:%M %Z" (localtime (current-time)))
+ (<a class=quiet href="#listenerprompt" onmouseout="UnTip()" onmouseover="Tip(extsnd_listenerprompt_tip)">listener-prompt</a>))))))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- read-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="readhook">read-hook</a> (text)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time a line is typed into the listener (it is triggered by the carriage return).
+</td></tr><tr><td></td><td colspan=2></td></tr>
+
+
+<!-- save-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="savehook">save-hook</a> (snd name)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time a sound ('snd') is about to be saved.
+If its function returns #t, the file is not saved. 'name' is #f unless
+the file is being saved under a new name (as in <a href="#savesoundas">save-sound-as</a>).
+See <a href="sndscm.html#autosavedoc">autosave.scm</a>.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- save-state-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="savestatehook">save-state-hook</a> (temp-filename)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time the <a href="#savestate">save-state</a>
+mechanism is about to create a new temporary file to save some edit history sample data; that is,
+each channel's edit history data is saved in a separate temporary file, and this hook provides
+a way to specify the name of that file.
+'temp-filename' is the temporary file name that will be used unless
+the hook function returns a different one (as a string). This hook provides a way to
+keep track of which files are used in a given saved state batch, so
+that later cleanup is easier to manage.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- select-channel-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="selectchannelhook">select-channel-hook</a> (snd chn)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a channel is selected (after the sound has been selected).
+The function arguments are the sound's index and the channel number.
+select-channel-hook is used in <a href="sndscm.html#playbetweenmarks">play-between-marks</a>
+to keep the loop bounds up-to-date.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- select-sound-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="selectsoundhook">select-sound-hook</a> (snd)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a sound is selected. The argument is the about-to-be-selected sound.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- snd-error-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="snderrorhook">snd-error-hook</a> (error-message)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon <a href="#snderror">snd-error</a>. If the listener is closed, it is also called upon any Scheme, Ruby, or Forth error.
+If it returns #t, Snd flushes the error (it assumes you've
+dealt with it via the hook).
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>snd-error-hook</em>
+ (lambda (msg)
+ (<a class=quiet href="#play" onmouseout="UnTip()" onmouseover="Tip(extsnd_play_tip)">play</a> "bong.snd") ; or if xm is loaded, (XBell (XtDisplay (cadr (<a class=quiet href="#mainwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_mainwidgets_tip)">main-widgets</a>))) 10)
+ #f))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- snd-warning-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="sndwarninghook">snd-warning-hook</a> (warning-message)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called upon <a href="#sndwarning">snd-warning</a>.
+If it returns #t, Snd flushes the warning (it assumes you've
+reported it via the hook).
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define without-warnings
+ (lambda (thunk)
+ (define no-warning (lambda (msg) #t))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>snd-warning-hook</em> no-warning)
+ (thunk)
+ (remove-hook! <em class=red>snd-warning-hook</em> no-warning)))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- start-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="starthook">start-hook</a> (filename)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when Snd starts.
+If its function returns #t, Snd exits immediately.
+Say we are so annoyed with Snd's really very fine file browser that we want
+Snd to exit back to the shell if its file argument is not
+found (this code has to be in the ~/.snd init file):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>start-hook</em>
+ (lambda (file)
+ (if (not (file-exists? file))
+ (begin
+ (display file) (display " does not exist")
+ #t))))
+</pre></td></tr></table></td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- start-playing-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="startplayinghook">start-playing-hook</a> (snd)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a sound is about to be played.
+If its function returns #t, Snd does not play.
+We can use this hook to replace "play" with "play-selection" if the
+selection is active:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>start-playing-hook</em>
+ (lambda (snd)
+ (if (and (<a class=quiet href="#selectionok" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionok_tip)">selection?</a>)
+ (<a class=quiet href="#selectionmember" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionmember_tip)">selection-member?</a> snd))
+ (begin
+ (<a class=quiet href="#playselection" onmouseout="UnTip()" onmouseover="Tip(extsnd_playselection_tip)">play-selection</a>)
+ #t) ; there's a selection so don't play the entire sound
+ #f))) ; no selection, so go ahead and play it all
+</pre></td></tr></table>
+
+See also <a href="sndscm.html#reportmarknames">report-mark-names</a> in marks.scm.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- start-playing-selection-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="startplayingselectionhook">start-playing-selection-hook</a> ()</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the selection is about to be played.
+If its function returns #t, Snd does not play the selection.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- stop-dac-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="stopdachook">stop-dac-hook</a> ()</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when Snd stops playing and turns off the DAC, normally upon <a href="#musaudioclose">mus-audio-close</a>.
+It is used by <a href="sndscm.html#withlevelmeters">with-level-meters</a> to start draining away the red bubble in the VU meter.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- stop-playing-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="stopplayinghook">stop-playing-hook</a> (snd)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when a sound finishes playing. stop-playing-hook may be called more often than start-playing-hook.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- stop-playing-selection-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="stopplayingselectionhook">stop-playing-selection-hook</a> ()</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when the selection finishes playing.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- time-graph-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="timegraphhook">time-graph-hook</a> (snd chn)</code> [<b>progn</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called just before each channel's time domain graph is updated if <a href="#channelstyle">channel-style</a> is
+<code>channels-combined</code> (that is, when all the channels are superimposed in one graph).
+If its function returns a pixel, that color is used to draw that channel's data.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>time-graph-hook</em>
+ (lambda (snd chn)
+ (lambda ()
+ (apply <a class=quiet href="#makecolor">make-color</a> (<a class=quiet href="#colormapref">colormap-ref</a> (<a class=quiet href="#colormap">colormap</a>) (/ chn (<a class=quiet href="#channels">channels</a> snd)))))))
+</pre></td></tr></table>
+
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- update-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="updatehook">update-hook</a> (snd)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+update-hook is called just before a sound is updated ("update" means the sound is re-read from the disk, flushing the current version; this
+is useful if you overwrite a sound file with some other program, while viewing it in Snd).
+The update process can be triggered by a variety of situations, not just by <a href="#updatesound">update-sound</a>.
+The hook is passed the sound's index. If its function returns #t, the update is cancelled (this is not
+recommended!); if it returns a procedure of one argument, that procedure is called upon
+completion of the update operation; its argument is the (possibly different) sound.
+Snd tries to maintain the index across the update, but if you change the number of channels
+the newly updated sound may have a different index. <a href="sndscm.html#addmarkpane">add-mark-pane</a> in snd-motif.scm uses
+the returned procedure to make sure the mark pane is reactivated right away when a sound is updated. The basic idea is:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>update-hook</em>
+ (lambda (snd-about-to-be-updated)
+ ;; this function called just before update
+ (lambda (updated-snd)
+ ;; this code executed when update is complete
+ (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> "ok!"))))
+</pre></td></tr></table>
+
+I use update-hook to make sure the y axis bounds reflect the new maxamp, if it is greater than 1.0:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>update-hook</em>
+ (lambda (old-snd)
+ (lambda (snd)
+ (do ((i 0 (+ 1 i)))
+ ((= i (<a class=quiet href="#chans" onmouseout="UnTip()" onmouseover="Tip(extsnd_chans_tip)">channels</a> snd)))
+ (let ((mx (<a class=quiet href="#maxamp" onmouseout="UnTip()" onmouseover="Tip(extsnd_maxamp_tip)">maxamp</a> snd i)))
+ (if (&gt; mx 1.0)
+ (set! (<a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a> snd i) (list (- mx) mx))
+ (if (and (&gt; (cadr (<a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a> snd)) 1.0) ; previous (pre-update) version was &gt; 1.0
+ (&lt;= mx 1.0)) ; but current is not, so reset axes
+ (set! (<a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a> snd i) (list -1.0 1.0)))))))))
+</pre></td></tr></table>
+
+Say we're editing a sound in several different windows, and want to save and re-apply any
+edits we may have in the other windows when we save the sound from one window (all the others
+then get the exploding bomb icon because their underlying data has changed):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(let ((eds #f))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <em class=red>update-hook</em>
+ (lambda (cursnd) ; called before actual update -- save our edits
+ (set! eds (<a href="#editlisttofunction">edit-list-&gt;function</a> cursnd 0))
+ (lambda (newsnd) ; called after update -- reapply our edits
+ (if eds (eds newsnd 0))))))
+</pre></td></tr></table>
+
+Actually this only works if there are just two windows on the same (mono) sound. I suppose for
+trickier cases, we could set up an association list with the old sound ("cursnd" above) and its edits,
+but it's probably better to bind some keystroke to a function that performs the same operations.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- view-files-select-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="viewfilesselecthook">view-files-select-hook</a> (dialog filename)</code>
+</td></tr><tr><td></td><td colspan=2>
+This hook is called each time a file is selected in a View Files dialog's files list.
+</td></tr><tr><td colspan=3 height=16></td></tr>
+
+
+<!-- window-property-changed-hook -->
+<tr><td colspan=3 bgcolor="#f2f4ff">
+<code><a class=def name="windowpropertychangedhook">window-property-changed-hook</a> (command)</code> [<b>or</b>]
+</td></tr><tr><td></td><td colspan=2>
+This hook is called when Snd sees a SND_COMMAND window property change.
+If its function returns #t, the command is not evaluated. This is an internal debugging hook.
+</td></tr>
+</table>
+<br><br>
+
+<table width="50%" border=0><tr><td bgcolor="#EEFDEE" valign="middle"><h4>Channel-specific hooks:</h4></td></tr></table>
+<pre>
+ <a class=def name="edithook">edit-hook</a> (snd chn)
+ <a class=def name="undohook">undo-hook</a> (snd chn)
+ <a class=def name="afteredithook">after-edit-hook</a> (snd chn)
+</pre>
+
+<table border=0><tr><td width=30><br></td><td>
+These are functions that return the hooks in question associated with the specified channel.
+The functions on these hooks are thunks &mdash; they should take no arguments.
+edit-hook is called just before any attempt to edit the channel's data; if it returns #t,
+the edit is cancelled. So,
+</td></tr></table>
+<pre>
+ Scheme: (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> (edit-hook snd chn) (lambda () #t))
+ Ruby: edit_hook(snd, chn).add_hook!(\"stop-edit\") do | | true end
+ Forth: snd chn edit-hook lambda: &lt;{ }&gt; #t ; add-hook!
+</pre>
+<table border=0><tr><td width=30><br></td><td>
+halts any attempt to edit the data; this is even more restrictive than setting the read-only
+flag because the latter only refuses to overwrite the current data. undo-hook is called
+just after any undo, redo, or revert that affects the channel. after-edit-hook is called
+after an edit, but before after-graph-hook (<a href="sndscm.html#addmarkpane">add-mark-pane</a> in snd-motif.scm
+uses this hook to update a mark list after each edit
+so that the displayed mark positions are correct).
+You can use edit-hook to set
+up protected portions of the edit history:
+
+<table border=0 cellpadding=5 hspace=20 vspace=10><tr><td><pre>
+(define* (protect :optional snd chn)
+ "(protect :optional snd chn) disallows any edits before the current one"
+ (let* ((edit-pos (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> snd chn))
+ (hook (<em class=red>edit-hook</em> snd chn)))
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_reset_hook_tip)">reset-hook!</a> hook)
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> hook
+ (lambda ()
+ (let ((val (&lt; (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> snd chn) edit-pos)))
+ (if val (<a class=quiet href="#reportinminibuffer" onmouseout="UnTip()" onmouseover="Tip(extsnd_reportinminibuffer_tip)">report-in-minibuffer</a> "protected"))
+ val)))))
+
+(define* (unprotect :optional snd chn)
+ "(unprotect :optional snd chn) allows edits at any edit history position"
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_reset_hook_tip)">reset-hook!</a> (<em class=red>edit-hook</em> snd chn)))
+</pre></td></tr></table>
+
+<a href="sndscm.html#enveddoc">enved.scm</a> uses several of these hooks to implement an envelope editor in lisp.
+add-mark-pane in snd-motif.scm uses them to make sure the mark list reflects the current edit history location.
+See also autosave.scm. <small>It is possible for after-edit-hook to be called more often that edit-hook, or
+vice-versa; edit-hook may be called more than once on a given attempt to edit; if a long computation is required
+Snd may check edit-hook ahead of time to avoid unnecessary work.</small>
+
+</td></tr></table>
+
+
+<br><br>
+<table width="80%" border=0><tr><td bgcolor="lightsteelblue" valign="middle"><h3><A NAME="sndobjects">Snd's objects</a></h3></td></tr></table>
+
+<p>Snd presents its various data structures as a list
+of sounds, each with a list of channels, each with lists of edits,
+marks, and mixes. The sound data itself is accessed through
+a variety of structures and functions, each aimed at a particular
+kind of use. The accessors from lowest level up are:
+samplers (one sample at a time iterators) and frame-readers (a "frame" is a multichannel sample),
+channel-at-a-time blocks (vcts, map-channel, etc), multichannel blocks (sound-data objects, map-sound, etc),
+a few historical leftovers that follow the "sync" field (scale-to, etc), and finally
+the top-level operations such as save-sound-as (these are used in the File menu, etc).
+In the following sections, I'll start with the lowest level and work upwards, more or less.
+But before launching into samplers, I need to explain a few things
+about the following documentation.
+</p>
+
+<p>
+Each sound is an object in Snd, and has an
+associated index. To refer to that sound, you can use either the object or the index.
+In the argument lists
+below, 'snd' as an argument refers to either the sound object or its index. It normally defaults to the currently
+selected sound. Similarly, 'chn' is the channel number, starting from 0, and defaults
+to the currently selected channel. So if there's only one sound active, and it has only
+one channel, (cursor), (cursor 0), (cursor 0 0), and (cursor (integer-&gt;sound 0)) all refer to the same
+thing. If you want to refer to the currently selected sound explicitly, use
+<a href="#selectedsound">selected-sound</a>.
+</p>
+
+<p>Some functions take <a class=quiet href="sndclm.html#optional-key" onmouseout="UnTip()" onmouseover="Tip(sndclm_optional_key_tip)">optional-key</a> arguments, as in CLM.
+These are marked "&amp;optional-key" below, followed by the keywords themselves. As in CLM,
+the keywords can be omitted.
+</p>
+
+<p>In many cases, the 'snd', 'chn', and 'reg' arguments
+can be #t which
+means "all"; if 'snd' is #t, all sounds are included.
+<code>(<a class=quiet href="#expandcontrol" onmouseout="UnTip()" onmouseover="Tip(extsnd_expandcontrol_tip)">expand-control</a> #t)</code> returns a list of the current
+control panel expansion settings of all sounds, and
+<code>(set! (<a class=quiet href="#transformgraphp" onmouseout="UnTip()" onmouseover="Tip(extsnd_transformgraphp_tip)">transform-graph?</a> #t #t) #t)</code>
+turns on the fft display in all channels of all sounds.
+</p>
+
+<p>When an error occurs, the function throws a tag such as 'no-such-sound,
+'no-active-selection, etc.
+All the functions that take sound and channel args ('snd chn' below) can return the errors
+'no-such-sound and 'no-such-channel; all the mix-related functions can return 'no-such-mix;
+all the region-related functions can return 'no-such-region; all selection-oriented functions
+can return 'no-active-selection. To reduce clutter, I'll omit mention
+of these below.
+</p>
+<br>
+
+
+<!-- INDEX samplers:samplers -->
+<!-- ---------------------------------------- SAMPLERS ---------------------------------------- -->
+
+<table width="50%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h3><A NAME="samplers">Samplers</a></h3></td></tr></table>
+<p>
+The simplest data access function is <a href="#sample">sample</a> which returns the sample at
+a given position in a sound's channel. This simplicity, however, comes at
+a price in computation: if the desired sample is not in Snd's
+in-core (already loaded) view of the data, it has to go get the sample,
+which can sometimes require that it open, read, and close a sound file.
+The result is that sample can bring your code
+to a grinding halt. There are two alternatives, leaving aside the scanning
+and mapping functions mentioned below. One involves keeping the buffer of
+data around explicitly (<a class=quiet href="#channeltovct" onmouseout="UnTip()" onmouseover="Tip(extsnd_channeltovct_tip)">channel-&gt;vct</a>), and the other involves the
+use of a special object known as a sampler. The sampler
+returns the next sample in its sound each time it is called; this kind
+of access is sometimes called an "enumerator" (Ruby) or perhaps "iterator" (Gtk+).
+The buffer approach (<a class=quiet href="#channeltovct" onmouseout="UnTip()" onmouseover="Tip(extsnd_channeltovct_tip)">channel-&gt;vct</a> in <a href="grfsnd.html#expsrc">expsrc</a>)
+is better if you're jumping around in the data, the sample-by-sample approach if you're treating
+the data as a sequence of samples.
+To get a sampler,
+you create a reader (via <a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a>) giving it the start position, the sound and channel
+to read, and the initial read direction, then get data via <a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> (which remembers the
+read direction passed to <a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a>),
+or <a class=quiet href="#nextsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_nextsample_tip)">next-sample</a> (read forward) and
+<a class=quiet href="#previoussample" onmouseout="UnTip()" onmouseover="Tip(extsnd_previoussample_tip)">previous-sample</a> (read backward);
+when done, you can close the reader with <a class=quiet href="#freesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_freesampler_tip)">free-sampler</a>,
+but it's usually not necessary; the
+garbage collector will take care of it if you forget (but, sigh, the GC can be dilatory at times).
+</p>
+
+<p>There is a similar set of functions giving access to the mix data.
+<a class=quiet href="#makemixsampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makemixsampler_tip)">make-mix-sampler</a> returns a mix reader for the desired mix,
+<a class=quiet href="#mixsamplerQ" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixsamplerQ_tip)">mix-sampler?</a> returns #t if its argument in a mix sampler,
+and <a class=quiet href="#readmixsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readmixsample_tip)">read-mix-sample</a> returns the next sample (before it is mixed into
+the output).
+</p>
+
+<p>Multichannel iterations can be handled via <a href="sndscm.html#framereaders">frame-readers</a>. These are currently
+implemented in frame.scm.
+</p>
+
+
+<!-- -------------------------------- SAMPLER TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- copy-sampler -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="copysampler">copy-sampler</a> (obj)</code>
+</td></tr><tr><td width=30><br></td><td>
+copy-sampler returns a copy of 'obj' which can be any kind of sampler.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- free-sampler -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="freesampler">free-sampler</a> (obj)</code>
+</td></tr><tr><td></td><td>
+free-sampler
+releases the sampler 'obj'. In most cases, you don't need to call this
+function because the garbage collector handles the sampler object, but it doesn't hurt anything (but don't try to use a sampler
+after you've freed it!). If you're using zillions of samplers in an optimized (run-based) loop that
+doesn't trigger garbage collection, freeing the samplers explicitly can reduce
+demands on memory.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- make-mix-sampler -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="makemixsampler">make-mix-sampler</a> (mix :optional (beg 0))</code>
+</td></tr><tr><td></td><td>
+make-mix-sampler creates a mix-sampler reading 'mix' starting (in the mix input) at 'beg'.
+See <a href="sndscm.html#mixtovct">mix-&gt;vct</a> in mix.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- make-region-sampler -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="makeregionsampler">make-region-sampler</a> (:optional start reg chn (dir 1))</code>
+</td></tr><tr><td></td><td>
+make-region-sampler creates a sampler reading channel 'chn' of the region 'reg' starting
+at sample 'start', and reading forward if 'dir' is 1, backwards if 'dir' is -1.
+It is not safe to assume that this reader will return zeros beyond the region boundaries.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- make-sampler -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="makesampler">make-sampler</a> (:optional start snd chn dir edpos)</code>
+</td></tr><tr><td></td><td>
+make-sampler creates a sampler reading the given channel
+starting at sample 'start' with initial read direction 'dir'
+(1=forward, -1=backward). 'edpos' is the edit history position to read;
+it defaults to the current edit.
+<pre>
+ :<em class=typing>(open-sound "oboe.snd")</em>
+ <em class=listener>#&lt;sound 0&gt;</em>
+ :<em class=typing>(define reader (make-sampler 1000))</em>
+ <em class=listener>reader</em>
+ :<em class=typing>reader</em>
+ <em class=listener>#&lt;sampler: oboe.snd[0: 0] from 1000, at 1000, forward&gt;</em>
+ :<em class=typing>(read-sample reader)</em>
+ <em class=listener>0.0328369140625</em>
+ :<em class=typing>(sample 1000)</em>
+ <em class=listener>0.0328369140625</em>
+ :<em class=typing>(next-sample reader)</em>
+ <em class=listener>0.0347900390625</em>
+ :<em class=typing>(sample 1001)</em>
+ <em class=listener>0.0347900390625</em>
+ :<em class=typing>(sampler-home reader)</em>
+ <em class=listener>(#&lt;sound 0&gt; 0)</em>
+ :<em class=typing>(sampler-position reader)</em>
+ <em class=listener>1002</em>
+</pre>
+One use of 'edpos' is to get the difference
+between two edits:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define snd-diff
+ (lambda () ;assume mono, get diff between current state and previous
+ (let* ((index (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>))
+ (edit-pos (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> index))
+ (previous-edit (<em class=red>make-sampler</em> 0 0 index 1 (- edit-pos 1))))
+ (lambda (x)
+ (- x (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> previous-edit)) #f))))
+
+(<a class=quiet href="#mapchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_mapchannel_tip)">map-channel</a> (snd-diff))
+</pre></td></tr></table>
+
+Once the reader has been set up to read at a given edit position, subsequent
+edits won't affect it. One sequence that takes advantage of this is: make-sampler, scale-by 0,
+then run an overlap-add process on the data from before the scaling.
+<br><br>
+'snd' can be a filename (a string); in this way a sampler
+can read external sounds without going to the trouble of loading them into Snd.
+<pre>
+ (define reader (make-sampler 100 "oboe.snd"))
+</pre>
+'snd' also can be a mix or region.
+make-sampler is probably the most useful function in Snd; there are lots of examples
+in the Scheme, Ruby, and Forth files.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-sampler? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixsamplerQ">mix-sampler?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+mix-sampler? returns #t if 'obj' is a mix-sampler.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- next-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="nextsample">next-sample</a> (obj)</code>
+</td></tr><tr><td></td><td>
+next-sample returns the next sample (reading forward) read by the sampler 'obj'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- previous-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="previoussample">previous-sample</a> (obj)</code>
+</td></tr><tr><td></td><td>
+previous-sample returns the previous sample in the stream read by the sampler 'obj'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- read-mix-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="readmixsample">read-mix-sample</a> (obj)</code>
+</td></tr><tr><td></td><td>
+read-mix-sample returns the next sample read by the mix-sampler 'obj'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- read-region-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="readregionsample">read-region-sample</a> (obj)</code>
+</td></tr><tr><td></td><td>
+read-region-sample returns the next sample read by the region-sampler 'obj'.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (region-&gt;vct reg :optional (chn 0))
+ (if (<a class=quiet href="#regionok" onmouseout="UnTip()" onmouseover="Tip(extsnd_regionok_tip)">region?</a> reg)
+ (if (&lt; chn (channels reg))
+ (let* ((reader (<em class=red>make-region-sampler</em> 0 reg chn))
+ (len (<a class=quiet href="#regionframes" onmouseout="UnTip()" onmouseover="Tip(extsnd_regionframes_tip)">region-frames</a> reg))
+ (data (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> len)))
+ (do ((i 0 (+ 1 i)))
+ ((= i len) data)
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data i (<em class=red>reader</em>))))
+ (throw 'no-such-channel (list "region-&gt;vct" reg chn)))
+ (throw 'no-such-region (list "region-&gt;vct" reg))))
+</pre></td></tr></table>
+
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- read-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="readsample">read-sample</a> (obj)</code>
+</td></tr><tr><td></td><td>
+read-sample returns the next sample read by the sampler 'obj',
+reading in the direction set by <a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-sampler? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionsamplerQ">region-sampler?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+region-sampler? returns #t if 'obj' is a region sampler.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sampler-at-end? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sampleratendQ">sampler-at-end?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+sampler-at-end? returns #t if the sampler 'obj' (any kind of reader) is at the end of the sound (or whatever it is reading),
+and hence is returning 0.0 each time it is called. When the last "real" sample is returned, the at-end? flag is still false; when it
+becomes true, the sampler returns a 0.0 sample.
+See <a href="sndscm.html#locatezero">locate-zero</a> in examp.scm, or <a href="sndscm.html#linearsrcchannel">linear-src-channel</a> in dsp.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sampler-home -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="samplerhome">sampler-home</a> (obj)</code>
+</td></tr><tr><td></td><td>
+sampler-home returns information describing the source of the data the sampler 'obj' is reading.
+if 'obj' is a sound sampler, it returns a list with the sound and channel number associated with 'obj'.
+If 'obj' is a mix reader, it returns the mix.
+Finally, if 'obj' is a region reader, it returns a list with the region.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sampler-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="samplerposition">sampler-position</a> (obj)</code>
+</td></tr><tr><td></td><td>
+sampler-position returns the
+current (sample-wise) location of the sampler 'obj' (any kind of reader).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sampler? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="samplerQ">sampler?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+sampler? returns #t if 'obj' is a sampler.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+</table>
+
+<p>If your extension language supports it, the read-sample functions can be omitted: <code>(reader)</code> is the same as <code>(<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> reader)</code>.
+</p>
+
+<br>
+<table width="35%" border=0><tr><td bgcolor="#EEFDEE" valign="middle"><h4>Snd-&gt;sample</h4></td></tr></table>
+
+<p>There is a Snd-specific CLM-style generator that redirects CLM instrument input (via in-any, ina, etc)
+to Snd data, snd-&gt;sample.
+</p>
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- make-snd->sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="makesndtosample">make-snd-&gt;sample</a> (:optional snd)</code>
+</td></tr><tr><td width=30><br></td><td>
+make-snd-&gt;sample creates a Snd data reader for use with CLM's in-any, file-&gt;sample, etc.
+</td></tr>
+<tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd->sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sndtosample">snd-&gt;sample</a> (gen frame :optional chan)</code>
+</td></tr><tr><td><br></td><td>
+snd-&gt;sample gets the next sample from the data accessed by 'gen', similar to file-&gt;sample.
+If *reverb* is a snd-&gt;sample generator, for example,
+<a class=quiet href="sndclm.html#ina" onmouseout="UnTip()" onmouseover="Tip(sndclm_ina_tip)">ina</a> and <a class=quiet href="sndclm.html#filetosample" onmouseout="UnTip()" onmouseover="Tip(sndclm_filetosample_tip)">file-&gt;sample</a> actually call snd-&gt;sample.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd->sample? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sndtosamplep">snd-&gt;sample?</a> (obj)</code>
+</td></tr><tr><td><br></td><td>
+snd-&gt;sample? returns #t if 'obj' is a snd-&gt;sample generator.
+</td></tr>
+
+</table>
+<br>
+
+
+<!-- INDEX Vcts:Vcts -->
+<table width="50%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h3><A NAME="Vcts">Vcts</a></h3></td></tr></table>
+<p>
+Many of the Snd and CLM functions handle vectors (arrays) of data.
+By defining a new vector type, named vct, and providing a package
+of old-style array-processing calls upon that type, we can speed up many
+operations by a factor of 30 &mdash; enough of a difference to warrant
+the added complexity.
+<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> creates a new vct object. It is freed by the
+garbage collector when it can't be referenced any further. To get
+an element of a vct, use <a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a>; similarly <a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a>
+sets an element.
+Once created, a vct can be passed to a variety of built-in
+functions:</p>
+
+<table border=0><tr><td>
+
+<table border=0 cellpadding=5><tr><td><pre>
+Scheme:
+ (define hi (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> 100))
+ (<a class=quiet href="#vctfill" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctfill_tip)">vct-fill!</a> hi 3.14)
+ (<a class=quiet href="#vctscale" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctscale_tip)">vct-scale!</a> hi -1.0)
+</pre></td></tr></table>
+</td><td>
+
+<table border=0 cellpadding=5><tr><td bgcolor="Beige"><pre>
+Ruby:
+ hi = make_vct(100)
+ vct_fill!(hi, 3.14)
+ vct_scale!(hi, -1.0)
+</pre></td></tr></table>
+</td><td>
+
+<table border=0 cellpadding=5><tr><td bgcolor="LightGreen"><pre>
+Forth: variable hi
+ 100 0.0 make-vct hi !
+ hi @ 3.14 vct-fill!
+ hi @ -1.0 vct-scale!
+</pre></td></tr></table>
+</td></tr></table>
+
+
+<p>Now our vct 'hi' has 100 -3.14's. </p>
+
+<!-- -------------------------------- VCT TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- list->vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="listtovct">list-&gt;vct</a> (lst)</code>
+</td></tr><tr><td width=30></td><td>
+return a new vct with elements of list 'lst' (equivalent to the <a href="#vct">vct</a> function).
+<pre>
+ :<em class=typing>(list-&gt;vct (list 0.1 0.2 0.3))</em>
+ <em class=listener>#&lt;vct[len=3]: 0.100 0.200 0.300&gt;</em>
+ :<em class=typing>(vct 0.1 0.2 0.3)</em>
+ <em class=listener>#&lt;vct[len=3]: 0.100 0.200 0.300&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- make-vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="makevct">make-vct</a> (len (initial-element 0.0))</code>
+</td></tr><tr><td></td><td>
+make-vct creates a vct of size 'len'.
+<pre>
+ :<em class=typing>(make-vct 3 0.1)</em>
+ <em class=listener>#&lt;vct[len=3]: 0.100 0.100 0.100&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-date->vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><em class=emdef>sound-data-&gt;vct</em> (sdobj (chan 0) (v #f))</code>
+</td></tr><tr><td></td><td>
+sound-data-&gt;vct places the sound-data data in a vct, returning 'v' (if given) or a new vct.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vct">vct</a> args...</code>
+</td></tr><tr><td></td><td>
+vct is equivalent to list-&gt;vct with 'args' as the list: <code>(vct 1 2 3)</code> is the same as <code>(<a class=quiet href="#listtovct" onmouseout="UnTip()" onmouseover="Tip(extsnd_listtovct_tip)">list-&gt;vct</a> '(1 2 3))</code>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctp">vct?</a> (v)</code>
+</td></tr><tr><td></td><td>
+vct? returns #t if 'v' is a vct.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-add! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctadd">vct-add!</a> (v1 v2 (off 0))</code>
+</td></tr><tr><td></td><td>
+vct-add! performs element-wise add: <code>v1[i + off] += v2[i]</code>, returning 'v1'. To protect the
+original vct, use vct-copy: <code>(vct-add! (vct-vopy v1) v2)</code>.
+<pre>
+:<em class=typing>(define v1 (vct .1 .2 .3))</em>
+<em class=listener>#&lt;unspecified&gt;</em>
+:<em class=typing>(vct-add! v1 (vct .3 .2 .1))</em>
+<em class=listener>#&lt;vct[len=3]: 0.400 0.400 0.400&gt;</em>
+:<em class=typing>v1</em>
+<em class=listener>#&lt;vct[len=3]: 0.400 0.400 0.400&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-copy -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctcopy">vct-copy</a> (v)</code>
+</td></tr><tr><td></td><td>
+vct-copy returns a copy of the vct 'v'.
+
+<!-- INDEX copying:Copying -->
+<A NAME="copying"></a>
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<blockquote><small>
+<br>
+copy file: in Scheme: copy-file, in Ruby: File.copy or File.syscopy<br>
+copy string: in Guile or Forth: string-copy<br>
+copy list: in Guile or Forth: list-copy or copy-tree<br>
+copy vct: <a href="#vctcopy">vct-copy</a>, <a href="#vcttovector">vct-&gt;vector</a>, <a href="sndscm.html#vcttoframe">vct-&gt;frame</a><br>
+copy mix: <a href="sndscm.html#mixtovct">mix-&gt;vct</a><br>
+copy sampler: <a href="#copysampler">copy-sampler</a><br>
+copy (clone) current sound edit state: <a href="#clonesoundas">clone-sound-as</a><br>
+copy channel data: <a href="#channeltovct">channel-&gt;vct</a>, or <a href="#savesoundas">save-sound-as</a><br>
+copy selection data: <a href="#selection2vct">selection-&gt;vct</a> or <a href="#saveselection">save-selection</a><br>
+copy region data: <a href="#regiontovct">region-&gt;vct</a>, <a href="#regiontovct">region-&gt;vct</a>, <a href="#saveregion">save-region</a>, or <a href="sndscm.html#regiontosounddata">region-&gt;sound-data</a><br>
+copy transform data: <a href="#transformtovct">transform-&gt;vct</a><br>
+copy sound-data: <a href="#sounddatatovct">sound-data-&gt;vct</a><br>
+copy a frame: <a href="sndscm.html#framecopy">frame-copy</a>, <a href="sndscm.html#frametovct">frame-&gt;vct</a><br>
+copy vector: <a href="#vectortovct">vector-&gt;vct</a><br>
+copy random state: Guile: copy-random-state, or use <a href="sndclm.html#mus-rand-seed">mus-rand-seed</a><br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-fill! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctfill">vct-fill!</a> (v val)</code>
+</td></tr><tr><td></td><td>
+vct-fill! sets each element of 'v' to 'val': <code>v[i] = val</code>. It returns 'v'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-length -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctlength">vct-length</a> (v)</code>
+</td></tr><tr><td></td><td>
+vct-length returns the length of 'v'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-map! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctmap">vct-map!</a> (v proc)</code>
+</td></tr><tr><td></td><td>
+vct-map! sets each element of 'v' to the value returned by the thunk 'proc': <code>(vct-map! v (lambda () 3.0))</code>
+is the same as <code>(<a class=quiet href="#vctfill" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctfill_tip)">vct-fill!</a> v 3.0)</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-move! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctmove">vct-move!</a> (v new old :optional backwards)</code>
+</td></tr><tr><td></td><td>
+vct-move moves a block of values within a vct: <code>v[new++] = v[old++]</code>, or
+if 'backwards' is #t: <code>v[new--] = v[old--]</code>. It returns 'v'.
+<pre>
+:<em class=typing>(define v1 (vct 1 2 3 4 5 6 7 8 9 10))</em>
+<em class=listener>#&lt;unspecified&gt;</em>
+:<em class=typing>(vct-move! v1 0 5)</em>
+<em class=listener>#&lt;vct[len=10]: 6.000 7.000 8.000 9.000 10.000 6.000 7.000 8.000 9.000 10.000&gt;</em>
+</pre>
+
+We can use vct-move! to maintain a sliding window on a sound:
+
+<pre>
+ (<a class=quiet href="#mapchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_mapchannel_tip)">map-channel</a>
+ (let* ((size 100)
+ (samps (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> size)))
+ (lambda (y)
+ (<em class=red>vct-move!</em> samps 0 1)
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> samps (- size 1) y)
+ ...)))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-multiply! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctmultiply">vct-multiply!</a> (v1 v2)</code>
+</td></tr><tr><td></td><td>
+vct-multiply! performs element-wise multiply of two vcts: <code>v1[i] *= v2[i]</code>. It returns 'v1'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-offset! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctoffset">vct-offset!</a> (v val)</code>
+</td></tr><tr><td></td><td>
+vct-offset! adds 'val' to each element of 'v': <code>v[i] += val</code>. It returns 'v'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-peak -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctpeak">vct-peak</a> (v)</code>
+</td></tr><tr><td></td><td>
+vct-peak returns the maximum absolute value of the elements of 'v'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-ref -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctref">vct-ref</a> (v pos)</code>
+</td></tr><tr><td></td><td>
+vct-ref returns the element 'pos' in 'v': <code>v[pos]</code>.
+<pre>
+:<em class=typing>(vct-ref (vct .1 .2 .3) 1)</em>
+<em class=listener>0.200000002980232</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-reverse! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctreverse">vct-reverse!</a> (v :optional size)</code>
+</td></tr><tr><td></td><td>
+vct-reverse! reverses the elements of 'v' (in-place), returning 'v'.
+If 'size' is given, the reversal centers around it.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-scale! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctscale">vct-scale!</a> (v scl)</code>
+</td></tr><tr><td></td><td>
+vct-scale! multiplies each element of 'v' by 'scl': <code>v[i] *= scl</code>. It returns 'v'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-set! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctset">vct-set!</a> (v pos val)</code>
+</td></tr><tr><td></td><td>
+vct-set! sets the vct 'v' element at 'pos' to 'val': <code>v[pos] = val</code>.
+In Scheme, this is the same as <code>(set! (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> v pos) val)</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-subtract! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctsubtract">vct-subtract!</a> (v1 v2)</code>
+</td></tr><tr><td></td><td>
+vct-subtract! performs an element-wise subtract: <code>v1[i] -= v2[i]</code>. It returns 'v1'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-subseq -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctsubseq">vct-subseq</a> (v start :optional (end len) nv)</code>
+</td></tr><tr><td></td><td>
+vct-subseq returns a new vct (or 'nv' if given) with the elements of 'v' between 'start' and 'end' inclusive. 'end' defaults
+to the end of 'v'.
+<pre>
+:<em class=typing>(define v1 (vct 1 2 3 4 5 6 7 8 9 10))</em>
+<em class=listener>#&lt;unspecified&gt;</em>
+:<em class=typing>(vct-subseq v1 3 6)</em>
+<em class=listener>#&lt;vct[len=4]: 4.000 5.000 6.000 7.000&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct+ -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vctplus">vct+</a> (obj1 obj2)</code>
+</td></tr><tr><td></td><td>
+vct+ combines <a class=quiet href="#vctadd" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctadd_tip)">vct-add!</a> and <a class=quiet href="#vctoffset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctoffset_tip)">vct-offset!</a>,
+depending on the type of its arguments.
+<code>(vct+ v 1.0)</code> or <code>(vct+ 1.0 v)</code> is the same as
+<code>(vct-offset! v 1.0)</code>, and <code>(vct+ v1 v2)</code> is the same as <code>(vct-add! v1 v2)</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct* -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vcttimes">vct*</a> (obj1 obj2)</code>
+</td></tr><tr><td></td><td>
+vct* combines <a class=quiet href="#vctmultiply" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctmultiply_tip)">vct-multiply!</a> and <a class=quiet href="#vctscale" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctscale_tip)">vct-scale!</a>,
+depending on the type of its arguments.
+<code>(vct* v 2.0)</code> or <code>(vct* 2.0 v)</code> is the same as <code>(vct-scale! v 2.0)</code>, and
+<code>(vct* v1 v2)</code> is the same as <code>(vct-multiply! v1 v2)</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct->channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vcttochannel">vct-&gt;channel</a> (v :optional (beg 0) dur snd chn edpos origin)</code>
+</td></tr><tr><td></td><td>
+vct-&gt;channel sets the samples from 'beg' to 'beg' + 'dur' from the values in 'v'.
+This changes (edits) the channel, so 'origin' provides a way to name the edit (for the edit history list and whatnot).
+Since with-sound can write its output to a vct, we can use it with vct-&gt;channel to paste in an fm-violin note as
+an edit:
+<pre>
+
+ (vct-&gt;channel (<a class=quiet href="sndscm.html#withsound" onmouseout="UnTip()" onmouseover="Tip(sndscm_wsdoc_tip)">with-sound</a> (:output (make-vct 44100)) (<a class=quiet href="sndscm.html#fmviolin" onmouseout="UnTip()" onmouseover="Tip(sndscm_fmviolin_tip)">fm-violin</a> 0 1 440 .1)))
+</pre>
+To add such a note to whatever is already present, use either <a href="#mixvct">mix-vct</a> or
+<a href="sndscm.html#mixsounddata">mix-sound-data</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct->list -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vcttolist">vct-&gt;list</a> (v)</code>
+</td></tr><tr><td></td><td>
+vct-&gt;list returns a list with elements of 'v'.
+<pre>
+ ;; Scheme:
+ :<em class=typing>(vct-&gt;list (list-&gt;vct (list 0.1 0.2 0.3)))</em>
+ <em class=listener>(0.100000001490116 0.200000002980232 0.300000011920929)</em> ; (sigh...)
+
+ ;; Ruby:
+ :<em class=typing>vct2list(list2vct([0.1, 0.2, 0.3]))</em>
+ <em class=listener>[0.100000001490116, 0.200000002980232, 0.300000011920929]</em>
+
+ ;; Forth:
+ <em class=listener>snd&gt;</em> <em class=typing>'( 0.1 0.2 0.3 ) list-&gt;vct vct-&gt;list</em>
+ <em class=listener>'( 0.1 0.2 0.3 )</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct->sound-data -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><em class=emdef>vct-&gt;sound-data</em> (v sd :optional (chan 0))</code>
+</td></tr><tr><td></td><td>
+vct-&gt;sound-data places the data in vct 'v' in the sound-data object 'sd', returning sd.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct->string -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vcttostring">vct-&gt;string</a> (v)</code>
+</td></tr><tr><td></td>
+<td>
+vct-&gt;string returns a Scheme-readable string describing 'v'. The standard way of displaying a vct
+uses "#&lt;vct...&gt;" which is not useful if you want to read the string later as a piece of Scheme code.
+<pre>
+ :<em class=typing>(define v1 (make-vct 3 0.1))</em>
+ prints v1 as <em class=listener>#&lt;vct[len=3]: 0.100 0.100 0.100&gt;</em>
+ :<em class=typing>(vct-&gt;string v1)</em>
+ <em class=listener>"(vct 0.100 0.100 0.100)"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct-&gt;vector -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vcttovector">vct-&gt;vector</a> (v)</code>
+</td></tr><tr><td></td><td>
+vct-&gt;vector returns a vector with the elements of 'v'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vector-&gt;vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vectortovct">vector-&gt;vct</a> (vect)</code>
+</td></tr><tr><td></td><td>
+vector-&gt;vct returns a vct with elements of vector 'vect'.
+</td></tr>
+
+</table>
+<br>
+
+<p>Many of the functions described below can take a vct as an argument;
+there are also several functions that create and fill vcts with data:</p>
+<pre>
+ <a href="#regiontovct">region-&gt;vct</a> region samples to vct
+ <a href="#transformtovct">transform-&gt;vct</a> fft data to vct
+ <a href="#channeltovct">channel-&gt;vct</a> channel samples to vct
+ <a href="sndscm.html#mixtovct">mix-&gt;vct</a> mix samples to vct
+ <a href="#sounddatatovct">sound-data-&gt;vct</a> sound-data samples to vct
+ <a href="#vectortovct">vector-&gt;vct</a> vector data to vct (assumed to be floats)
+ <a href="#selection2vct">selection-&gt;vct</a> selected samples to vct
+ <a href="sndscm.html#filetovct">file-&gt;vct</a> file data to vct
+ <a href="sndscm.html#frametovct">frame-&gt;vct</a> frame data to vct
+ <a href="sndscm.html#vcttoframe">vct-&gt;frame</a> vct data to frame
+</pre>
+
+<p>We could combine some of these vct functions to implement Horner's rule
+(the <a href="sndclm.html#polynomial">polynomial</a> generator) over an entire
+channel:
+</p>
+<table border=0 cellpadding=5 hspace=20><tr><td><pre>
+(define (vct-polynomial v coeffs)
+ (let* ((v-len (<em class=red>length</em> v))
+ (num-coeffs (<em class=red>length</em> coeffs))
+ (new-v (<em class=red>make-vct</em> v-len (<em class=red>vct-ref</em> coeffs (- num-coeffs 1)))))
+ (do ((i (- num-coeffs 2) (- i 1)))
+ ((&lt; i 0))
+ (<em class=red>vct-offset!</em> (<em class=red>vct-multiply!</em> new-v v) (<em class=red>vct-ref</em> coeffs i)))
+ new-v))
+
+(define* (channel-polynomial coeffs :optional snd chn)
+ (let ((len (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd chn)))
+ (<em class=red>vct-&gt;channel</em> (vct-polynomial (<em class=red>channel-&gt;vct</em> 0 len snd chn) coeffs) 0 len snd chn)))
+
+;;; (channel-polynomial (<em class=red>vct</em> 0.0 .5)) = x*.5
+;;; (channel-polynomial (<em class=red>vct</em> 0.0 1.0 1.0 1.0)) = x*x*x + x*x + x
+</pre></td></tr></table>
+
+<p>There is one slightly
+unusual function in this family: vct-map!.
+This is a do-loop (or for-each) over a vct, calling some
+function to get the values to assign into the vct. For example</p>
+<pre>
+ (<a class=quiet href="#vctmap" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctmap_tip)">vct-map!</a> out-data (lambda ()
+ (<a class=quiet href="sndclm.html#convolve" onmouseout="UnTip()" onmouseover="Tip(sndclm_convolve_tip)">convolve</a> cnv (lambda (dir)
+ (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> sf)))))
+</pre>
+<p>in the cnvtest function in <a href="sndscm.html#exampdoc">examp.scm</a> is calling the convolve generator and
+assigning the result to each successive member of the out-data vct.
+</p>
+
+<p>In some cases (s7, Ruby) it's possible to access a vct's
+elements with the syntax <code>(v index)</code>, equivalent to <code>(<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> v index)</code>.
+In Ruby, vcts partake in the Enumerable and Comparable classes, and have a variety of
+additional methods: map, each, &lt;=&gt;, etc. See vct.c and the Ruby documentation for a complete list.
+</p>
+<pre>
+ :<em class=typing>v1</em>
+ <em class=listener>#&lt;vct[len=10]: 0.100 0.100 0.100 3.000 0.100 0.100 0.100 0.100 0.100 0.100&gt;</em>
+ :<em class=typing>v1.find_all {|x| x &gt; 1.0 }</em>
+ <em class=listener>[3.0, 4.0]</em>
+ :<em class=typing>v1.max</em>
+ <em class=listener>4.0</em>
+ :<em class=typing>v2 = make_vct(10, 0.1)</em>
+ <em class=listener>#&lt;vct[len=10]: 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100&gt;</em>
+ :<em class=typing>v2 &lt; v1</em>
+ <em class=listener>true</em>
+</pre>
+
+<br><br>
+
+
+<!-- INDEX sndsounddata:sound-data -->
+<table width="50%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h3><A NAME="sndsounddata">Sound-data</a></h3></td></tr></table>
+
+<p>Another Snd object containing sound samples is the sound-data object; it can be viewed either as an array of vcts,
+each vct representing one channel's data, or as an array of frames, each frame holding a sample from
+each channel at that position in the sound. <a href="sndscm.html#framedoc">frame.scm</a> has a number of useful functions that use
+sound-data objects.
+As with vcts, sound-data objects partake in the Enumerable and Comparable
+classes in Ruby.
+</p>
+
+<!-- -------------------------------- SOUND-DATA TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- make-sound-data -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="makesounddata">make-sound-data</a> (chans frames)</code>
+</td></tr><tr><td width=30><br></td><td>
+make-sound-data returns a new sound-data object with 'chans' arrays, each with 'frames' elements.
+<pre>
+ :<em class=typing>(make-sound-data 2 5)</em>
+ <em class=listener>#&lt;sound-data[chans=2, length=5]:
+ (0.000 0.000 0.000 0.000 0.000)
+ (0.000 0.000 0.000 0.000 0.000)&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-add! -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounddataadd">sound-data-add!</a> (sd1 sd2)</code>
+</td></tr><tr><td><br></td><td>
+sound-data-add! adds the contents of sd2 into sd1 and returns sd1.
+<pre>
+ :<em class=typing>(define sd1 (make-sound-data 2 5))</em>
+ <em class=listener>#&lt;unspecified&gt;</em>
+ :<em class=typing>(do ((chn 0 (+ 1 chn))) ((= chn 2))
+ (do ((i 0 (+ 1 i))) ((= i 5))
+ (sound-data-set! sd1 chn i (+ i (* 5 chn)))))</em>
+ <em class=listener>#&lt;unspecified&gt;</em>
+ :<em class=typing>sd1</em>
+ <em class=listener>#&lt;sound-data[chans=2, length=5]:
+ (0.000 1.000 2.000 3.000 4.000)
+ (5.000 6.000 7.000 8.000 9.000)&gt;</em>
+ :<em class=typing>(sound-data-add! (sound-data-fill! (make-sound-data 2 5) .25) sd1)</em>
+ <em class=listener>#&lt;sound-data[chans=2, length=5]:
+ (0.250 1.250 2.250 3.250 4.250)
+ (5.250 6.250 7.250 8.250 9.250)&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-chans -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddatachans">sound-data-chans</a> (sd)</code>
+</td></tr><tr><td></td><td>
+sound-data-chans returns the number of channels in sd.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-copy -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounddatacopy">sound-data-copy</a> (sd)</code>
+</td></tr><tr><td></td><td>
+sound-data-copy returns a copy of the sound-data object sd.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-fill! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddatafill">sound-data-fill!</a> (sd value)</code>
+</td></tr><tr><td></td><td>
+sound-data-fill! sets each element of sound-data object sd to 'value'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-length -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddatalength">sound-data-length</a> (sd)</code>
+</td></tr><tr><td></td><td>
+sound-data-length returns the length (in samples) of each channel in the sound-data-object sd.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-maxamp -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddatamaxamp">sound-data-maxamp</a> (sd)</code>
+</td></tr><tr><td></td><td>
+sound-data-maxamp returns a list of maxamps (one for each channel) of the data in sd.
+<pre>
+ :<em class=typing>sd1</em>
+ <em class=listener>#&lt;sound-data[chans=2, length=5]:
+ (0.000 1.000 2.000 3.000 4.000)
+ (5.000 6.000 7.000 8.000 9.000)&gt;</em>
+ :<em class=typing>(sound-data-maxamp sd1)</em>
+ <em class=listener>(4.0 9.0)</em>
+ :<em class=typing>(sound-data-peak sd1)</em>
+ <em class=listener>9.0</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-multiply! -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounddatamultiply">sound-data-multiply!</a> (sd1 sd2)</code>
+</td></tr><tr><td></td><td>
+sound-data-multiply! multiplies each element of sd2 by the corresponding element of sd2 and returns sd1.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-offset! -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounddataoffset">sound-data-offset!</a> (sd off)</code>
+</td></tr><tr><td></td><td>
+sound-data-offset! adds the number 'off' to each element of sd and returns sd.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-peak -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounddatapeak">sound-data-peak</a> (sd)</code>
+</td></tr><tr><td></td><td>
+sound-data-peak returns the overall maximum element in sd.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-ref -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddataref">sound-data-ref</a> (sd chan frame)</code>
+</td></tr><tr><td></td><td>
+sound-data-ref returns (as a float) the sample in channel chan at location frame. In s7 you can omit the "sound-data-ref":
+<pre>
+ <em class=listener>&gt;</em><em class=typing>(let ((sd (make-sound-data 1 1))) (sd 0 0))</em>
+ <em class=listener>0.0</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-reverse! -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounddatareverse">sound-data-reverse!</a> (sd)</code>
+</td></tr><tr><td></td><td>
+sound-data-reverse! reverses the elements of each channel of sd and returns sd.
+<pre>
+ :<em class=typing>sd1</em>
+ <em class=listener>#&lt;sound-data[chans=2, length=5]:
+ (0.000 1.000 2.000 3.000 4.000)
+ (5.000 6.000 7.000 8.000 9.000)&gt;</em>
+ :<em class=typing>(sound-data-reverse! sd1)</em>
+ <em class=listener>#&lt;sound-data[chans=2, length=5]:
+ (4.000 3.000 2.000 1.000 0.000)
+ (9.000 8.000 7.000 6.000 5.000)&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-scale! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddatascale">sound-data-scale!</a> (sd scaler)</code>
+</td></tr><tr><td></td><td>
+sound-data-scale! multiplies each sample in sd by scaler.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data-set! -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddataset">sound-data-set!</a> (sd chan frame val)</code>
+</td></tr><tr><td></td><td>
+sound-data-set! sets sd's sample at 'frame' in channel 'chan' to val.
+In s7 you can use generalized set:
+<pre>
+ <em class=listener>&gt;</em><em class=typing>(let ((sd (make-sound-data 1 1))) (set! (sd 0 0) 1.0) (sd 0 0))</em>
+ <em class=listener>1.0</em>
+</pre>
+
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data+ -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounddata+">sound-data+</a> (val1 val2)</code>
+</td></tr><tr><td></td><td>
+sound-data+ adds val1 to val2 (either or both can be sound-data objects).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data* -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounddata*">sound-data*</a> (val1 val2)</code>
+</td></tr><tr><td></td><td>
+sound-data* multiplies val1 by val2 (either or both can be sound-data objects).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddata?">sound-data?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+sound-data? returns #t if obj is a sound-data object.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data->sound-data -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddatatosounddata">sound-data-&gt;sound-data</a> (sd-in sd-out beg dur cycle)</code>
+</td></tr><tr><td></td><td>
+sound-data-&gt;sound-data copies sound-data sd-in's
+data from 0 for dur frames into sound-data sd-out starting at beg, wrapping around if sd-out's end is reached.
+This is an experimental function currently used in the oscilloscope (oscope.scm).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-data->vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="sounddatatovct">sound-data-&gt;vct</a> (sd chan v)</code>
+</td></tr><tr><td></td><td>
+sound-data-&gt;vct copies sound-data sd's channel 'chan' data into vct v.
+<pre>
+ :<em class=typing>sd1</em>
+ <em class=listener>#&lt;sound-data[chans=2, length=5]:
+ (4.000 3.000 2.000 1.000 0.000)
+ (9.000 8.000 7.000 6.000 5.000)&gt;</em>
+ :<em class=typing>(sound-data-&gt;vct sd1 1)</em>
+ <em class=listener>#&lt;vct[len=5]: 9.000 8.000 7.000 6.000 5.000&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- vct->sound-data -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vcttosounddata">vct-&gt;sound-data</a> (v sd chan)</code>
+</td></tr><tr><td></td><td>
+vct-&gt;sound-data copies vct v's data into sound-data sd's channel chan.
+</td></tr>
+
+</table>
+
+<br>
+
+<table width="50%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h3><A NAME="extsndlib">Sndlib</a></h3></td></tr></table>
+
+<p>All of the underlying sound library (<a href="sndlib.html">Sndlib</a>)
+functions are available, as well as most of CLM (<a href="sndclm.html">sndclm.html</a>).
+For many eamples, see play.scm and rtio.scm. The most important Sndlib functions for Snd are:
+</p>
+
+<!-- -------------------------------- SNDLIB TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- mus-alsa-buffers -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musalsabuffers">mus-alsa-buffers</a> ()</code>
+</td></tr><tr><td width=30><br></td><td>
+mus-alsa-buffers is the number of buffers ("periods") used in ALSA; you can also use the environment variable MUS_ALSA_BUFFERS.
+The default setting is 3.
+These ALSA variables only matter if you built Snd with the configure switch --with-alsa.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-alsa-buffer-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musalsabuffersize">mus-alsa-buffer-size</a> ()</code>
+</td></tr><tr><td><br></td><td>
+mus-alsa-buffer-size is the buffer size used in ALSA. You can also use the environment variable MUS_ALSA_BUFFER_SIZE.
+The defaut setting is 1024.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-alsa-device -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musalsadevice">mus-alsa-device</a> ()</code>
+</td></tr><tr><td><br></td><td>
+This is the ALSA audio device; it defaults to "default".
+The matching environment variable is MUS_ALSA_DEVICE. If the ALSA "default" device can't be found, we also look
+for "plughw:0" and "hw:0". The "0" is apparently a card number or something. On my machine where the internal
+sound card is worse than useless, I have an EMI 2|6 connected to a USB port. Its ALSA name seems to be "hw:1"
+on a good day.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-alsa-capture-device -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musalsacapturedevice">mus-alsa-capture-device</a> ()</code>
+</td></tr><tr><td><br></td><td>
+This is the ALSA capture (audio recording) device. The matching environment variable is MUS_ALSA_CAPTURE_DEVICE.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-alsa-playback-device -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musalsaplaybackdevice">mus-alsa-playback-device</a> ()</code>
+</td></tr><tr><td><br></td><td>
+This is the ALSA audio playback device. The matching environment variable is MUS_ALSA_PLAYBACK_DEVICE.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-alsa-squelch-warning -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musalsasquelchwarning">mus-alsa-squelch-warning</a> ()</code>
+</td></tr><tr><td><br></td><td>
+Set mus-alsa-squelch-warning to #t to squelch warnings from ALSA about srate mismatches.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-close -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musaudioclose">mus-audio-close</a> (line)</code>
+</td></tr><tr><td><br></td><td>
+mus-audio-close closes the audio port 'line' ('line' comes from either <a href="#musaudioopeninput">mus-audio-open-input</a>
+or <a href="#musaudioopenoutput">mus-audio-open-output</a>).
+
+<table border=0 cellpadding=5 vspace=10><tr><td>
+<pre>
+(let* ((audio-fd (<a class=quiet href="#musaudioopenoutput" onmouseout="UnTip()" onmouseover="Tip(extsnd_musaudioopenoutput_tip)">mus-audio-open-output</a> mus-audio-default 22050 1 <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_muslshort_tip)">mus-lshort</a> 1024))
+ ;; open DAC at srate 22050, 1 channel, 1024 bytes per buffer
+ (osc (<a class=quiet href="sndclm.html#make-oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_oscil_tip)">make-oscil</a> 440.0)) ; make a sine wave at 440 Hz
+ (data (<a class=quiet href="#makesounddata" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesounddata_tip)">make-sound-data</a> 1 512))) ; output buffer (1 chan, 512 samples)
+ (do ((beg 0 (+ beg 512))) ; fill a buffer at a time
+ ((&gt; beg 22050)) ; stop playing after 1 second
+ (do ((i 0 (+ 1 i))) ; write each sample of the sinusoid
+ ((= i 512)) ; until this buffer is full
+ (<a class=quiet href="#sounddataset" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounddataset_tip)">sound-data-set!</a> data 0 i (* .1 (<a class=quiet href="sndclm.html#oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_oscil_tip)">oscil</a> osc)))) ; .1 amp
+ (<a class=quiet href="#musaudiowrite" onmouseout="UnTip()" onmouseover="Tip(extsnd_musaudiowrite_tip)">mus-audio-write</a> audio-fd data 512)) ; send a buffer to the DAC
+ (<em class=red>mus-audio-close</em> audio-fd)) ; close the DAC
+</pre>
+</td></tr></table></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-describe -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musaudiodescribe">mus-audio-describe</a> ()</code>
+</td></tr><tr><td></td><td>
+mus-audio-describe displays a string purporting to describe the audio hardware state. This function
+works best in OSS. If you're not getting any sound during playback, the first thing to do is to
+examine this function's output.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-mixer-read -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musaudiomixerread">mus-audio-mixer-read</a> (device field channel vals)</code>
+</td></tr><tr><td></td><td>
+mus-audio-mixer-read reads the current state of the field 'field' of audio device 'device'.
+'vals' should be a vct big enough to handle the returned data (32 is a good first guess).
+The 'channel' argument is often treated as the size of the vct 'vals'.
+Device names are listed below under <a href="#musaudioopeninput">mus-audio-open-input</a>.
+The fields are:
+</td></tr><tr><td></td><td>
+<pre>
+
+ mus-audio-amp mus-audio-srate mus-audio-channel mus-audio-format
+ mus-audio-imix mus-audio-igain mus-audio-reclev mus-audio-pcm
+ mus-audio-ogain mus-audio-line mus-audio-synth mus-audio-bass
+ mus-audio-direction mus-audio-port mus-audio-pcm2 mus-audio-treble
+ mus-audio-samples-per-channel
+</pre>
+These fields originally referred to OSS soundcard settings; many years have passed, and the whole notion is now
+obsolete, but if you think there's some easy way to reflect the same idea in modern hardware, check out ALSA or
+the new Mac audio system. I can't face this mess!
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-mixer-write -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musaudiomixerwrite">mus-audio-mixer-write</a> (device field channel vals)</code>
+</td></tr><tr><td></td><td>
+mus-audio-mixer-write sets the state of the field 'field' of audio device 'device'.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+;;; here we get the microphone volume, then set it to .5
+(define vals (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> 32))
+(<em class=red>mus-audio-mixer-read</em> mus-audio-microphone mus-audio-amp 0 vals)
+(<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> vals 0)
+(<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> vals 0 .5)
+(<em class=red>mus-audio-mixer-write</em> mus-audio-microphone mus-audio-amp 0 vals)
+;;; now set the 2 "igain" fields to 1
+(<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> vals 0 1.0)
+(<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> vals 1 1.0)
+(<em class=red>mus-audio-mixer-write</em> mus-audio-mixer mus-audio-igain 2 vals)
+</pre>
+</td></tr></table></td></tr>
+<tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-open-input -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musaudioopeninput">mus-audio-open-input</a> (device srate chans format bufsize)</code>
+</td></tr><tr><td></td><td>
+mus-audio-open-input opens the audio input (recording) port 'device'. It returns -1 if the open failed. 'device' is one of:
+</td></tr><tr><td></td><td>
+<pre>
+
+ mus-audio-default mus-audio-duplex-default mus-audio-line-out
+ mus-audio-microphone mus-audio-speakers mus-audio-dac-out
+ mus-audio-aes-in mus-audio-digital-in mus-audio-digital-out
+ mus-audio-aes-out mus-audio-dac-filter mus-audio-mixer
+ mus-audio-line2 mus-audio-line3 mus-audio-aux-input
+ mus-audio-line-in mus-audio-aux-output mus-audio-adat-in
+ mus-audio-adat-out mus-audio-line1 mus-audio-cd
+ mus-audio-spdif-in mus-audio-spdif-out
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-open-output -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musaudioopenoutput">mus-audio-open-output</a> (device srate chans format bufsize)</code>
+</td></tr><tr><td></td><td>
+mus-audio-open-output opens the audio output (playback) port 'device'. It returns -1 if the open failed.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-read -->
+<tr><td colspan=2 height=16><code><a class=def name="musaudioread">mus-audio-read</a> (line sd frames)</code>
+</td></tr><tr><td></td><td>
+mus-audio-read reads 'frames' frames of data into the sound-data object 'sd' from the audio input port 'line'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-report -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musaudioreport">mus-audio-report</a> ()</code>
+</td></tr><tr><td></td><td>
+mus-audio-report returns a string describing the current audio hardware state. <a href="#musaudiodescribe">mus-audio-describe</a>
+prints out the same string.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-audio-write -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musaudiowrite">mus-audio-write</a> (line sd frames)</code>
+</td></tr><tr><td></td><td>
+mus-audio-write writes 'frames' frames of data from the sound-data object 'sd' to the audio output port 'line'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-bytes-per-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musbytespersample">mus-bytes-per-sample</a> (data-format)</code>
+</td></tr><tr><td></td><td>
+mus-bytes-per-sample returns the number of bytes that 'data-format' uses to encode one sample of sound.
+<pre>
+ :<em class=typing>(mus-bytes-per-sample mus-bdouble)</em>
+ <em class=listener>8</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-clipping -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musclipping">mus-clipping</a> ()</code>
+</td></tr><tr><td></td><td>
+mus-clipping is the default low-level clipping choice while accessing sound data.
+Its default is #f which makes clipping very obvious (it will cause wrap-around).
+If you're using the standard Snd file accessors, you probably want to use <a href="#clipping">clipping</a>, not this function.
+This function refers to <a href="#mussoundopenoutput">mus-sound-open-output</a> and friends; the file-local version
+is <a href="#musfileclipping">mus-file-clipping</a> &mdash; surely we could make this more confusing!
+See also <a href="#cliphook">clip-hook</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-data-format-name -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musdataformatname">mus-data-format-name</a> (format)</code>
+</td></tr><tr><td></td><td>
+mus-data-format-name converts 'format' from an integer to an explanatory string, e.g. "16-bit big endian linear".
+The sndlib data formats are:</td></tr>
+<tr><td></td><td>
+<pre>
+ mus-bshort mus-lshort mus-mulaw mus-alaw mus-byte
+ mus-lfloat mus-bint mus-lint mus-b24int mus-l24int
+ mus-ubshort mus-ulshort mus-ubyte mus-bfloat mus-bdouble
+ mus-ldouble mus-unknown
+</pre>
+There are also "unscaled" versions of the floating point types, and "normalized" versions of the integers.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-data-format->string -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musdataformattostring">mus-data-format-&gt;string</a> (format)</code>
+</td></tr><tr><td></td><td>
+mus-data-format-&gt;string converts 'format' from an integer to a string, e.g. "mus-mulaw".
+<pre>
+ :<em class=typing>(mus-data-format-&gt;string mus-bdouble)</em>
+ <em class=listener>"mus-bdouble"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-error-type->string -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="muserrortypetostring">mus-error-type-&gt;string</a> (error)</code>
+</td></tr><tr><td></td><td>
+mus-error-type-&gt;string returns a brief string description of 'error'
+(a mus-error return type). This is only useful in <a href="#muserrorhook">mus-error-hook</a>, and it's not very useful even there.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-expand-filename -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musexpandfilename">mus-expand-filename</a> (name)</code>
+</td></tr><tr><td></td><td>
+mus-expand-filename fills out the filename 'name' to include its 'absolute' pathname;
+that is, it replaces '~' with the current home directory,
+and whatever else seems appropriate.
+<pre>
+ :<em class=typing>(mus-expand-filename "oboe.snd")</em>
+ <em class=listener>"/home/bil/cl/oboe.snd"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-file-clipping -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musfileclipping">mus-file-clipping</a> (fd)</code>
+</td></tr><tr><td></td><td>
+This is the clipping choice for the file referred to by 'fd'
+(a file identifier as returned by <a href="#mussoundopeninput">mus-sound-open-input</a>).
+The default is #f which makes clipping very obvious (it will cause wrap-around).
+See also <a href="#cliphook">clip-hook</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-file-prescaler -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musfileprescaler">mus-file-prescaler</a> (fd)</code>
+</td></tr><tr><td></td><td>
+This is the prescaling value for reading data from the sndlib file descriptor 'fd'.
+If you're reading float data that is extremely soft (i.e. peak amplitude
+below .001), the transfer to integer form in sndlib (if you're using integer internal sample format) can cause bits
+to be lost, resulting in hiss. In this case set the prescaler for
+the file to 1000.0 or so to get the data into a more normal
+range. Since mus-file-prescaler must be set after opening
+the sound file, but before trying to read any data, you need to use it in the context of <a href="#duringopenhook">during-open-hook</a>.
+The default prescaler value is <a href="#musprescaler">mus-prescaler</a>, normally 1.0.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-header-raw-defaults -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musheaderrawdefaults">mus-header-raw-defaults</a> ()</code>
+</td></tr><tr><td></td><td>
+mus-header-raw-defaults returns a list: '(srate chans data-format), the current raw header defaults. These can be
+set:
+<pre>
+ (set! (<em class=red>mus-header-raw-defaults</em>) (list 22050 4 mus-lint))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-header-type-name -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musheadertypename">mus-header-type-name</a> (type)</code>
+</td></tr><tr><td></td><td>
+mus-header-type-name converts 'type', an integer, to a string, e.g. "AIFF". Some of the sndlib header types are:
+</td></tr>
+<tr><td></td><td><pre>
+
+ mus-next mus-aifc mus-riff mus-rf64 mus-nist mus-raw mus-ircam mus-aiff mus-caff
+ mus-bicsf mus-soundfont mus-voc mus-svx mus-unsupported
+</pre>
+This function doesn't set the header choices for output of recording; it simply decodes a sndlib header type identifier.
+<pre>
+ :<em class=typing>(mus-header-type-name (mus-sound-header-type "oboe.snd"))</em>
+ <em class=listener>"Sun/Next"</em>
+</pre>
+The default sound output header choice is <a href="#defaultoutputheadertype">default-output-header-type</a>,
+a sound file's
+header type is <a href="#mussoundheadertype">mus-sound-header-type</a>, the CLM (<a href="sndscm.html#wsdoc">with-sound</a>) header default
+is *clm-header-type*, and an opened sound's header type is <a href="#headertype">header-type</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-header-type->string -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musheadertypetostring">mus-header-type-&gt;string</a> (type)</code>
+</td></tr><tr><td></td><td>
+mus-header-type-&gt;string converts 'type', an integer, to a string, e.g. "mus-aifc".
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-oss-set-buffers -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musosssetbuffers">mus-oss-set-buffers</a> (num size)</code>
+</td></tr><tr><td></td><td>
+In Linux (OSS), this sets the number and size of the OSS fragments.
+The default (as of 21-May-01) is to accept whatever OSS chooses: I believe this is normally
+equivalent to <code>(mus-oss-set-buffers 16 12)</code>. This default makes the control panel controls very sluggish.
+Snd used to call <code>(mus-oss-set-buffers 4 12)</code> as its default,
+but this seems to cause trouble for a variety of new sound cards.
+My initialization file includes <code>(mus-oss-set-buffers 2 12)</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-prescaler -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="musprescaler">mus-prescaler</a> ()</code>
+</td></tr><tr><td></td><td>
+mus-prescaler is the global default prescaling value for reading data from a file (see <a href="#musfileprescaler">mus-file-prescaler</a>).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-chans -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundchans">mus-sound-chans</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This is the number of channels in 'filename'. This value can be set (as can the others like it mentioned below);
+the assignment refers to the table of sound file data maintained by sndlib. The file itself is not touched, but any
+subsequent reference to it in Snd will assume the new value. In the mus-sound-chans case, say we have a sound file
+whose header claims it has 43 channels, but we know it only has 2:
+<pre>
+ (set! (<em class=red>mus-sound-chans</em> "43chans.snd") 2)
+</pre>
+tells Snd that it has 2 channels no matter what the header says.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-close-input -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundcloseinput">mus-sound-close-input</a> (fd)</code>
+</td></tr><tr><td></td><td>
+This closes the sound file referred to by 'fd'; 'fd' is an integer returned by <a href="#mussoundopeninput">mus-sound-open-input</a>.
+These mus-sound-* file functions refer to a direct path to read and write sound files. Any such operation is beneath the
+notice, so to speak, of Snd.
+This function reads the first 32 samples of a file, returning the 30th in channel 0:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define read-sample-30
+ (lambda (file)
+ (let* ((fd (<a class=quiet href="#mussoundopeninput" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundopeninput_tip)">>mus-sound-open-input</a> file))
+ (<a class=quiet href="#chans" onmouseout="UnTip()" onmouseover="Tip(extsnd_chans_tip)">channels</a> (channels file))
+ (data (<a class=quiet href="#makesounddata" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesounddata_tip)">make-sound-data</a> chans 32)))
+ (<a class=quiet href="#mussoundread" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundread_tip)">mus-sound-read</a> fd 0 31 chans data)
+ (let ((val (<a class=quiet href="#sounddataref" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounddataref_tip)">sound-data-ref</a> data 0 29)))
+ (<em class=red>mus-sound-close-input</em> fd)
+ val))))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-close-output -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundcloseoutput">mus-sound-close-output</a> (fd bytes)</code>
+</td></tr><tr><td></td><td>
+This function closes the sound file 'fd', and updates its length indication, if any to be 'bytes' bytes.
+If you didn't specify a data-format to <a href="#mussoundopenoutput">mus-sound-open-output</a>,
+it defaulted to <code>mus-out-format</code>.
+<code>mus-out-format</code> can
+currently be either ints, floats, or doubles, depending on how you've configured Snd, so it's safest
+to use <code>(<a href="#musbytespersample">mus-bytes-per-sample</a> mus-out-format)</code>
+for the number of bytes per sample.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-comment -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundcomment">mus-sound-comment</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-comment returns the comment in the header of the file 'filename'.
+<pre>
+ :<em class=typing>(with-sound (:comment "this is a comment") (fm-violin 0 1 440 .1))</em>
+ <em class=listener>"test.snd"</em>
+ :<em class=typing>(mus-sound-comment "test.snd")</em>
+ <em class=listener>"this is a comment"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-data-format -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussounddataformat">mus-sound-data-format</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-data-format returns the data format (e.g. <code>mus-bshort</code>) of the file 'filename'.
+<pre>
+ :<em class=typing>(mus-data-format-&gt;string (mus-sound-data-format "oboe.snd"))</em>
+ <em class=listener>"mus-bshort"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-data-location -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussounddatalocation">mus-sound-data-location</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This is the location in bytes of the first sample in the file 'filename'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-datum-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussounddatumsize">mus-sound-datum-size</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This returns the size in bytes of each sample in 'filename'.
+It is equivalent to <code>(mus-bytes-per-sample (mus-sound-data-format filename))</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-duration -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundduration">mus-sound-duration</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This returns the duration in seconds of the sound data in the file 'filename'.
+<pre>
+ :<em class=typing>(mus-sound-duration "oboe.snd")</em>
+ <em class=listener>2.30512475967407</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-forget -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundforget">mus-sound-forget</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-forget removes the file 'filename' from the sndlib sound cache.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-frames -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundframes">mus-sound-frames</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-frames returns the number of frames of sound data in the file 'filename' according to its header
+(this number is occasionally incorrect in mus-next headers).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-header-type -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundheadertype">mus-sound-header-type</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This returns the header type (e.g. <code>mus-aifc</code>) of the file 'filename'.
+<pre>
+ :<em class=typing>(mus-header-type-&gt;string (mus-sound-header-type "oboe.snd"))</em>
+ <em class=listener>"mus-next"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-length -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundlength">mus-sound-length</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-length returns the number of bytes of sound data in the file 'filename'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-loop-info -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundloopinfo">mus-sound-loop-info</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This function refers to the "loop" info that is sometimes found in some headers (aifc, wav etc).
+<a href="sndscm.html#markloops">mark-loops</a> in examp.scm uses mus-sound-loop-info to place a mark at each loop point.
+<pre>
+ :<em class=typing>(mus-sound-loop-info "~/sf1/forest.aiff")</em>
+ <em class=listener>(24981 144332 0 0 60 0 1 0)</em>
+</pre>
+The loop info is a list of
+up to 4 points, the first two (start, end = 24981 144332 above) refer to the sustain loop,
+and the second two (0 0 above) refer to the release.
+The 5th and 6th list entries are the base note and detune values (60 0 above).
+For historical reasons, the 7th and 8th entries are the sustain and release modes (1 0 above).
+The <a href="sndclm.html#table-lookup">looper</a> instrument uses this function to implement a sort of "freeze" function.
+See also <a href="#soundloopinfo">sound-loop-info</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-mark-info -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundmarkinfo">mus-sound-mark-info</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This function refers to the "mark" info that is sometimes found in aifc and aiff headers.
+It returns a list of lists (or an empty list if there are no marks),
+each inner list being (mark-id mark-position). The mark-id is a number that identifies it for
+use with mus-sound-loop-info, and the mark-position is its sample number in the file.
+Normally, this information is already included in the mus-sound-loop-info list:
+<pre>
+ :<em class=typing>(mus-sound-mark-info "/home/bil/sf1/forest.aiff")</em>
+ <em class=listener>((4 1) (3 0) (2 144332) (1 24981))</em>
+ :<em class=typing>(mus-sound-loop-info "/home/bil/sf1/forest.aiff")</em>
+ <em class=listener>(24981 144332 0 0 60 0 1 0)</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-maxamp -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundmaxamp">mus-sound-maxamp</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-maxamp returns a list of max amps and locations thereof. The corresponding set!
+affects only the sndlib table of sound file info, not the sound file itself, as in all such cases.
+<pre>
+ :<em class=typing>(mus-sound-maxamp "oboe.snd")</em>
+ <em class=listener>(24971 0.147247314453125)</em>
+ ;; oboe's maxamp is .147 first encountered at sample 24971
+ :<em class=typing>(mus-sound-maxamp "2a.snd")</em>
+ <em class=listener>(933 0.0999755859375 2827 0.0999755859375)</em>
+ ;; 2a's maxamps are 0.1 in each channel at sample 933 in chan 0, 2827 in chan 1
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-maxamp-exists? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundmaxampexists">mus-sound-maxamp-exists?</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This function returns #t if the sound's maxamp data is available
+in the sound cache; if it isn't, a call on mus-sound-maxamp has to open and read the data to get the maxamp.
+<pre>
+ :<em class=typing>(mus-sound-maxamp-exists? "/home/bil/test/sound/away.snd")</em>
+ <em class=listener>#f</em>
+ :<em class=typing>(mus-sound-maxamp "/home/bil/test/sound/away.snd")</em>
+ <em class=listener>(14562264 0.463623046875 14557044 0.404571533203125)</em>
+ :<em class=typing>(mus-sound-maxamp-exists? "/home/bil/test/sound/away.snd")</em>
+ <em class=listener>#t</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-open-input -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundopeninput">mus-sound-open-input</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-open-input opens the sound file 'filename' and returns an integer for use with
+<a href="#mussoundread">mus-sound-read</a> and <a href="#mussoundcloseinput">mus-sound-close-input</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-open-output -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundopenoutput">mus-sound-open-output</a> (filename :optional (srate 44100) (chans 1) data-format header-type comment)</code>
+</td></tr><tr><td></td><td>
+mus-sound-open-output creates a new sound file with the indicated attributes, and returns an integer
+for use with <a href="#mussoundwrite">mus-sound-write</a> and <a href="#mussoundcloseoutput">mus-sound-close-output</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-prune -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundprune">mus-sound-prune</a> ()</code>
+</td></tr><tr><td></td><td>
+mus-sound-prune removes all defunct (non-existent) files from the sound cache. This is primarily intended for internal testing (snd-test.scm).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-read -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundread">mus-sound-read</a> (fd beg end chans sd)</code>
+</td></tr><tr><td></td><td>
+mus-sound-read reads data from the sound file 'fd', loading the sound-data object 'sd' from 'beg'
+to 'end'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-reopen-output -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundreopenoutput">mus-sound-reopen-output</a> (filename :optional (chans 1) data-format header-type data-location)</code>
+</td></tr><tr><td></td><td>
+mus-sound-reopen-output reopens the sound file 'filename', ready to continue writing output.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-report-cache -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundreportcache">mus-sound-report-cache</a> (file)</code>
+</td></tr><tr><td></td><td>
+This function prints the current sound header data table to the file given or stdout if none is specified.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-samples -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundsamples">mus-sound-samples</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-samples returns the number of samples in the sound file 'filename' according to its header.
+<pre>
+ :<em class=typing>(mus-sound-samples "oboe.snd")</em>
+ <em class=listener>50828</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-seek-frame -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundseekframe">mus-sound-seek-frame</a> (fd frame)</code>
+</td></tr><tr><td></td><td>
+mus-sound-seek-frame moves the input or output reading point to 'frame' in the sound file 'fd'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-srate -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundsrate">mus-sound-srate</a> (filename)</code>
+</td></tr><tr><td></td><td>
+mus-sound-srate returns the sampling rate of 'filename'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-type-specifier -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundtypespecifier">mus-sound-type-specifier</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This is the original type indication of 'filename'. This is only useful in internal testing.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-write -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundwrite">mus-sound-write</a> (fd beg end chans sd)</code>
+</td></tr><tr><td></td><td>
+mus-sound-write writes data from the sound-data object 'sd' to the sound file 'fd'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sound-write-date -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussoundwritedate">mus-sound-write-date</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This returns the sound's write date:
+</td></tr><tr><td></td><td>
+<pre>
+ :<em class=typing>(strftime "%d-%b %H:%M %Z" (localtime (mus-sound-write-date "oboe.snd")))</em>
+ <em class=listener>"18-Oct 06:56 PDT"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mus-sun-set-outputs -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mussunsetoutputs">mus-sun-set-outputs</a> (speakers headphones line-out)</code>
+</td></tr><tr><td></td><td>
+This sets the current Sun audio outputs.
+Each entry should be either 0 (turn off the device) or 1 (turn it on).
+On NetBSD, use <a class=def name="musnetbsdsetoutputs">mus-netbsd-set-outputs</a>.
+</td></tr>
+
+</table>
+
+<p>See <a href="sndlib.html">Sndlib</a> for more information on these functions. When called from Snd, these
+throw 'mus-error upon encountering an error, rather than returning -1 like the underlying sndlib functions.
+</p>
+<p>The following function uses the sndlib functions to mimic the 'info' popup menu option (see <a href="sndscm.html#exampdoc">examp.scm</a> for a version that uses format):</p>
+
+<table border=0 cellpadding=5 hspace=20><tr><td><pre>
+<A NAME="sndinfo"></a>(define info
+ (lambda (file)
+ (string-append
+ file
+ ": chans: " (number-&gt;string (channels file))
+ ", srate: " (number-&gt;string (srate file))
+ ", " (<a class=quiet href="#musheadertypename" onmouseout="UnTip()" onmouseover="Tip(extsnd_musheadertypename_tip)">mus-header-type-name</a> (<a class=quiet href="#mussoundheadertype" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundheadertype_tip)">mus-sound-header-type</a> file))
+ ", " (<a class=quiet href="#musdataformatname" onmouseout="UnTip()" onmouseover="Tip(extsnd_musdataformatname_tip)">mus-data-format-name</a> (<a class=quiet href="#mussounddataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussounddataformat_tip)">mus-sound-data-format</a> file))
+ ", len: " (number-&gt;string
+ (/ (<a class=quiet href="#mussoundsamples" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundsamples_tip)">mus-sound-samples</a> file)
+ (* (channels file) (srate file)))))))
+</pre></td></tr></table>
+<br>
+<br>
+<br>
+<table width="50%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h3><A NAME="sndmarks">Marks</a></h3></td></tr></table>
+
+<A NAME="markstuff"></a>
+
+<p>A mark is an object that refers to a particular sample.
+Each mark has an associated sample number (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a>),
+name (<a class=quiet href="#markname" onmouseout="UnTip()" onmouseover="Tip(extsnd_markname_tip)">mark-name</a>), and sync value (<a class=quiet href="#marksync" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksync_tip)">mark-sync</a>).
+See <a href="snd.html#marks">Marks</a> in snd.html
+for an overview and key bindings associated with marks.
+See also the <a href="#sndhooks">hooks</a> section above for various mark-related hooks.
+</p>
+
+<!-- -------------------------------- MARKS TABLE -------------------------------- -->
+
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- add-mark -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="addmark">add-mark</a> (sample :optional snd chn name sync)</code>
+</td></tr><tr><td width=30><br></td><td>
+add-mark adds a mark at the position 'sample', returning the new mark.
+<pre>
+ :<em class=typing>(define m1 (add-mark 1234))</em>
+ <em class=listener>m1</em>
+ :<em class=typing>m1</em>
+ <em class=listener>#&lt;mark 0&gt;</em>
+ :<em class=typing>(mark-sample m1)</em>
+ <em class=listener>1234</em>
+</pre>
+The mark-name can be set via 'name', and the mark-sync field via 'sync'.
+If 'sample' is beyond the end of the data, add-mark throws 'no-such-sample.
+There is also the form add-mark! which returns #f if the sample number is beyond the current last sample,
+rather than throwing the 'no-such-sample error.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- delete-mark -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="deletemark">delete-mark</a> (mark)</code>
+</td></tr><tr><td></td><td>
+delete-mark deletes the mark. Mark additions and deletions follow the
+edit list, so if the deleted mark was present in an earlier edit, and you undo to that point,
+the mark comes back to life.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- delete-marks -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="deletemarks">delete-marks</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This function deletes all marks in the given channel. It could be defined in Scheme as:
+<pre>
+ (for-each
+ (lambda (m)
+ (delete-mark m))
+ (<a class=quiet href="#emarks" onmouseout="UnTip()" onmouseover="Tip(extsnd_emarks_tip)">marks</a> (or snd (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>)) (or chn (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>))))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- find-mark -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="findmark">find-mark</a> (samp :optional snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+find-mark returns the mark at sample 'samp' or #f if none is found.
+If 'samp' is a string, rather than an integer, find-mark
+looks for a mark of that name. <a href="sndscm.html#marknametoid">mark-name-&gt;id</a>
+in marks.scm finds a named mark in any channel (a global version of find-mark).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- integer->mark -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="integertomark">integer-&gt;mark</a> (i)</code>
+</td></tr><tr><td></td><td>
+In olden times, a mark was handled in Snd code as an integer; nowadays, it's an object.
+This function, and its companion <a href="#marktointeger">mark-&gt;integer</a>, exist mainly to convert
+old code to the current style.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark->integer -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="marktointeger">mark->integer</a> (mark)</code>
+</td></tr><tr><td></td><td>
+This is the counterpart to <a href="#integertomark">integer-&gt;mark</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><em class=emdef><a href="#markcolor">mark-color</a></em></code>
+</td></tr><tr><td></td><td>
+This sets the color of mark indicator; the default is red.
+<a href="sndscm.html#marksynccolor">mark-sync-color</a> uses mark-color to
+display all sync'd marks with some distinctive color.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><em class=emdef><a href="#markcontext">mark-context</a></em></code>
+</td></tr><tr><td></td><td>
+This is the graphics context to use to draw a mark (XOR mode).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-home -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="markhome">mark-home</a> (mark)</code>
+</td></tr><tr><td></td><td>
+mark-home is a list with the sound and channel that hold the mark.
+<pre>
+ :<em class=typing>(marks 0 0)</em> ; what marks are in snd 0, chn 0?
+ <em class=listener>(#&lt;mark 0&gt;)</em> ; just one
+ :<em class=typing>(mark-home (car (marks 0 0)))</em> ; what is that mark's snd/chn?
+ <em class=listener>(#&lt;sound 0&gt; 0)</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-name -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="markname">mark-name</a> (mark)</code>
+</td></tr><tr><td></td><td>
+This is the name of the mark.
+<pre>
+ :<em class=typing>(define m1 (add-mark 1234 0 0 "a name"))</em>
+ <em class=listener>m1</em>
+ :<em class=typing>(mark-name m1)</em>
+ <em class=listener>"a name"</em>
+ :<em class=typing>(set! (mark-name m1) "a new name")</em>
+ <em class=listener>"a new name"</em>
+ :<em class=typing>(mark-name m1)</em>
+ <em class=listener>"a new name"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-properties -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="markproperties">mark-properties</a> (mark)</code>
+</td></tr><tr><td></td><td>
+mark-properties is a property list associated with a mark.
+<a href="sndscm.html#markproperty">mark-property</a> (in marks.scm) reads and writes this list.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="marksample">mark-sample</a> (mark :optional edpos)</code>
+</td></tr><tr><td></td><td>
+mark-sample is the sample number (a location) marked by the mark at edit history position 'edpos'.
+<pre>
+ :<em class=typing>(mark-sample m1)</em>
+ <em class=listener>1234</em>
+ :<em class=typing>(set! (mark-sample m1) 4321)</em>
+ <em class=listener>4321</em>
+ :<em class=typing>(mark-sample m1)</em>
+ <em class=listener>4321</em>
+</pre>
+It might be more consistent with other Snd names to call this mark-position, but I wanted to emphasize
+that a mark follows its sample around as a sound is edited; that is, it marks a sample, not a position in the sound.
+Say we have three named marks in a speech excerpt (see below), then delete the initial spoken word ("now");
+each mark backs up with the deletion so that it
+continues to point to its original sample:
+<br>
+
+<img src="pix/mark1.png" align=left vspace=20 hspace=20 alt="marks" onmouseout="UnTip()" onmouseover="Tip('This is a recording of a man saying &quot;now the same piece is played&quot;.<br>The three marks are set at the start of three of the words.<br>To play from a mark, click the red triangle at the bottom.<br>To reposition a mark, drag the upper rectangle.')">
+
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-sync -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="marksync">mark-sync</a> (mark)</code>
+</td></tr><tr><td></td><td>
+This is the
+mark's sync field (the default is 0).
+The sync value
+provides a way to group marks for simultaneous
+changes. Marks that share the same sync value (if not 0), move together when any one of them is
+dragged, play together if clicked, etc. To find which marks share a given
+sync value, use <a href="#syncdmarks">syncd-marks</a>; to find an unused sync value use <a href="#marksyncmax">mark-sync-max</a>.
+<br><br>
+Marks that are syncd together can be used for insertions, and deletions, and can
+set arbitrary groups of play points. But it's a bit tedious to type <code>(set! (mark-sync ...)...)</code>
+for each of the marks you want in the group. The following code example uses the <a href="#markclickhook">mark-click-hook</a>
+instead; you type <code>(start-sync)</code>, then click each of the marks that you want grouped together, then <code>(stop-sync)</code>.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define mark-sync-number 0)
+(define (start-sync) (set! mark-sync-number (+ (<a class=quiet href="#marksyncmax" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksyncmax_tip)">mark-sync-max</a>) 1)))
+(define (stop-sync) (set! mark-sync-number 0))
+(define (click-to-sync id) (set! (<em class=red>mark-sync</em> id) mark-sync-number) #f)
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#markclickhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_markclickhook_tip)">mark-click-hook</a> click-to-sync)
+</pre></td></tr></table>
+
+Now control-click and drag one of them, and all of them move together deleting data, or
+inserting zeros; or click the "play" triangle, and all of them play together starting from
+their respective samples.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-sync-max -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="marksyncmax">mark-sync-max</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the maximum mark sync value seen so far.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-tag-height -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="marktagheight">mark-tag-height</a> ()</code>
+</td></tr><tr><td></td><td>
+When a mark is drawn, it has a horizontal rectangle at the top, then a vertical line, then a triangle.
+The line marks the marked sample, the triangle can be clicked to play from the mark, and the
+rectangle can be clicked or dragged. The mark-tag-height refers to the vertical thickness of that tag
+in pixels; its default is 4.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-tag-width -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="marktagwidth">mark-tag-width</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the
+mark tag width in pixels; it defaults to 10.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- marks -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="emarks">marks</a> (:optional snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+This function returns a list of mark ids in the given channel at the edit history position 'edpos'.
+If 'chn' and 'edpos' are omitted, a list of lists is returned,
+each inner list representing a channel of 'snd'. If 'snd' is
+also omitted, a list of lists of lists is returned, representing
+each sound and its channels.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (how-many-marks-in-channel snd chn)
+ (length (<em class=red>marks</em> snd chn)))
+
+(define (how-many-marks-in-sound snd)
+ (apply + (map length (<em class=red>marks</em> snd))))
+
+(define (how-many-marks)
+ (apply + (map how-many-marks-in-sound (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+</pre></td></tr></table>
+
+If the marks function is called
+without any argument, or with just a sound, it returns a list of lists; each inner list is the list
+of current marks active in that channel, ordered by sample number. If the channel argument is
+specified, marks returns just the list of marks. If the edit history position is given,
+the list of marks reflects the marks active at that point in the edit history. See <a href="sndscm.html#describemark">describe-mark</a> in marks.scm.
+<br><br>
+Say we have two sounds open, 2 marks in the first (a mono sound), and one
+in the 2nd channel of the 2nd (a stereo sound):
+<pre>
+ :<em class=typing>(marks 0 0)</em>
+ <em class=listener>(#&lt;mark 1&gt; #&lt;mark 0&gt;)</em> ; these are mark id's, as returned by the add-mark function for example
+ :<em class=typing>(marks 1)</em>
+ <em class=listener>(() (#&lt;mark 2&gt;))</em> ; no mark in channel 0, one in channel 1
+ :<em class=typing>(marks)</em>
+ <em class=listener>(((#&lt;mark 1&gt; #&lt;mark 0&gt;)) (() (#&lt;mark 2&gt;)))</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="markp">mark?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+mark? returns #t if 'obj' is a mark and is active (that is, if it is present in a currently open channel).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-marks -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="savemarks">save-marks</a> (:optional snd filename)</code>
+</td></tr><tr><td></td><td>
+save-marks saves the given sound's marks, writing a Scheme, Ruby, or Forth source file named either 'filename' or
+&lt;sound's file-name&gt;.marks. It returns the file name or #f if there are no marks to save.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><em class=emdef><a href="#showmarks">show-marks</a></em></code>
+</td></tr><tr><td></td><td>
+show-marks is #t if marks are being displayed.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- syncd-marks -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="syncdmarks">syncd-marks</a> (sync)</code>
+</td></tr><tr><td></td><td>
+syncd-marks returns a list of marks that share the mark-sync value 'sync'.
+
+<table border=0 cellpadding=5><tr><td><pre>
+(define (move-syncd-marks sync diff)
+ (for-each
+ (lambda (m)
+ (set! (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> m) (+ (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> m) diff)))
+ (<em class=red>syncd-marks</em> sync)))
+</pre></td></tr></table>
+</td></tr>
+
+</table>
+
+<!-- INDEX markstuff:Marking -->
+<p>
+See <a href="sndscm.html#marksdoc">marks.scm</a> for
+more examples including:
+</p>
+
+<TABLE border=3 bordercolor="tan" hspace=20><tr><td width=500>
+<blockquote><small>
+<br>
+global find-mark: <a href="sndscm.html#marknametoid">mark-name-&gt;id</a><br>
+mark history: <a href="sndscm.html#describemark">describe-mark</a><br>
+synchronize marks by inserting silences: <a href="sndscm.html#syncup">syncup</a><br>
+squeeze selection between marks: <a href="sndscm.html#fitselectionbetweenmarks">fit-selection-between-marks</a><br>
+insert silence before marks: <a href="sndscm.html#padmarks">pad-marks</a><br>
+move syncd marks: <a href="sndscm.html#movesyncdmarks">move-syncd-marks</a><br>
+play starting from syncd marks: <a href="sndscm.html#playsyncdmarks">play-syncd-marks</a><br>
+evaluate function between marks: <a href="sndscm.html#evalbetweenmarks">eval-between-marks</a><br>
+place marks at selection start and end: <a href="sndscm.html#snapmarks">snap-marks</a><br>
+define selection via marks: <a href="sndscm.html#defineselectionviamarks">define-selection-via-marks</a><br>
+force dragged mark to land on a beat: <a href="sndscm.html#snapmarktobeat">snap-mark-to-beat</a><br>
+loop continuously between the two specified marks: <a href="sndscm.html#loopbetweenmarks">loop-between-marks</a><br>
+split sound into separate files based on mark placement: <a href="sndscm.html#markexplode">mark-explode</a><br>
+mark property lists: <a href="sndscm.html#markproperty">mark-property</a><br>
+save mark properties in saved state file: <a href="sndscm.html#savemarkproperties">save-mark-properties</a><br>
+show mark properties upon click: <a href="sndscm.html#markclickinfo">mark-click-info</a><br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+
+<p>Other examples can be found in Dave Phillips' marks-menu.scm, snd-motif.scm (add-mark-pane),
+edit-menu.scm (trim from mark, etc), examp.scm (move window to correspond to mark, looping).
+</p>
+<br>
+<br>
+<table width="50%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h3><A NAME="sndmixes">Mixes</a></h3></td></tr></table>
+
+<p>Mixing operations have a lot of extra support built into Snd. In nearly every mixing function, you
+can request a "mix tag" (or set that request globally via <a href="#withmixtags">with-mix-tags</a>).
+If the mix operation is tagged, you can then operate on that data through a number of functions,
+the Mix Dialog, various hooks, and various mouse-related actions.
+</p>
+
+
+<table width="35%" border=0><tr><td bgcolor="#EEFDEE" valign="middle"><h4>Mixes</h4></td></tr></table>
+
+<p>A mix is an object that represents a channel (one channel in and one channel out) of a sound mix.
+Various mixing functions create these objects (mix-vct for example). In the old days, mixes were identified
+by integers, so for conversion you can use mix-&gt;integer and integer-&gt;mix.
+Say we have a mix object stored in the variable "id":
+</p>
+<pre>
+ &gt;<em class=listener>(set! (mix-amp id) .5)</em>
+ <em class=typing>.5</em>
+</pre>
+<p>This sets the mix's amplitude scaler to .5.
+</p>
+
+
+<!-- -------------------------------- MIX FUNCTION TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- integer->mix -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="integertomix">integer-&gt;mix</a> (i)</code>
+</td></tr><tr><td></td><td>
+In olden times, a mix was handled in Snd code as an integer; nowadays, it's an object.
+This function, and its companion <a href="#mixtointeger">mix-&gt;integer</a>, exist mainly to convert
+old code to the current style.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix->integer -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixtointeger">mix->integer</a> (mix)</code>
+</td></tr><tr><td></td><td>
+This is the counterpart to <a href="#integertomix">integer-&gt;mix</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mix">mix</a> (file :optional samp in-chan snd chn with-mix-tags auto-delete)</code>
+</td></tr><tr><td width=30></td><td>
+<p>mix is one of the basic mixing functions.
+It mixes the 'in-chan' channel of the file 'file' into the given channel
+starting at 'samp' in the output channel, and returns a list with the mix.
+If 'in-chan' is #t, all input channels are mixed into successive output channels, and
+mix returns a list of the mixes.
+</p>
+<p>If 'with-mix-tags' is #f (the default is #t), the data is simply
+mixed without creating any mix objects.
+</p>
+
+<pre>
+ (mix "test.snd") ; add channel 0 of test.snd to the current sound at sample 0
+ (mix "test.snd" 0 #t) ; same but add all channels of test.snd into successive output channels
+ (mix "test.snd" 0 1) ; add channel 1 of test.snd to channel 0 of the current sound
+ (mix "test.snd" 0 0 #f 1) ; add channel 0 of test.snd to channel 1 of the current sound
+ (mix "test.snd" 0 3 #f 1 #f) ; add channel 3 of test.snd to channel 1 of the current sound, without a mix tag
+</pre>
+
+<p>
+The input file ('file') is not deleted by Snd unless 'auto-delete' is #t (or 1 or 3).
+auto-delete can be a boolean (#f = don't delete), or and integer: 0=don't delete, 1=delete, 3=delete but keep track of multichannel inputs.
+</p>
+<p>In the next example, we mix in two sounds:
+</p>
+
+<img src="pix/mix1.png" alt="mixes" vspace=10 onmouseout="UnTip()" onmouseover="Tip('the mix tag is the red rectangle at the left end of the mix waveform.<br>The number under it is that mix\'s id.')">
+<br>
+Now we can drag either of the red tags to move the mixed sounds, call up the View:Mixes dialog to edit them,
+or use the functions in this section. For example, we'll set the amplitude of the first and the position of
+the second:
+<br>
+<img src="pix/mix2.png" alt="mixes" vspace=10>
+<br>
+We can use <a href="sndscm.html#dlocsigdoc">dlocsig</a> in conjunction with mix to move the mixed-in sound:
+
+<table border=0 cellpadding=5 vspace=20><tr><td><pre>
+(if (not (provided? 'snd-dlocsig.scm)) (load-from-path "dlocsig.scm"))
+(if (not (provided? 'snd-ws.scm)) (load-from-path "ws.scm"))
+
+(define (<a name="mixmovesound">mix-move-sound</a> start-time file path)
+ "mix file at start-time in the currently selected sound following the given dlocsig path"
+ (let* ((duration (<a class=quiet href="#mussoundduration" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundduration_tip)">mus-sound-duration</a> file))
+ (rd (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> 0 file))
+ (start (<a class=quiet href="sndclm.html#secondstosamples" onmouseout="UnTip()" onmouseover="Tip(sndclm_secondstosamples_tip)">seconds-&gt;samples</a> start-time))
+ (tmp-sound (<a class=quiet href="sndscm.html#sound-let" onmouseout="UnTip()" onmouseover="Tip(sndscm_sound_let_tip)">with-temp-sound</a> (:channels (<a class=quiet href="#channels" onmouseout="UnTip()" onmouseover="Tip(extsnd_channels_tip)">channels</a>) :srate (srate file))
+
+ ;; We use with-temp-sound here rather than sound-let because mix normally expects its input file to
+ ;; be around until it decides it doesn't need it anymore, but sound-let deletes all its temp files.
+ ;; We use with-temp-sound rather than with-sound because the latter would want to open the output
+ ;; file in Snd; this could be turned off by including the :to-snd #f argument.
+
+ (let* ((vals (<em class=red>make-dlocsig</em> :start-time 0
+ :duration duration
+ :path path))
+ (dloc (car vals))
+ (beg (cadr vals))
+ (end (caddr vals)))
+ (run
+ (lambda ()
+ (do ((i beg (+ 1 i)))
+ ((= i end))
+ (<em class=red>dlocsig</em> dloc i (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> rd)))))))))
+
+ ;; now tmp-sound is the name of a temp sound file that moves 'file' in a spiral
+
+ (<em class=red>mix</em> tmp-sound start #t #f #f (<a class=quiet href="#withmixtags" onmouseout="UnTip()" onmouseover="Tip(extsnd_withmixtags_tip)">with-mix-tags</a>) #t)))
+
+;;; (mix-move-sound 0 "oboe.snd" (make-spiral-path :turns 3))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2></td></tr>
+
+
+<!-- mixes -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixes">mixes</a> (:optional snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+mixes returns a list of the mix objects associated with the given channel at the edit history position 'edpos'.
+If the channel argument is omitted, you get a list of lists, each inner list referring to a single channel of that sound.
+If the sound is also omitted, you get a list of lists of lists, the outer list referring to each sound, each
+inner list to that sound's channels. Say we have two sounds open, 2 mixes in the first (a mono sound), and 1 mix
+in the 2nd channel of the 2nd (a stereo sound):
+<pre>
+ :<em class=typing>(mixes 0 0)</em>
+ <em class=listener>(#&lt;mix 0&gt; #&lt;mix 2&gt;)</em> ; these are mix objects, as returned by the mix function for example
+ :<em class=typing>(mixes 1)</em>
+ <em class=listener>(() (#&lt;mix 1&gt;))</em> ; no mix in channel 0, one in channel 1
+ :<em class=typing>(mixes)</em>
+ <em class=listener>(((#&lt;mix 0&gt; #&lt;mix 2&gt;)) (() (#&lt;mix 1&gt;)))</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-amp -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixamp">mix-amp</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-amp is the amplitude scaler applied to the mix. To make mix mx half as loud:
+<pre>
+ (set! (mix-amp mx) .5)
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-amp-env -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixampenv">mix-amp-env</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-amp-env is the
+amplitude envelope applied to the mix (a list of breakpoints).
+To reset this to its default (null) state, use #f.
+<pre>
+ (set! (mix-amp-env mx) '(0 0 1 1))
+</pre>
+sets mix mx's envelope to a ramp.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-color -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixcolor">mix-color</a> (:optional mix)</code>
+</td></tr><tr><td></td><td>
+This is the color of mix waveforms; it defaults to dark-gray.
+If you
+want to set just a particular mix's color, pass the mix object
+as the 'mix' argument: <code>(set! (mix-color) red)</code> sets all mix waveforms to
+red; but <code>(set! (mix-color mx) red)</code> sets only mix mx's waveform to red.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-length -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixlength">mix-length</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-length returns the mix's length in samples.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-home-->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixhome">mix-home</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-home returns a list containing the mix's output sound and channel number, and the input original filename (if any), and input channel.
+<pre>
+ :<em class=typing>(define mx (mix "pistol.snd" 1000))</em>
+ <em class=listener>#&lt;mix 0&gt;</em>
+ :<em class=typing>(mix-home mx)</em>
+ <em class=listener>(#&lt;sound 0&gt; 0 "/home/bil/cl/pistol.snd" 0)</em>
+ ;; (list output-sound-index output-channel input-filename input-channel)
+ :<em class=typing>(set! mx (mix-vct (make-vct 100 .1) 2000))</em>
+ <em class=listener>#&lt;mix 1&gt;</em>
+ :<em class=typing>(mix-home mx)</em>
+ <em class=listener>(#&lt;sound 0&gt; 0 #f 0)</em>
+ ;; #f: no input file
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-name -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixname">mix-name</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-name is the mix's name, if any. The mix name is displayed near the mix tag.
+See also <a href="sndscm.html#mixnametoid">mix-name-&gt;id</a>.
+Here's an example that uses the mix name and the tag location (mix-tag-y) to provide some pitch
+feedback:
+
+<table border=0 cellpadding=5 vspace=5><tr><td><pre>
+(if (not (provided? 'snd-v.scm)) (load-from-path "v.scm"))
+(if (not (provided? 'snd-ws.scm)) (load-from-path "ws.scm"))
+
+(define (frequency-&gt;tag-y freq lo octs) ; tag height dependent on freq
+ (inexact-&gt;exact (round (* 100 (- 1.0 (/ (log (/ freq lo)) (* (log 2.0) octs)))))))
+
+(let ((violin-sync 1)
+ (violin-color (<a class=quiet href="#makecolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_makecolor_tip)">make-color</a> 0 0 1)) ; blue
+ (cello-sync 2)
+ (cello-color (<a class=quiet href="#makecolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_makecolor_tip)">make-color</a> 0 1 0)) ; green
+ (index (<a class=quiet href="#newsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_newsound_tip)">new-sound</a> "test.snd" :channels 1 :size (* 44100 22))))
+
+ (define (violin beg dur freq amp)
+ (let ((id (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> (<a class=quiet href="sndscm.html#withtempsound" onmouseout="UnTip()" onmouseover="Tip(sndscm_withtempsound_tip)">with-temp-sound</a> () ; write instrument output to temp sound
+ (<a class=quiet href="sndscm.html#fmviolin" onmouseout="UnTip()" onmouseover="Tip(sndscm_fmviolin_tip)">fm-violin</a> 0 dur (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">-&gt;frequency</a> freq #t) amp)) ; our favorite FM instrument
+ (<a class=quiet href="sndscm.html#tosample" onmouseout="UnTip()" onmouseover="Tip(sndscm_tosample_tip)">-&gt;sample</a> beg) 0 index 0 ; mix start, file in-chan, sound, channel
+ #t #t))) ; mix with tag and auto-delete
+ (if (symbol? freq)
+ (set! (<em class=red>mix-name</em> id) (symbol-&gt;string freq)))
+ (set! (<a class=quiet href="#mixsync" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixsync_tip)">mix-sync</a> id) violin-sync)
+ (set! (<a class=quiet href="#mixcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixcolor_tip)">mix-color</a> id) violin-color)
+ (set! (<a class=quiet href="#mixtagy" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixtagy_tip)">mix-tag-y</a> id) (frequency-&gt;tag-y (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">-&gt;frequency</a> freq #t) (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">-&gt;frequency</a> 'c2) 3))))
+
+ (define (cello beg dur freq amp)
+ (let ((id (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> (<a class=quiet href="sndscm.html#withtempsound" onmouseout="UnTip()" onmouseover="Tip(sndscm_withtempsound_tip)">with-temp-sound</a> ()
+ (<a class=quiet href="sndscm.html#fmviolin" onmouseout="UnTip()" onmouseover="Tip(sndscm_fmviolin_tip)">fm-violin</a> 0 dur (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">-&gt;frequency</a> freq #t) amp :fm-index 1.5))
+ (<a class=quiet href="sndscm.html#tosample" onmouseout="UnTip()" onmouseover="Tip(sndscm_tosample_tip)">-&gt;sample</a> beg) 0 index 0
+ #t #t)))
+ (if (symbol? freq)
+ (set! (<em class=red>mix-name</em> id) (symbol-&gt;string freq)))
+ (set! (<a class=quiet href="#mixsync" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixsync_tip)">mix-sync</a> id) cello-sync)
+ (set! (<a class=quiet href="#mixcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixcolor_tip)">mix-color</a> id) cello-color)
+ (set! (<a class=quiet href="#mixtagy" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixtagy_tip)">mix-tag-y</a> id) (frequency-&gt;tag-y (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">-&gt;frequency</a> freq #t) (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">-&gt;frequency</a> 'c2) 3))))
+
+ (<a class=quiet href="#asoneedit" onmouseout="UnTip()" onmouseover="Tip(extsnd_asoneedit_tip)">as-one-edit</a>
+ (lambda ()
+ (violin 0 1 'e4 .2) (violin 1 1.5 'g4 .2) (violin 2.5 .5 'g3 .2)
+ (cello 0 1 'c3 .2) (cello 1 1.5 'e3 .2) (cello 2.5 .5 'g2 .2)
+
+ (violin 3 3 'f4 .2)
+ (cello 3 3 'd3 .2)
+
+ (violin 6 1 'e4 .2) (violin 7 1 'g3 .2) (violin 8 1 'e4 .2)
+ (cello 6 1 'c3 .2) (cello 7 1 'g2 .2) (cello 8 1 'c3 .2)
+
+ (violin 9 3 'd4 .2)
+ (cello 9 3 'b2 .2))))
+</pre></td></tr></table>
+<img src="pix/mixname.png" alt="mix name example" vspace=10>
+<p>
+But note names are a bother to read; musglyphs.scm has code to display notes using CMN glyphs.
+<A NAME="waltzexample">Here</a> we use the draw-mix-hook to display our notes as a score:
+</p>
+<img src="pix/mixcmn.png" alt="mix CMN example" vspace=10>
+<p>
+In more complex cases, using a mix per note fills the screen with mix tags; it's probably cleaner
+to use multiple output files, collecting related notes in one file, then mixing these at the end:
+</p>
+<table border=0 cellpadding=5 vspace=5><tr><td><pre>
+;; open two output files, one for the violin notes, the other for the cellos
+;; then mix them into "test.snd"
+
+(let ((violins (<a class=quiet href="sndclm.html#make-sampletofile" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_sampletofile_tip)">make-sample-&gt;file</a> "violins.snd" 1 <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_muslfloat_tip)">mus-lfloat</a> mus-next))
+ (cellos (<a class=quiet href="sndclm.html#make-sampletofile" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_sampletofile_tip)">make-sample-&gt;file</a> "cellos.snd" 1 <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_muslfloat_tip)">mus-lfloat</a> mus-next)))
+
+ (define (violin beg dur freq amp)
+ (<a class=quiet href="sndscm.html#withtempsound" onmouseout="UnTip()" onmouseover="Tip(sndscm_withtempsound_tip)">with-temp-sound</a> (:continue-old-file #t :output "violins.snd")
+ (<a class=quiet href="sndscm.html#fmviolin" onmouseout="UnTip()" onmouseover="Tip(sndscm_fmviolin_tip)">fm-violin</a> beg dur (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">-&gt;frequency</a> freq #t) amp)))
+
+ (define (cello beg dur freq amp)
+ (<a class=quiet href="sndscm.html#withtempsound" onmouseout="UnTip()" onmouseover="Tip(sndscm_withtempsound_tip)">with-temp-sound</a> (:continue-old-file #t :output "cellos.snd")
+ (<a class=quiet href="sndscm.html#fmviolin" onmouseout="UnTip()" onmouseover="Tip(sndscm_fmviolin_tip)">fm-violin</a> beg dur (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">-&gt;frequency</a> freq #t) amp :fm-index 1.5)))
+
+ (violin 0 1 'e4 .2) (violin 1 1.5 'g4 .2) (violin 2.5 .5 'g3 .2)
+ (cello 0 1 'c3 .2) (cello 1 1.5 'e3 .2) (cello 2.5 .5 'g2 .2)
+ ;; etc
+
+ (let ((index (<a class=quiet href="#newsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_newsound_tip)">new-sound</a> "test.snd" :channels 1))) ; our overall output file
+ (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> "violins.snd")
+ (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> "cellos.snd"))
+
+ (<a class=quiet href="sndclm.html#mus-close" onmouseout="UnTip()" onmouseover="Tip(sndclm_mus_close_tip)">mus-close</a> violins)
+ (<a class=quiet href="sndclm.html#mus-close" onmouseout="UnTip()" onmouseover="Tip(sndclm_mus_close_tip)">mus-close</a> cellos))
+</pre></td></tr></table>
+
+<p>See also <a href="sndscm.html#withmixedsound">with-mixed-sound</a> in ws.scm.
+</p>
+</td></tr><tr><td colspan=2 height=32></td></tr>
+
+
+<!-- mix-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixposition">mix-position</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-position is the current starting position (a sample number) of 'mix'. To move mix mx so that it starts at sample 200 in the output:
+<pre>
+ (set! (mix-position mx) 200)
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-properties -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="mixproperties">mix-properties</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-properties is a property list associated with a mix.
+<a href="sndscm.html#mixproperty">mix-property</a> (in mix.scm) reads and writes this list.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- mix-region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixregion">mix-region</a> (:optional samp reg snd chn reg-chan)</code>
+</td></tr><tr><td></td><td>
+mix-region mixes region 'reg's' channel 'reg-chan' into the given channel starting at sample 'samp' ('samp' defaults to the cursor sample).
+It returns a list of the new mixes.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><em class=emdef>mix-selection</em> (:optional beg snd chn selection-chan)</code>
+</td></tr><tr><td></td><td>
+mix-selection mixes the current selection's channel 'selection-cha' into the given channel starting at 'beg', returning a list of the new mixes.
+The Edit:Mix selection menu choice is essentially <code>(mix-selection (cursor))</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-speed -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixspeed">mix-speed</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-speed is the speed (resampling ratio) of 'mix'; 1.0 (the default) means no resampling takes place;
+2.0 causes the mix data to be read twice as fast.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-sync -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixsync">mix-sync</a> (mix)</code>
+</td></tr><tr><td></td><td>
+mix-sync is an integer, like <a href="#sync">sync</a> that you can use to group mixes. See <a href="sndscm.html#mixdoc">mix.scm</a>
+for many examples.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-sync-max -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixsyncmax">mix-sync-max</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the maximum mix sync value seen so far.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-tag-height -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixtagheight">mix-tag-height</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the mix tag height (the vertical extent of the tag rectangle) in pixels (the default is 14).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-tag-width -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixtagwidth">mix-tag-width</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the mix tag width in pixels (the default is 6).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-tag-y -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixtagy">mix-tag-y</a> (mix)</code>
+</td></tr><tr><td></td><td>
+This is the mix tag y (vertical) offset; 0 (the default) is the top of the graph, so
+higher tag-y values position the tag lower in the graph. For
+example, if you know the frequency of the mix sound, you can reflect that in the tag height with:
+<pre>
+ (set! (mix-tag-y mix-id)
+ (inexact-&gt;exact (round (* 100 (- 1.0 (/ (log (/ freq 40.0)) (* (log 2.0) 7)))))))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixvct">mix-vct</a> (vct :optional beg snd chn with-mix-tags origin)</code>
+</td></tr><tr><td></td><td>
+mix-vct is one of the basic mixing functions. It
+mixes the contents of 'vct' into the given channel starting at sample 'beg'.
+If 'with-mix-tags' is #f (the default is #t), the data is simply
+mixed without creating any mix tags.
+mix-vct returns the id of the new mix, or -1 (a simple mix, no tag).
+<pre>
+ :<em class=typing>(channel-&gt;vct 1000 3)</em> ; what are these 3 samples before the mix?
+ <em class=listener>#&lt;vct[len=3]: -0.065 -0.059 -0.060&gt;</em>
+ :<em class=typing>(define mx (mix-vct (vct .1 .2 .3) 1000))</em> ; add these 3 values
+ <em class=listener>#&lt;mix 3&gt;</em>
+ :<em class=typing>(channel-&gt;vct 1000 3)</em> ; now we hope they were added...
+ <em class=listener>#&lt;vct[len=3]: 0.035 0.141 0.240&gt;</em>
+ :<em class=typing>(mix-position mx)</em> ; and the new mix starts at 1000
+ <em class=listener>1000</em>
+ :<em class=typing>(length mx)</em> ; and its length is 3 samples
+ <em class=listener>3</em>
+ :<em class=typing>(mix-vct (with-sound (:output (make-vct 44100)) (fm-violin 0 1 440 .1)))</em>
+ <em class=listener>#&lt;mix 4&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-waveform-height -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixwaveformheight">mix-waveform-height</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the maximum height in pixels of mix waveforms. The default is 20 (see <a href="#showmixwaveforms">show-mix-waveforms</a>).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixp">mix?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+mix? returns #t if 'obj' is a mix object and it is accessible in a channel's edit list.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- play-mix -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="playmix">play-mix</a> (mix :optional beg)</code>
+</td></tr><tr><td></td><td>
+play-mix plays the mix 'mix'. 'beg' is where to start playing within the mix.
+This function does not return until the play is complete or is interrupted (it is similar to <a href="#playandwait">play-and-wait</a>,
+rather than <a href="#play">play</a>).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- with-mix-tags -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="withmixtags">with-mix-tags</a> ()</code>
+</td></tr><tr><td></td><td>
+If with-mix-tags is #f (the default is #t), newly mixed data does not have a mix id or tag associated with it.
+</td></tr>
+
+</table>
+
+<!-- INDEX sndmixes:Mixing -->
+<br>
+<TABLE border=3 bordercolor="tan" hspace=20><tr><td>
+<blockquote><small>
+<br>
+mix sound file: <a href="#mix">mix</a> or drag-and-drop it where you want it mixed<br>
+mix channel: see <a href="sndscm.html#mixchannel">mix-channel</a> in extensions.scm<br>
+mix region: <a href="#mixregion">mix-region</a><br>
+mix selection: <a href="#mixselection">mix-selection</a><br>
+mix vct: <a href="#mixvct">mix-vct</a><br>
+mix sound-data: <a href="sndscm.html#mixsounddata">mix-sound-data</a><br>
+mix a frame: <a href="sndscm.html#mixframe">mix-frame</a><br>
+enveloped mix: see <a href="sndscm.html#envelopedmix">enveloped-mix</a> in extensions.scm<br>
+read mix samples: <a href="#makemixsampler">make-mix-sampler</a><br>
+mix data maxamp: <a href="sndscm.html#mixmaxamp">mix-maxamp</a><br>
+mix data to vct: <a href="sndscm.html#mixtovct">mix-&gt;vct</a><br>
+save mix data in file: <a href="sndscm.html#savemix">save-mix</a><br>
+mix property list: <a href="sndscm.html#mixproperty">mix-property</a> in mix.scm<br>
+pan mono sound into stereo: see <a href="sndscm.html#placesound">place-sound</a> in examp.scm<br>
+move a mixed sound via dlocsig: <a href="#mixmovesound">mix-move-sound</a><br>
+the mix dialog: <a href="snd.html#mixdialog">Mix Dialog</a><br>
+cross-fade in frequency: cross-fade and dissolve-fade in <a href="sndscm.html#fadedoc">fade.scm</a><br>
+zipper cross-fade: <a href="sndscm.html#zipdoc">zipper.scm</a><br>
+snap mix to beat after drag: <a href="sndscm.html#snapmixtobeat">snap-mix-to-beat</a><br>
+delete all mixes: <a href="sndscm.html#silenceallmixes">silence-all-mixes</a><br>
+with-sound (a notelist) expanded into mixes: <a href="sndscm.html#withmixedsound">with-mixed-sound</a><br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+<br><br>
+
+
+
+<table width="50%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h3><A NAME="sndregions">Regions and Selections</a></h3></td></tr></table>
+
+<br>
+<table width="35%" border=0><tr><td bgcolor="#EEFDEE" valign="middle"><h4>Regions</h4></td></tr></table>
+
+<p>A region is a saved portion of sound data. Use the View:Region browser to inspect, edit, and save regions.
+As regions are defined, the new ones are pushed on a stack, and if enough regions already
+exist, old ones are pushed off (and deleted) to make room.
+</p>
+
+
+<!-- -------------------------------- REGION TABLE -------------------------------- -->
+
+<A NAME="regionstuff"></a>
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- forget-region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="forgetregion">forget-region</a> reg</code>
+</td></tr><tr><td width=30><br></td><td>
+forget-region deletes region 'reg', removing it from the region stack. This does not affect any of the
+active sounds; it just tells Snd that you no longer need any access to one of the current regions.
+To delete all regions,
+<pre>
+ (for-each <em class=red>forget-region</em> (<a class=quiet href="#eregions" onmouseout="UnTip()" onmouseover="Tip(extsnd_eregions_tip)">regions</a>))
+</pre>
+I called this forget-region because delete-region seemed ambiguous, especially given delete-selection.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- insert-region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="insertregion">insert-region</a> reg beg :optional snd chn</code>
+</td></tr><tr><td></td><td>
+insert-region inserts region 'reg' at sample 'beg' in the given channel. The following
+function uses insert-region (and other region functions) to rotate the samples in a channel:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<a name="rotatechannel">rotate-channel</a> :optional (samps 1) snd chn)
+ (let* ((ind (or snd (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (car (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+ (chan (or chn (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>) 0)))
+ (let ((reg (<em class=red>make-region</em> 0 (- samps 1) ind chan)))
+ (<a class=quiet href="#asoneedit" onmouseout="UnTip()" onmouseover="Tip(extsnd_asoneedit_tip)">as-one-edit</a>
+ (lambda ()
+ (<a class=quiet href="#deletesamples" onmouseout="UnTip()" onmouseover="Tip(extsnd_deletesamples_tip)">delete-samples</a> 0 samps ind chan)
+ (<em class=red>insert-region</em> reg (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> ind chan))))
+ (<em class=red>forget-region</em> reg))))
+</pre></td></tr></table></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- integer->region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="integertoregion">integer-&gt;region</a> (i)</code>
+</td></tr><tr><td></td><td>
+In olden times, a region was handled in Snd code as an integer; nowadays, it's an object.
+This function, and its companion <a href="#regiontointeger">region-&gt;integer</a>, exist mainly to convert
+old code to the current style.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- make-region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="makeregion">make-region</a> :optional beg end snd chn</code>
+</td></tr><tr><td></td><td>
+make-region creates a new region spanning the samples 'beg' to 'end' in the given channel.
+It returns the new region. If no arguments are given, the
+current selection is used. If 'chn' is #t, all chans are included, taking the <a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> fields into account.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- make-region-sampler -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a href="#makeregionsampler">make-region-sampler</a> reg :optional start chn (dir 1)</code>
+</td></tr><tr><td></td><td>
+This creates a <a href="#samplers">sampler</a> reading the region's channel 'chn' starting at sample 'start' within that region.
+'dir' can be 1 (read forwards) or -1 (read backwards).
+</td></tr>
+<tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><em class=emdef>mix-region</em> reg samp :optional snd chn</code>
+</td></tr><tr><td></td><td>
+mix-region mixes region 'reg' into the given channel starting at sample 'samp' (defaulting to the cursor location).
+It returns a list of mixes, one for each channel mixed.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- play-region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="playregion">play-region</a> reg :optional wait stop-func</code>
+</td></tr><tr><td></td><td>
+play-region plays region 'reg'; if wait is #t, it plays to the end before returning. The 'stop-func'
+can be a function which is called when the play process stops. Its one argument is
+the reason the play is stopping; it will be 0 if the play completed normally.
+To see all possible reasons, see <a href="#stopplayreasons">play</a>.
+Here is a brief example (taken from play.scm) that plays a region over and over until someone types C-g:
+<pre>
+ (<em class=red>play-region</em> reg #f
+ (letrec ((stop-func (lambda (reason)
+ (if (and (not (<a class=quiet href="#cgp" onmouseout="UnTip()" onmouseover="Tip(extsnd_cgp_tip)">c-g?</a>))
+ (= reason 0)) ; 0 -&gt; play completed normally
+ (<em class=red>play-region</em> reg #f stop-func)))))
+ stop-func))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-chans -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionchans">region-chans</a> reg</code>
+</td></tr><tr><td></td><td>
+This returns the number of channels in the region 'reg'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-frames -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionframes">region-frames</a> reg :optional (chan 0)</code>
+</td></tr><tr><td></td><td>
+region-frames returns the number of frames in the region 'reg'.
+<pre>
+ :<em class=typing>(make-region 100 200)</em>
+ <em class=listener>#&lt;region 1&gt;</em>
+ :<em class=typing>(region-frames (integer-&gt;region 1))</em>
+ <em class=listener>101</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-graph-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regiongraphstyle">region-graph-style</a> style</code>
+</td></tr><tr><td></td><td>
+region-graph-style is the graph drawing choice for the region dialog's graph.
+The choices are:
+<pre>
+ graph-lines graph-dots graph-filled graph-lollipops graph-dots-and-lines
+</pre>
+<code>graph-lines</code> is the default.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-home -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionhome">region-home</a> reg</code>
+</td></tr><tr><td></td><td>
+This returns a list with the name of the source file for the given region, its start time in the original
+data, and its length in frames.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region->integer -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regiontointeger">region->integer</a> (region)</code>
+</td></tr><tr><td></td><td>
+This is the counterpart to <a href="#integertoregion">integer-&gt;region</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-maxamp -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionmaxamp">region-maxamp</a> reg</code>
+</td></tr><tr><td></td><td>
+region-maxamp is the peak amplitude of the samples in the region 'reg'.
+<pre>
+ :<em class=typing>(region-maxamp (integer-&gt;region 1))</em>
+ <em class=listener>4.8828125e-4</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-maxamp-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionmaxampposition">region-maxamp-position</a> reg</code>
+</td></tr><tr><td></td><td>
+region-maxamp-position returns the location (a sample number) of the peak amplitude of the region 'reg'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionposition">region-position</a> reg :optional chan</code>
+</td></tr><tr><td></td><td>
+region-position returns the begin time of the region's channel 'chan' in the original sound.
+<pre>
+ :<em class=typing>(make-region 1000 2000)</em>
+ <em class=listener>2</em>
+ :<em class=typing>(region-position (integer-&gt;region 2))</em>
+ <em class=listener>1000</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionsample">region-sample</a> reg samp :optional chan</code>
+</td></tr><tr><td></td><td>
+region-sample returns the value of the sample 'samp' in channel 'chan' of the region 'reg'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region->vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regiontovct">region-&gt;vct</a> reg :optional samp samps chan v</code>
+</td></tr><tr><td></td><td>
+region-&gt;vct returns a vct containing 'samps' samples starting at 'samp' in channel 'chan' of the region 'reg'.
+If 'v' (a vct) is provided, it is filled,
+rather than creating a new vct.
+
+<table border=0 cellpadding=5><tr><td><pre>
+(define (region-rms n)
+ (let* ((data (<em class=red>region-&gt;vct</em> (integer-&gt;region 0) 0 #f n))
+ (len (length data)))
+ (sqrt (/ (<a class=quiet href="sndclm.html#dot-product" onmouseout="UnTip()" onmouseover="Tip(sndclm_dot_product_tip)">dot-product</a> data data len) len))))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region-srate -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionsrate">region-srate</a> reg</code>
+</td></tr><tr><td></td><td>
+region-srate returns the sampling rate of the data that makes up the region 'reg'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- regions -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="eregions">regions</a> </code>
+</td></tr><tr><td></td><td>
+regions returns a list of active regions. The most recently created region is <code>(car (regions))</code>.
+<code>(map region-frames (regions))</code> returns a list of region lengths.
+The maximum length of this list is set by <a href="#maxregions">max-regions</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- region? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="regionok">region?</a> reg</code>
+</td></tr><tr><td></td><td>
+region? returns #t if the region 'reg' exists. There is a limit to how many regions Snd tries to
+keep track of (<a href="#maxregions">max-regions</a>); when necessary, the least-recently created region is
+deleted.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-region -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="saveregion">save-region</a> reg <a class=quiet href="sndclm.html#optional-key" onmouseout="UnTip()" onmouseover="Tip(sndclm_optional_key_tip)">&amp;optional-key</a> :file :header-type :data-format :comment</code>
+</td></tr><tr><td></td><td>
+save-region saves the region 'reg' in 'file' in the given data format and header type.
+It returns the output filename. The arguments after 'reg' are <a class=quiet href="sndclm.html#optional-key" onmouseout="UnTip()" onmouseover="Tip(sndclm_optional_key_tip)">optional-key</a>
+args (that is, they are normal keyword arguments, but the keywords are optional). The following calls are equivalent:
+<pre>
+ (save-region reg "reg0.snd")
+ (save-region reg :file "reg0.snd" :header-type mus-next)
+ (save-region reg "reg0.snd" mus-next <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_musbfloat_tip)">mus-bfloat</a> "a comment")
+ (save-region reg :file "reg0.snd" :comment "a comment" :data-format <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_musbfloat_tip)">mus-bfloat</a>)
+</pre>
+</td></tr>
+
+</table>
+
+<br>
+<!-- INDEX regionstuff:Regions -->
+<TABLE border=3 bordercolor="tan" hspace=20><tr><td>
+<small><blockquote>
+Max length of region list: <a href="#maxregions">max-regions</a><br>
+Whether selection creates a region: <a href="#selectioncreatesregion">selection-creates-region</a><br>
+To play region repeatedly: <a href="sndscm.html#playregionforever">play-region-forever</a><br>
+Start region browser from Scheme: <a href="#viewregionsdialog">view-regions-dialog</a><br>
+All about regions: <a href="snd.html#regions">regions</a><br>
+The region dialog: <a href="snd.html#regionbrowser">region browser</a><br>
+Region rms amp: <a href="sndscm.html#regionrms">region-rms</a><br>
+region-play-list and region-play-sequence in examp.scm<br>
+<a href="sndscm.html#regiontoframe">region-&gt;frame</a><br>
+<a href="sndscm.html#regiontosounddata">region-&gt;sound-data</a><br>
+<a href="sndscm.html#makeregionframereader">make-region-frame-reader</a><br>
+<br>
+</blockquote></small>
+</td></tr></TABLE>
+<br><br>
+
+
+<table width="35%" border=0><tr><td bgcolor="#EEFDEE" valign="middle"><h4>Selections</h4></td></tr></table>
+
+
+<!-- -------------------------------- SELECTION TABLE -------------------------------- -->
+<br>
+<A NAME="selectionstuff"></a>
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- convolve-selection-with -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="convolveselectionwith">convolve-selection-with</a> (file :optional amp)</code>
+</td></tr><tr><td width=30><br></td><td>
+convolve-selection-with convolves the current selection with 'file', replacing the selection with the result.
+'amp' sets the maxamp of the result.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- delete-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="deleteselection">delete-selection</a> ()</code>
+</td></tr><tr><td></td><td>
+delete-selection deletes the selection, equivalent to the Edit:Delete selection menu choice.
+</td></tr>
+<tr><td colspan=2 height=16></td></tr>
+
+
+<!-- env-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envselection">env-selection</a> (envelope :optional env-base)</code>
+</td></tr><tr><td></td><td>
+env-selection applies 'envelope' to the selection. (as an amplitude envelope).
+'envelope' can also be a CLM env generator; in this case, 'env-base' is ignored.
+These are equivalent:
+<pre>
+ (env-selection '(0 0 1 1 2 0))
+ (env-selection (<a class=quiet href="sndclm.html#make-env" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_env_tip)">make-env</a> '(0 0 1 1 2 0) :length (<a class=quiet href="#selectionframes" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionframes_tip)">selection-frames</a>)))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- filter-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="filterselection">filter-selection</a> (env :optional order truncate)</code>
+</td></tr><tr><td></td><td>
+filter-selection applies an FIR filter of order 'order' and frequency response 'env'
+to the selection. 'env' can be the filter coefficients
+themselves in a vct with at least 'order' elements, or
+a CLM filtering generator (see <a href="#filtersound">filter-sound</a>).
+If 'truncate' is #t (the default), the filter output is truncated at the selection
+end. If 'truncate' is #f, the extra output ('order' samples worth) is mixed into the stuff following the selection.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- insert-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="insertselection">insert-selection</a> (:optional beg snd chn)</code>
+</td></tr><tr><td></td><td>
+insert-selection inserts a copy of the selection starting at 'beg' in the given channel (that is, it pastes in the selection
+as a block).
+The Edit:Insert selection menu choice is essentially <code>(insert-selection (cursor))</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixselection">mix-selection</a> (:optional beg snd chn)</code>
+</td></tr><tr><td></td><td>
+mix-selection mixes (adds) a copy of the selection starting at 'beg' in the given channel, and returns a list of the new mixes.
+The Edit:Mix selection menu choice is <code>(mix-selection (cursor))</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- play-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="playselection">play-selection</a> (:optional wait edpos stop-func)</code>
+</td></tr><tr><td></td><td>
+play-selection plays the selection. 'edpos' is the edit position which default to the current edit.
+If 'wait' is #t, play-selection does not return until the play has completed.
+If 'stop-func' is a procedure of one argument, it is called when the play process stops.
+The argument provides the reason the play is stopping; it will be 0 if the play completed normally.
+See <a href="#playregion">play-region</a> for an example, and <a href="#stopplayreasons">play</a>
+for a complete list of these reasons.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reverse-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="reverseselection">reverse-selection</a> ()</code>
+</td></tr><tr><td></td><td>
+reverse-selection reverses the selection.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="saveselection">save-selection</a> (<a class=quiet href="sndclm.html#optional-key" onmouseout="UnTip()" onmouseover="Tip(sndclm_optional_key_tip)">&amp;optional-key</a> :file (:header-type mus-next) :data-format :srate :comment :channel)</code>
+</td></tr><tr><td></td><td>
+save-selection saves the selection in 'file'. If 'channel' is given, it saves only that channel.
+See popup.scm for an example.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (brksnd dur base)
+ "(brksnd dur base) divides the current sound into dur-sized pieces,
+saving them in files named 'base'.n: (brksnd 1.0 \"sec\")"
+ (let ((hop (inexact-&gt;exact (* (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>) dur)))
+ (len (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>))
+ (old-sync (<a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a>)))
+ (set! (<a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a>) 1) ; save all chans
+ (do ((i 0 (+ i hop))
+ (j 0 (+ 1 j)))
+ ((&gt;= i len))
+ (<a class=quiet href="sndscm.html#makeselection" onmouseout="UnTip()" onmouseover="Tip(sndscm_makeselection_tip)">make-selection</a> i (+ i hop)) ; in extensions.scm
+ (<em class=red>save-selection</em> (string-append base "." (number-&gt;string j))))
+ (set! (<a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a>) old-sync)))
+</pre></td></tr></table>
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<a name="extractchannels">extract-channels</a> #:rest chans)
+ ;; extract a list of channels from the current sound and save as test.snd: (extract-channels 0 2)
+ (let ((snd (or (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (car (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>)))))
+ (if (<a class=quiet href="#soundp" onmouseout="UnTip()" onmouseover="Tip(extsnd_soundp_tip)">sound?</a> snd)
+ (begin
+ (for-each
+ (lambda (chan)
+ (set! (<a class=quiet href="#selectionmember" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionmember_tip)">selection-member?</a> snd chan) #t)
+ (set! (<a class=quiet href="#selectionposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionposition_tip)">selection-position</a> snd chan) 0)
+ (set! (<a class=quiet href="#selectionframes" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionframes_tip)">selection-frames</a> snd chan) (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd chan)))
+ chans)
+ (<em class=red>save-selection</em> "test.snd")))))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- scale-selection-by -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="scaleselectionby">scale-selection-by</a> (scalers)</code>
+</td></tr><tr><td></td><td>
+scale-selection-by scales (multiplies) the selection by 'scalers' which can be either a float,
+a list of floats, or a vct. In a multichannel selection, each member of the vct or list
+is applied to the next channel in the selection. <code>(scale-selection-by '(0.0 2.0))</code> scales
+the first channel by 0.0, the second (if any) by 2.0. <code>(scale-selection-by 2.0)</code> scales
+all channels by 2.0. Normally the order of channels follows the order of the sounds.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- scale-selection-to -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="scaleselectionto">scale-selection-to</a> (:optional norms)</code>
+</td></tr><tr><td></td><td>
+scale-selection-to normalizes the selection to peak amplitude 'norms' which can be either a float,
+a list of floats, or a vct.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- select-all -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectall">select-all</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This function selects all samples in the given channel.
+If a region is created, it returns the new region.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection-chans -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectionchans">selection-chans</a> ()</code>
+</td></tr><tr><td></td><td>
+selection-chans returns the number of channels in the current selection.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection-frames -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectionframes">selection-frames</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+selection-frames returns the number of frames in the current selection (its length in samples).
+You can set this to move the selection end point:
+<pre>
+ :<em class=typing>(select-all)</em> ; grab all of current channel
+ <em class=listener>#&lt;region 1&gt;</em>
+ :<em class=typing>(selection-frames)</em>
+ <em class=listener>55240</em>
+ :<em class=typing>(set! (selection-frames) 10000)</em> ; unselect all but the starting 10000
+ <em class=listener>10000</em>
+ :<em class=typing>(selection-frames)</em>
+ <em class=listener>10000</em>
+ :<em class=typing>(set! (selection-frames) (* 2 (selection-frames)))</em> ; double the selection length
+ <em class=listener>20000</em>
+</pre>
+See also <a href="sndscm.html#makeselection">make-selection</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection-maxamp -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectionmaxamp">selection-maxamp</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+selection-maxamp returns the peak amplitude of the selection in the given channel.
+I use this to provide a view of the selection amplitude envelope in the envelope editor. If you select
+'selection' and 'wave' in that dialog, it displays a copy of whatever is in the main channel graph,
+so to get a display that makes it easy to "connect the dots", I use C-x m:
+<pre>
+ (<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> #\m 0
+ (lambda ()
+ (set! (<a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a> (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>)) (list 0 (<em class=red>selection-maxamp</em>))))
+ #t)
+
+ (<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> #\m 4
+ (lambda ()
+ (set! (<a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a> (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>)) (list -1.0 1.0)))
+ #t)
+</pre>
+The second key binding (C-x C-m), undoes the previous C-x m. Another useful key binding in this regard is C-x v, the
+built-in command to fill the current window with the selection.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection-maxamp-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectionmaxampposition">selection-maxamp-position</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+selection-maxamp-position returns the location (a sample number) of the peak amplitude of the selection in the given channel.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection-member? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectionmember">selection-member?</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+selection-member? returns #t if the given channel has data that is currently selected.
+This is mostly useful when adding a channel to the current selection; see
+<a href="sndscm.html#makeselection">make-selection</a> in extensions.scm.
+If 'snd' is #t and the new value is #f, the entire selection is deactivated
+<pre>
+ (set! (<em class=red>selection-member?</em> #t) #f)
+</pre>
+ie equivalent to unselect-all.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectionposition">selection-position</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+selection-position is the sample where selection begins.
+You can set this to move the selection's starting point to some arbitrary sample.
+If changed, the selection end point stays the same, while the length (<a class=quiet href="#selectionframes" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionframes_tip)">selection-frames</a>) changes to reflect the
+moved origin.
+See <a href="sndscm.html#makeselection">make-selection</a> in extensions.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection-srate -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectionsrate">selection-srate</a> ()</code>
+</td></tr><tr><td></td><td>
+This function returns the selection srate. There's some arbitrariness in this if the sounds that make up the selection have different sampling rates.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="selectionok">selection?</a> ()</code>
+</td></tr><tr><td></td><td>
+selection? returns #t if there is a selection.
+<pre>
+ :<em class=typing>(select-all)</em>
+ <em class=listener>#&lt;region 2&gt;</em>
+ :<em class=typing>(selection?)</em>
+ <em class=listener>#t</em>
+ :<em class=typing>(set! (selection-member? #t) #f)</em>
+ <em class=listener>#f</em>
+ :<em class=typing>(selection?)</em>
+ <em class=listener>#f</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- smooth-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="smoothselection">smooth-selection</a> ()</code>
+</td></tr><tr><td></td><td>
+smooth-selection applies a smoothing function to the selection, producing a sinusoid between
+the selection end points. In normal use, you'd bind this function to some key,
+select a portion (say a few samples) of a sound around a click,
+then smooth it by typing that key.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- src-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="srcsoundselection">src-selection</a> (num-or-env :optional base) </code>
+</td></tr><tr><td></td><td>
+src-selection applies sampling rate conversion to the selection;
+this is the same as src-sound but as applied to the selection.
+</td></tr>
+</table>
+<br>
+
+<!-- INDEX selectionstuff:Selections -->
+<TABLE border=3 bordercolor="tan" hspace=20><tr><td>
+<small><blockquote>
+show the current selection: <a href="sndscm.html#showselection">show-selection</a><br>
+color of selected portion: <a href="#selectioncolor">selection-color</a><br>
+set whether creating a selection creates a region: <a href="#selectioncreatesregion">selection-creates-region</a><br>
+fft graph refers to the selection: <a href="#showselectiontransform">show-selection-transform</a><br>
+hook called when selection stops playing: <a href="#stopplayingselectionhook">stop-playing-selection-hook</a><br>
+swap chans in selected portion: <a href="sndscm.html#swapselectionchannels">swap-selection-channels</a><br>
+replace portion with selection: <a href="sndscm.html#replacewithselection">replace-with-selection</a><br>
+select portion via function: <a href="sndscm.html#makeselection">make-selection</a><br>
+evaluate func on each sample of selection: <a href="sndscm.html#evaloverselection">eval-over-selection</a> (map-selection in effect)<br>
+selection members as list of lists of sounds and channels: <a href="sndscm.html#selectionmembers">selection-members</a><br>
+rms of selection data: <a href="sndscm.html#selectionrms">selection-rms</a><br>
+delete selection and smooth the splice: <a href="sndscm.html#deleteselectionandsmooth">delete-selection-and-smooth</a><br>
+select portion between two marks: <a href="sndscm.html#defineselectionviamarks">define-selection-via-marks</a><br>
+place marks at selection start and end: <a href="sndscm.html#snapmarks">snap-marks</a><br>
+squeeze selection between marks: <a href="sndscm.html#fitselectionbetweenmarks">fit-selection-between-marks</a><br>
+add context-sensitive popup menu specific to selection: <a href="sndscm.html#popupdoc">add-selection-popup</a><br>
+delete selection and write it to a file: <a href="sndscm.html#menusdoc">cut-selection-&gt;new</a><br>
+append selection: <a href="sndscm.html#menusdoc">append-selection</a><br>
+write selection to a file: <a href="sndscm.html#menusdoc">selection-&gt;new</a><br>
+notch filter selection: <a href="sndscm.html#notchselection">notch-selection</a><br>
+undo select-all.: <a href="sndscm.html#menusdoc">deselect-all</a><br>
+filter the selection: <a href="#filterselection">filter-selection</a>, <a href="sndscm.html#filterselectionandsmooth">filter-selection-and-smooth</a><br>
+<br>
+</blockquote></small>
+</td></tr></TABLE>
+
+<p>The selected portion can be chosen, independent of any region, by setting selection-position and selection-frames.
+It's easy to extend the notion of a selection to an arbitrary list of sound portions:
+</p>
+<table border=0 cellpadding=5 hspace=20><tr><td><pre>
+(define (make-section . members)
+ ;; each member is '(beg dur snd chn)
+ (append (list 'Section) members))
+
+(define (section-for-each func section)
+ ;; call func on each member of the section
+ (<a class=quiet href="#asoneedit" onmouseout="UnTip()" onmouseover="Tip(extsnd_asoneedit_tip)">as-one-edit</a> (lambda () (for-each func (cdr section)))))
+
+;; an example that scales each member of the section by .5
+(section-for-each
+ (lambda (sect)
+ (apply <a class=quiet href="#scalechannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_scalechannel_tip)">scale-channel</a> (append (list .5) sect)))
+ (make-section (list 0 10000 0 0) (list 30000 10000 0 0)))
+</pre></td></tr></table>
+
+
+<br><br><br>
+<table width="50%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h3><A NAME="sndsounds">Sounds and channels</a></h3></td></tr></table>
+
+<p>This is the heart of Snd; we've waded through all the ancillary junk, and we've
+finally reached the functions that actually edit sounds! Most of these functions
+take both a sound and a channel number. When the function refers to a variable
+that can be set locally on a sound (zero-pad, for example),
+the 'snd' and 'chn' arguments can be #t, referring to all current sounds or all channels of a sound;
+this possibility is identified below by displaying the arguments in this weird brownish color:
+<em class=narg>snd</em> or <em class=narg>snd chn</em>. (I tried green, but it is illegible, and I'm already
+using red and blue all over the place).
+In cases where it makes sense, if the 'snd' argument is omitted, the
+reference is to the global default value. So, <code>(set! (amp-control-bounds) '(0.0 2.0))</code>
+sets the global amp control (slider) bounds to be between 0.0 and 2.0, whereas
+<code>(set! (amp-control-bounds snd) '(0.0 2.0))</code> sets it only for the sound referred to by 'snd'.
+</p>
+
+<p>Many of the procedures also have an 'edpos' argument (standing for "edit position").
+It always defaults to the current edit history position. If specified, it can be either an edit history position (to which
+the operation is applied), the constant <a name="currenteditposition">current-edit-position</a> (the default), or a function
+of two arguments, the sound and the channel number. The function should return the
+desired edit history position. In most cases, you should only refer to edits in the past
+(that is, 'edpos' should be less than or equal to the current edit-position); in a few
+situations, you can make use of data in the "redo" section of the edit-history list, but
+nothing is guaranteed.
+</p>
+
+<table border=1 hspace=100 cellpadding=10>
+<tr><td>
+<p>
+<A NAME="regularizedargs"></a>
+For not-very-good historical reasons (it took me awhile to decide how to organize things), some of the procedures here are unnecessarily inconsistent in
+what arguments they accept, whether a channel of #t signals application to all channels or just the
+selected one, whether the <a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> field is followed, and so on. Rather than make a bunch of backwards
+incompatible changes, I decided to add a bunch of more-or-less synonymous functions that regularize
+these calls. The replacements always take arguments in the order begin time, duration (not end sample),
+sound, channel number, and edit position, possibly preceded by one argument, and sometimes followed by
+an edit history name or 'ring time' (overlap). The <a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> field is ignored, an unspecified sound argument applies only to the
+current sound, and an unspecified channel argument applies only to the current channel.
+The following substitutions can be made:
+</p>
+
+<pre>
+<a href="#convolvewith">convolve-with</a> file amp s c e <a href="#clmchannel">clm-channel</a> convolve-gen beg dur s c e
+<a href="#envsound">env-sound</a> env beg dur base s c e <a href="#envchannel">env-channel</a> env beg dur s c e
+<a href="#filtersound">filter-sound</a> env order s c e <a href="#filterchannel">filter-channel</a> env order beg dur s c e trunc
+<a href="#insertsilence">insert-silence</a> beg dur s c <a href="#padchannel">pad-channel</a> beg dur s c e
+<a href="#insertsound">insert-sound</a> file beg filechn s c e <a href="sndscm.html#insertchannel">insert-channel</a> filedat beg dur s c e
+<a href="#mix">mix</a> file beg filechn s c with-tags <a href="sndscm.html#mixchannel">mix-channel</a> filedat beg dur s c e
+<a href="#play">play</a> beg s c sync end e <a href="#playchannel">play-channel</a> beg dur s c e
+<a href="#redo">redo</a> edits s c <a href="#redochannel">redo-channel</a> edits s c
+<a href="#reversesound">reverse-sound</a> s c e <a href="#reversechannel">reverse-channel</a> beg dur s c e
+<A href="#scaleby">scale-by</a> scls s c <a href="#scalechannel">scale-channel</a> scl beg dur s c e
+<A href="#scaleto">scale-to</a> scls s c <a href="#normalizechannel">normalize-channel</a> norm beg dur s c e
+<a href="#setsamples">set-samples</a> beg dur data s c trunc origin fchan <a href="#vcttochannel">vct-&gt;channel</a> vct beg dur s c e
+<a href="#smoothsound">smooth-sound</a> beg dur s c <a href="#smoothchannel">smooth-channel</a> beg dur s c e
+<a href="#srcsound">src-sound</a> num base s c e <a href="#srcchannel">src-channel</a> ratio-or-env beg dur s c e
+<a href="#undo">undo</a> edits s c <a href="#undochannel">undo-channel</a> edits s c
+<a href="grfsnd.html#applyladspa">apply-ladspa</a> reader dat dur origin snd chn <a href="grfsnd.html#ladspachannel">ladspa-channel</a> dat beg dur s c e
+</pre>
+
+<p>Another case that might deserve "regularization" is <a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> which confusingly interpolates
+the direction argument between the channel and edit-position:
+</p>
+<pre> (define* (read-channel :optional (beg 0) snd chn edpos (direction 1))
+ (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> beg snd chn direction edpos))
+</pre>
+
+<p>
+The edit position argument can cause ambiguity in a few cases. What should Snd do with:
+<code>(pad-channel 100 0 snd chn 2)</code>?
+It currently treats any 0-length operation as a no-op, so the edit history is not changed by this function call.
+However, in a similar situation (where the current edit counter is greater than 2, so this code is reaching
+back into the edit history list): <code>(scale-channel 1.0 0 #f snd chn 2)</code>
+Snd essentially copies the state of the channel at that edit position, and puts it in the current edit position.
+There's never any good reason to do this, so if it looks like a no-op, do it a different way.
+</p>
+</td></tr></table>
+
+<br>
+
+
+<!-- -------------------------------- SOUND AND CHANNEL TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- add-player -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addplayer">add-player</a> (player :optional start end edpos stop-proc out-chan)</code>
+</td></tr><tr><td width=30></td><td>
+add-player adds 'player' to the play-list (see <a href="#makeplayer">make-player</a>).
+If 'edpos' is given, play at that edit position.
+'stop-proc' can be a procedure of one argument; it is called when the play process stops and passed
+the reason the play is stopping; it will be 0 if the play completed normally (the other possibilities
+are listed <a href="#stopplayreasons">here</a>, but they really aren't interesting).
+The 'out-chan' argument is the audio output channel to send the data to; it defaults to
+the channel number of the player's channel in the containing sound (that is, the default is to
+send channel 1 data to channel 1 of the DAC, and so on).
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (play-mono-as-stereo :optional snd)
+ "(play-mono-as-stereo snd) sends the channel 0 data in 'snd' to all available DAC channels."
+ (let ((vals (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> 3))
+ (end (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd)))
+ (<a class=quiet href="#musaudiomixerread" onmouseout="UnTip()" onmouseover="Tip(extsnd_musaudiomixerread_tip)">mus-audio-mixer-read</a> mus-audio-default mus-audio-channel 3 vals)
+ (let ((chans (max (inexact-&gt;exact (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> vals 0)) 2))) ; assume stereo is out there
+ (do ((chan 0 (+ 1 chan))) ; get a player for each output channel
+ ((= chan chans))
+ (let ((player (<em class=red>make-player</em> snd 0)))
+ (<em class=red>add-player</em> player 0 end current-edit-position #f chan)))
+ (<em class=red>start-playing</em> chans (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> snd)))))
+</pre></td></tr></table>
+
+See play-with-envs in enved.scm, play-syncd-marks in marks.scm, or start-dac in play.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- axis-info -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="axisinfo">axis-info</a> (snd chn :optional grf)</code>
+</td></tr><tr><td><br></td><td>
+axis-info returns a list describing the specified axis:
+<pre>
+ (list left-sample right-sample
+ x0 y0 x1 y1 x-min y-min x-max y-max
+ x0-position y0-position x1-position y1-position y-offset
+ xlabel ylabel new-peaks)
+</pre>
+This can be
+useful if you're drawing arbitrary figures in a graph. 'grf' defaults to
+<code>time-graph</code>; the other choices are <code>transform-graph</code> and <code>lisp-graph</code>.
+'x0' is the time in seconds corresponding to the left-sample (the left edge of the graph).
+Similarly 'y0' is the lower y axis limit as a sample value (i.e. -1.0).
+'x-max' is the sound's duration in seconds ('x-min' is always 0.0).
+The "positions" are pixel values, in drawing area coordinates; these give the position
+of the graph in the drawing area. 'y-offset' refers to "united" graphs where
+several channels share one drawing area. You can use it to translate mouse coordinates
+to channel number in that situation.
+For example, <a href="#xtoposition">x-&gt;position</a>
+could be:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (x-&gt;position-1 x snd chn)
+ (let* ((axinfo (<em class=red>axis-info</em> snd chn <a class=quiet onmouseout="UnTip()" onmouseover="Tip(extsnd_time_graph_tip)">time-graph</a>))
+ (x0 (list-ref axinfo 2))
+ (x1 (list-ref axinfo 4))
+ (axis-left (list-ref axinfo 10))
+ (axis-right (list-ref axinfo 12)))
+ (inexact-&gt;exact
+ (+ axis-left
+ (* (- x x0)
+ (/ (- axis-right axis-left)
+ (- x1 x0)))))))
+</pre></td></tr></table>
+
+Here's a key binding that uses axis-info to save every channel's graph position upon "Page Down",
+then restore that state upon "Page Up":
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> "Page_Down" 0
+ (lambda ()
+ (let ((last-page-state
+ (map (lambda (snd)
+ (let ((data (list snd (<a class=quiet href="#filename" onmouseout="UnTip()" onmouseover="Tip(extsnd_filename_tip)">file-name</a> snd))))
+ (do ((i 0 (+ 1 i)))
+ ((= i (<a class=quiet href="#channels" onmouseout="UnTip()" onmouseover="Tip(extsnd_channels_tip)">channels</a> snd)) data)
+ (set! data (append data (list (cons i (<em class=red>axis-info</em> snd i))))))))
+ (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+ (<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> "Page_Up" 0
+ (lambda ()
+ (if last-page-state
+ (for-each
+ (lambda (lst)
+ (let ((snd (list-ref lst 0))
+ (name (list-ref lst 1)))
+ (if (and (<a class=quiet href="#soundp" onmouseout="UnTip()" onmouseover="Tip(extsnd_soundp_tip)">sound?</a> snd)
+ (string=? (<a class=quiet href="#filename" onmouseout="UnTip()" onmouseover="Tip(extsnd_filename_tip)">file-name</a> snd) name))
+ (for-each
+ (lambda (chan-data)
+ (let ((chn (list-ref chan-data 0))
+ (x0 (list-ref chan-data 3))
+ (x1 (list-ref chan-data 5))
+ (y0 (list-ref chan-data 4))
+ (y1 (list-ref chan-data 6)))
+ (set! (<a class=quiet href="#xbounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_xbounds_tip)">x-bounds</a> snd chn) (list x0 x1))
+ (set! (<a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a> snd chn) (list y0 y1))))
+ (cddr lst)))))
+ last-page-state)))))))
+</pre></td></tr></table>
+
+See also draw-smpte-label in snd-motif.scm, or make-current-window-display in draw.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- beats-per-measure -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="beatspermeasure">beats-per-measure</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+The x axis labelling of the time domain waveform can be in measures
+(<a class=quiet href="#xaxisstyle" onmouseout="UnTip()" onmouseover="Tip(extsnd_xaxisstyle_tip)">x-axis-style</a> = <code>x-axis-in-measures</code>); this variable sets the number of beats per measure.
+The default is 4.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- beats-per-minute -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="beatsperminute">beats-per-minute</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+The x axis labelling of the time domain waveform can be in beats
+(<a class=quiet href="#xaxisstyle" onmouseout="UnTip()" onmouseover="Tip(extsnd_xaxisstyle_tip)">x-axis-style</a> = <code>x-axis-in-beats</code>) or in measures
+(<code>x-axis-in-measures</code>); this variable sets the number of beats per minute.
+The default is 60.0, making it the same as <code>x-axis-in-seconds</code>.
+See <a href="#snpmark">snap-mark-to-beat</a>, or <a href="sndscm.html#snapmixtobeat">snap-mix-to-beat</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- bomb -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="bomb">bomb</a> (:optional snd on)</code>
+</td></tr><tr><td></td><td>
+bomb displays an exploding bomb icon next to 'snd's' name (in the minibuffer area). Set 'on' to #f to erase the bomb. Each time bomb
+is called, the bomb icon moves to the next image in its sequence (showing the bomb's fuse burning down),
+restarting the sequence whenever it reaches the end. This icon is used when a sound and its underlying file
+get out of sync somehow (<a href="#autoupdate">auto-update</a>).
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define show-bomb
+ (lambda (n speed)
+ (if (&gt; n 0)
+ (begin
+ (<em class=red>bomb</em>)
+ (<a class=quiet href="#gin" onmouseout="UnTip()" onmouseover="Tip(extsnd_gin_tip)">in</a> speed (lambda () (show-bomb (- n 1) speed))))
+ (<em class=red>bomb</em> 0 #f))))
+
+(show-bomb 15 200) ; there are 15 images in the sequence
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- channel-amp-envs -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="channelampenvs">channel-amp-envs</a> (file chan size :optional peak-file-func work-proc-func)</code>
+</td></tr><tr><td></td><td>
+channel-amp-envs returns two vcts of length 'size' containing the peak-amp envelopes of the channel 'chan' of file 'file'.
+'peak-file-func' (if any) is used to get the name of the associated peak-env-info file if the file is very large.
+'work-proc-func' is called when the amp envs are ready if the amp envs are gathered in the background.
+If 'file' is a sound, 'size' is an edit-position, and the current amp envs (if any) are returned.
+The arguments to 'peak-file-func' are the file and the channel. If it returns a string, that is treated as the filename
+to read to get the peak info. The arguments to 'work-proc-func' are the filename, the channel and the current peak.
+make-sound-icon in <a href="sndscm.html#makesoundbox">make-sound-box</a> in snd-motif.scm uses
+this function to draw the little thumbnail graph for each sound icon.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- channel-data -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="channeldata">channel-data</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+channel-data provides very low-level access to the data currently in the given channel's sample buffers.
+It is used by the <a href="sndscm.html#variabledisplay">variable-display</a> mechanism to show graphs
+of variable values (normally in an instrument). channel-data only works with sounds returned
+by make-variable-display, and only in a float-sample version of Snd (i.e. not one that was built with
+the configure argument --without-float-samples). See make-variable-display in snd-motif.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- channel-properties -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="channelproperties">channel-properties</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+channel-properties is a property list associated with a channel. It is set to '() at the time a sound is opened, so
+it provides a relatively simple way to save data about a channel which will automatically be erased when the channel is closed.
+<a href="sndscm.html#channelproperty">channel-property</a> (in extensions.scm) reads and writes this list.
+<br><br>
+Traditionally in Lisp, a property list has been treated as an association list. This is a list
+of pairs (made by cons), each inner pair having a key as its first element, and the associated value as the second element.
+The function <b>assoc</b> can be used to search the list for a given key's value; a new key-value pair can be
+added with:
+<pre>
+ (cons (cons key value) a-list)
+</pre>
+In Common Lisp, property lists have other properties, so to speak, but channel-properties (and
+<a href="#soundproperties">sound-properties</a>) can be handled in any way you like.
+See <a href="sndscm.html#channelsync">channel-sync</a> in extensions.scm for a brief example; more
+elaborate examples are in enved.scm (enved-envelope), or draw.scm (colored-samples and insert-envelope).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- channel-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="channelstyle">channel-style</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+channel-style reflects the value of the '<a href="snd.html#unitebutton">unite</a>' button in multichannel files.
+Possible values are <code>channels-separate</code>, <code>channels-combined</code> (the default), and <code>channels-superimposed</code>.
+The following code sets the 'unite' button if the current sound has more than 4 channels:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#afteropenhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_afteropenhook_tip)">after-open-hook</a>
+ (lambda (snd)
+ (if (&gt; (<a class=quiet href="#chans" onmouseout="UnTip()" onmouseover="Tip(extsnd_chans_tip)">channels</a> snd) 4)
+ (set! (<em class=red>channel-style</em> snd) <a class=quiet href="#channelstyle" onmouseout="UnTip()" onmouseover="Tip(extsnd_channelstyle_tip)">channels-combined</a>))))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- channel->vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="channeltovct">channel-&gt;vct</a> (:optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+channel-&gt;vct returns a vct with the specified data. In Ruby, the "-&gt;" in a function name is translated to "2",
+so the function call is:
+<pre> v = channel2vct(0, 100)
+</pre>
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+<A NAME="selection2vct"></a>(define* (selection-&gt;vct :optional snd chn)
+ (if (<a class=quiet href="#selectionmember" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionmember_tip)">selection-member?</a> snd chn)
+ (<em class=red>channel-&gt;vct</em> (<a class=quiet href="#selectionposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionposition_tip)">selection-position</a> snd chn)
+ (<a class=quiet href="#selectionframes" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionframes_tip)">selection-frames</a> snd chn)
+ snd chn)
+ (if (<a class=quiet href="#selectionok" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionok_tip)">selection?</a>)
+ (throw 'no-such-channel
+ (list "selection-&gt;vct"
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "snd ~A channel ~D is not a member of the selection" snd chn)))
+ (throw 'no-active-selection (list "selection-&gt;vct")))))
+</pre></td></tr></table>
+See also mark-explode in marks.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- channels -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="channels">channels</a> (:optional <em class=narg>snd</em>)</code>
+<br><code><a class=def name="chans">chans</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This function returns the number of channels in 'snd'. It can be set, but the result is a new
+version of the underlying sound with the header changed to reflect the new number of channels.
+That is, no new data is created, but the existing data is reapportioned to the new channels:
+<code>(set! (channels) 2)</code>; this is not undo-able (except by calling it again with the
+original number of channels &mdash; the data is not touched).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- clear-minibuffer -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="clearminibuffer">clear-minibuffer</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+This clears the sound's minibuffer area (both the text and the error message widgets).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- clm-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="clmchannel">clm-channel</a> (clm-gen :optional beg dur snd chn edpos overlap origin)</code>
+</td></tr><tr><td></td><td>
+clm-channel applies 'clm-gen' to the given channel starting
+at sample 'beg' for 'dur' samples, and 'overlap' samples of 'ring time'.
+This is used by some of the <a class=quiet href="#regularizedargs" onmouseout="UnTip()" onmouseover="Tip(extsnd_regularizedargs_tip)">regularized</a> functions, but it can also be used directly:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (convolve-channel kernel :optional nbeg ndur nsnd nchn nedpos)
+ (let* ((beg (or nbeg 0))
+ (snd (or nsnd (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (car (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+ (chn (or nchn (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>)))
+ (dur (or ndur (- (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd chn) beg)))
+ (edpos (or nedpos current-edit-position))
+ (reader (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> beg snd chn 1 edpos))
+ (cgen (<a class=quiet href="sndclm.html#make-convolve" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_convolve_tip)">make-convolve</a> :filter kernel
+ :input (lambda (dir)
+ (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> reader)))))
+ (<em class=red>clm-channel</em> cgen beg dur snd chn edpos)
+ (<a class=quiet href="#freesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_freesampler_tip)">free-sampler</a> reader)))
+
+(define (difference) (<em class=red>clm-channel</em> (<a class=quiet href="sndclm.html#make-two-zero" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_two_zero_tip)">make-two-zero</a> 1 -1)))
+(define (wobble) (<em class=red>clm-channel</em> (<a class=quiet href="sndclm.html#make-ncos" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_ncos_tip)">make-ncos</a> 50 3)))
+(define (hold-nose) (<em class=red>clm-channel</em> (<a class=quiet href="sndclm.html#make-ncos" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_ncos_tip)">make-ncos</a> 1 3)))
+(define (bad-reception) (<em class=red>clm-channel</em> (<a class=quiet href="sndclm.html#make-ncos" onmouseout="UnTip()" onmouseover="Tip(sndclm_ncos_tip)">make-ncos</a> 10 5)))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- close-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="closesound">close-sound</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This closes 'snd' (the same as the File:Close menu item). To close all sounds:
+<pre>
+ (close-sound #t)
+ ;; equivalent to:
+ (for-each close-sound (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))
+</pre>
+Before the sound is actually closed, <a class=quiet href="#beforeclosehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_beforeclosehook_tip)">before-close-hook</a>
+is called, then <a class=quiet href="#closehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_closehook_tip)">close-hook</a>,
+then the sound is closed.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- comment -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="comment">comment</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This returns the sound's comment, if any; when a sound is opened, the comment is taken from the file's header
+(the same as <a href="#mussoundcomment">mus-sound-comment</a>). If you set it, the header is not updated until the sound is saved.
+If the new comment is the only change you want to make, you can save the new header via the Edit:Edit Header menu option.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- main-index |convolvewith:convolution reverb -->
+<!-- convolve-with -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="convolvewith">convolve-with</a> (file :optional amp snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+This convolves the given channel (or the currently sync'd data)
+with the data in the sound file 'file'. 'amp' is the resultant
+peak amplitude (leave 'amp' unset, or set it to #f to get the
+unnormalized result).
+Convolve-with in conjunction with mix can provide high-quality reverb:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define conrev
+ (lambda (impulse amp)
+ (<em class=red>convolve-with</em> impulse amp)
+ (<a class=quiet href="#savesoundas" onmouseout="UnTip()" onmouseover="Tip(extsnd_savesoundas_tip)">save-sound-as</a> "reverb.snd") ;let mix scalers set reverb amount
+ (<a class=quiet href="#revertsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_revertsound_tip)">revert-sound</a>)
+ (<em class=red>mix</em> "reverb.snd")))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- count-matches -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="countmatches">count-matches</a> (proc :optional sample snd chn edpos) </code>
+</td></tr><tr><td></td><td>
+This returns how many samples satisfy the function 'proc'; 'proc' should
+take one argument (the current sample value), and return #t for a hit. 'sample'
+determines where to start the search.
+<pre>
+ Scheme: (count-matches (lambda (y) (&gt; y .1)))
+
+ Ruby: count_matches(lambda do |y| y &gt; 0.1 end)
+
+ Forth: lambda: &lt;{ y }&gt; y 0.1 f- f0&lt; ; count-matches
+</pre>
+
+count-matches is modelled after Emacs. It could be defined along these lines:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (count-matches proc)
+ (let ((count 0))
+ (<a class=quiet href="#scanchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_scanchannel_tip)">scan-channel</a>
+ (lambda (y)
+ (if (proc y) (set! count (+ count 1)))
+ #f))
+ count))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- cursor -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="cursor">cursor</a> (:optional <em class=narg>snd chn</em> edpos)</code>
+</td></tr><tr><td></td><td>
+This returns the cursor location (as a sample number; the first sample is numbered 0) in channel 'chn' of 'snd'.
+<code>(set! (cursor) 100)</code> moves the cursor to sample 100. The cursor is somewhat similar to a
+mark in that it moves if you delete or insert samples in front of it.
+
+<!-- INDEX cursorexamples:Cursors -->
+<A NAME="cursorexamples"></a>
+<br>
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<blockquote><small>
+<br>
+Tracking cursor: <a href="#withtrackingcursor">with-tracking-cursor</a> (cursor-follows-play was the old name)<br>
+Change cursor shape or size: <a href="#cursorstyle">cursor-style</a>, <a href="#cursorsize">cursor-size</a><br>
+Cursor moving keys: <a href="snd.html#movecursor">Moving the Cursor</a><br>
+Display data about sample under cursor: <a href="#verbosecursor">verbose cursor</a><br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- cursor-follows-play -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="cursorfollowsplay">cursor-follows-play</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This is #t if the cursor is following along in the sound as it plays. The new name of this variable
+is <a href="#withtrackingcursor">with-tracking-cursor</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- cursor-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="cursorposition">cursor-position</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This gives the current cursor position as a list (x y).
+These graph-relative values can be turned into axis-relative values with
+<a href="#positiontox">position-&gt;x</a> and <a href="#positiontoy">position-&gt;y</a>:
+<pre>
+ (<a class=quiet href="#positiontox" onmouseout="UnTip()" onmouseover="Tip(extsnd_positiontox_tip)">position-&gt;x</a> (car (cursor-position)))
+ ;; equals:
+ (/ (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>))
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- cursor-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="cursorsize">cursor-size</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This gives the cursor size in pixels; it defaults to 15. <code>(set! (cursor-size) 30)</code> makes the cursor twice as big as usual.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- cursor-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="cursorstyle">cursor-style</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+The cursor style is <code>cursor-cross</code>, <code>cursor-line</code>, or a cursor-drawing function.
+The default cursor shape is a "+" sign; the cursor-line is a vertical line.
+As a function, cursor-style is a procedure of three arguments, the
+sound, channel number, and a boolean that is true if the cursor is currently
+tracking playback (a "tracking-cursor").
+The procedure
+should draw the cursor at the current cursor position using the
+<a href="#cursorcontext">cursor-context</a>.
+One example is smart-line-cursor in draw.scm.
+Here is a simpler one that
+replaces the normal "+" cursor with an "x":
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<A NAME="xcursor">x-cursor</a> snd chn ax)
+ (let* ((point (<em class=red>cursor-position</em>))
+ (x (car point))
+ (y (cadr point))
+ (size (inexact-&gt;exact (/ (<em class=red>cursor-size</em>) 2))))
+ (<a class=quiet href="#drawline" onmouseout="UnTip()" onmouseover="Tip(extsnd_drawline_tip)">draw-line</a> (- x size) (- y size) (+ x size) (+ y size) snd chn <em class=red>cursor-context</em>)
+ (<a class=quiet href="#drawline" onmouseout="UnTip()" onmouseover="Tip(extsnd_drawline_tip)">draw-line</a> (- x size) (+ y size) (+ x size) (- y size) snd chn <em class=red>cursor-context</em>)))
+
+(set! (<em class=red>cursor-style</em>) x-cursor)
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- data-format -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="dataformat">data-format</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This returns the sound's data format &mdash; the encoding used for the sound samples (e.g. mus-bshort).
+
+<br><br>
+The standard formats nowadays are <code>mus-bshort</code> (big-endian 16-bit integers), <code>mus-bfloat</code>
+(32-bit big-endian floats), and <code>mus-bint</code> (32-bit big-endian integers), and the
+corresponding little-endian versions: <code>mus-lshort</code>, <code>mus-lfloat</code>, and <code>mus-lint</code>.
+If you're using an Intel-style PC, you're using a little-endian machine;
+Old macs (PowerPC Macs) and Suns use big-endian (NeXT, SGI, and Atari also used it in the good old days). If you
+write a Next file and use little-endian data, some programs other than Snd
+may complain; similarly, RIFF wants little-endian and AIFC wants big-endian
+data (both can handle the other kind, but most sound-related programs don't know
+that). In the old days, when disk space was at a premium, 8-bit formats
+were used a lot: <code>mus-mulaw</code> and <code>mus-alaw</code> (kludges for a kind of 8-bit float),
+<code>mus-byte</code> and <code>mus-ubyte</code> (8-bit ints, unsigned in the latter case). A few
+DACs want a particular kind of data, but Snd handles that conversion internally.
+Anything less than 12 bits will sound bad &mdash; Perry Cook's book "Real Sound Synthesis"
+has examples.
+
+<br><br>
+If you encounter a file
+with an unknown format, or a header that has the wrong format,
+you can set this field to force Snd to interpret the data in any
+way you like. Similar remarks apply to the <a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>, <a class=quiet href="#datalocation" onmouseout="UnTip()" onmouseover="Tip(extsnd_datalocation_tip)">data-location</a>,
+<a class=quiet href="#headertype" onmouseout="UnTip()" onmouseover="Tip(extsnd_headertype_tip)">header-type</a>, and <a class=quiet href="#channels" onmouseout="UnTip()" onmouseover="Tip(extsnd_channels_tip)">channels</a> fields. There are ambiguities in some header
+specifications, usually involving big/little endian or signed/unsigned data confusion.
+If you encounter a sound that is clipping crazily or is just a burst of noise, try changing these settings.
+Some NeXT/Sun (au) header files using byte-wide data
+assume the byte is unsigned, whereas most others assume it is signed. Sndlib
+treats it as signed by default, so to make one of the unsigned-byte files playable,
+<pre>
+ (set! (data-format) <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_dataformat_tip)">mus-ubyte</a>)
+</pre>
+mus_float_t data is another source of confusion;
+there is apparently no agreement on whether the data is between -1.0 and 1.0, or -32768.0 and 32767.0 or anything else.
+In this case, Snd assumes -1.0 to 1.0 (except in one special case involving IRCAM headers), and you may have to
+set <a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a> to see the actual data.
+Yet another gotcha: files with 32-bit integers. Some programs (Glame, apparently, and perhaps Ardour) assume the fraction is
+31 bits wide, others (Snd) use whatever its sample width is configured to be; there is no correct or standard
+placement of the fixed point, but not to worry! Your data is ok:
+<code>(set! (<a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a>) (list -256.0 256.0))</code>. There are several ways you can handle
+these files automatically in Snd. Perhaps the simplest is to use one of the open hooks:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#afteropenhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_afteropenhook_tip)">after-open-hook</a>
+ (lambda (snd)
+ ;; this could also (alternatively) set the y-bounds as above
+ (if (= (<em class=red>data-format</em> snd) mus-lint)
+ (set! (<em class=red>data-format</em> snd) mus-lintn))))
+</pre></td></tr></table>
+
+or (an alternative that sets the underlying database entry, rather than the current in-Snd choice):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#openhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openhook_tip)">open-hook</a>
+ (lambda (name)
+ (if (= (<a class=quiet href="#mussounddataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussounddataformat_tip)">mus-sound-data-format</a> name) mus-lint)
+ (set! (<a class=quiet href="#mussounddataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussounddataformat_tip)">mus-sound-data-format</a> name) mus-lintn))
+ #f))
+</pre></td></tr></table>
+
+If you set any of these fields, the sound's index may change (there can be an embedded <a class=quiet href="#updatesound" onmouseout="UnTip()" onmouseover="Tip(extsnd_updatesound_tip)">update-sound</a>).
+To deal with MPEG, OGG, Flac, or Speex files, see examp.scm (<a class=quiet href="sndscm.html#mpg" onmouseout="UnTip()" onmouseover="Tip(sndscm_mpg_tip)">mpg</a>) or misc.scm (mpg123 and ogg123).
+Octave/WaveLab ASCII files can be translated by read-ascii (examp.scm).
+<br><br>
+To turn a data-format number into a string, use <a href="#musdataformatname">mus-data-format-name</a>. To get
+the data format of some sound file, use <a href="#mussounddataformat">mus-sound-data-format</a>.
+The default output (<a class=quiet href="#newsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_newsound_tip)">new-sound</a>, and
+<a class=quiet href="#savesoundas" onmouseout="UnTip()" onmouseover="Tip(extsnd_savesoundas_tip)">save-sound-as</a>) data-format is <a href="#defaultoutputdataformat">default-output-data-format</a>.
+To change a sound file's data-format, use <a href="#savesoundas">save-sound-as</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- data-location -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="datalocation">data-location</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This gives the location (in bytes) of the sound samples in the file represented by 'snd'. In a raw (headerless) file,
+this is 0, but normally the data comes after some portion of the header.
+To get the data-location of some sound file, use <a href="#mussounddatalocation">mus-sound-data-location</a>.
+If you set this field (you don't want to do this &mdash; it is a law of nature that you will forget the original setting!), the underlying file is immediately rewritten.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- data-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="datasize">data-size</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This gives the size (in bytes) of the sound data in the file represented by 'snd'.
+If you set this field, the underlying file is immediately rewritten (the header is changed; I don't
+think the file is truncated, but no matter what happens, it is not my fault).
+Next/Sun files treat the size field as purely "advisory", so an incorrect data size is often
+ignored in that case.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- delete-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="deletesample">delete-sample</a> (samp :optional snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+This deletes sample 'samp' in the given channel.
+
+<!-- INDEX deletionexamples:Deletions -->
+<A NAME="deletionexamples"></a>
+<br><br>
+<TABLE border=3 bordercolor="tan" hspace=20><tr><td>
+<small><blockquote>
+delete a file: use the Scheme function delete-file, Ruby's File.delete, or Forth's file-delete<br>
+delete a region: <a href="#forgetregion">forget-region</a><br>
+delete the currently selected samples: <a href="#deleteselection">delete-selection</a><br>
+delete the selection and smooth the splice: <a href="sndscm.html#deleteselectionandsmooth">delete-selection-and-smooth</a><br>
+delete a mark or all marks: <a href="#deletemark">delete-mark</a><br>
+delete a colormap: <a href="#deletecolormap">delete-colormap</a><br>
+delete samples: <a href="#deletesamples">delete-samples</a><br>
+remove a file from the sound cache: <a href="#mussoundforget">mus-sound-forget</a><br>
+remove a menu item: <a href="#removefrommenu">remove-from-menu</a> or remove-main-menu in snd-motif.scm<br>
+delete a mix or all mixes: <a href="sndscm.html#silenceallmixes">silence-mixes</a><br>
+add a 'delete' option to the file selection dialog: <a href="sndscm.html#adddeleteoption">add-delete-option</a><br>
+Scheme delete funcs: remove-if assoc-remove! hash-remove! delete-if! delete! string-delete<br>
+<br>
+</blockquote></small>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- delete-samples -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="deletesamples">delete-samples</a> (samp samps :optional snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+This deletes a block of samples. The deleted portion starts at sample 'samp' and runs for 'samps' samples.
+See <a href="#deletetozero">delete-to-zero</a> or delete-selection-and-smooth in extensions.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- dot-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="dotsize">dot-size</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr>
+<tr><td></td><td>
+This gives the size in pixels of dots when graphing with dots (default: 1); this affects <a href="#graphstyle">graph-styles</a> such as <code>graph-lollipops</code>. See <a href="#graphhook">graph-hook</a> or auto-dot in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- env-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="envchannel">env-channel</a> (clm-env-gen :optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+env-channel is the <a class=quiet href="#regularizedargs" onmouseout="UnTip()" onmouseover="Tip(extsnd_regularizedargs_tip)">regularized</a> version of <a href="#envsound">env-sound</a>. 'clm-env-gen'
+can be either a CLM envelope generator or an envelope (a list of breakpoints). <code>(env-channel '(0 0 1 1 2 0))</code>.
+To get .1 seconds of attack and decay:
+<pre>
+ (let ((dur (/ (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>))))
+ (<em class=red>env-channel</em> (list 0 0 .1 1 (- dur .1) 1 dur 0)))
+</pre>
+
+<A NAME="envexamples"></a>
+An envelope in Snd is a list of breakpoints. It can be packaged as a CLM generator (an 'env') via <a href="sndclm.html#make-env">make-env</a>.
+It can be declared via define just like any other variable, or with <a href="#defvar">defvar</a> (for CLM/Snd intercompatibility),
+or with <a href="#defineenvelope">define-envelope</a>.
+<!-- INDEX envexamples:Envelopes -->
+<br><br>
+<TABLE border=3 bordercolor="tan" hspace=20><tr><td>
+<blockquote><small>
+<br>
+envelopes in Snd:<br>
+envelope sound: <a href="#envchannel">env-channel</a>, <a href="#envsound">env-sound</a><br>
+Other enveloping functions: <a href="#rampchannel">ramp-channel</a>, <a href="#xrampchannel">xramp-channel</a>, <a href="#smoothchannel">smooth-channel</a><br>
+The CLM env generator: <a href="sndclm.html#make-env">env</a>, many examples in examp.scm, new-effects.scm, etc<br>
+Various operations on envelopes: <a href="sndscm.html#envdoc">env.scm</a><br>
+Peak env files: <a href="sndscm.html#peakenvdoc">peak-env.scm</a><br>
+The envelope editor: <a href="snd.html#editenvelope">Edit or View and Envelope</a><br>
+Panning: place-sound in examp.scm<br>
+Envelope over mix: <a href="sndscm.html#envelopedmix">enveloped-mix</a><br>
+Local envelope editor: <a href="sndscm.html#enveddoc">enved.scm</a>, xm-enved.scm<br>
+Read sound indexed through envelope: <a href="sndscm.html#envsoundinterp">env-sound-interp</a><br>
+Cosine as envelope: <a href="#cosinechannel">cosine-channel</a>, <a href="#cosinechannelviaptree">cosine-channel-via-ptree</a>, <a href="sndclm.html#bellcurve">bell-curve</a><br>
+envelope with sinusoidal connections between points: <a href="sndscm.html#sineenvchannel">sine-env-channel</a><br>
+envelope with separate base for each segment: <a href="#powenvchannel">powenv-channel</a><br>
+envelope with x^2 connections: <a href="sndscm.html#envsquaredchannel">env-squared-channel</a><br>
+envelope with x^n connections: <a href="sndscm.html#envexptchannel">env-expt-channel</a><br>
+envelope with <a href="sndclm.html#ncos">ncos</a> connections: <a href="sndscm.html#blackman4envchannel">blackman4-env-channel</a><br>
+Customizing the envelope editor: <a href="#envedhook">enved-hook</a><br>
+peak amp follower: <a href="sndclm.html#moving-max">moving-max</a><br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- env-channel-with-base -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="envchannelwithbase">env-channel-with-base</a> (envelope-or-env-gen :optional base beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+env-channel-with-base is a slight variation on env-channel. There are times when it's a bother
+to call <a href="sndclm.html#make-env">make-env</a> just to get an exponential envelope.
+</td></tr>
+<tr><td colspan=2 height=18></td></tr>
+
+<!-- env-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="envsound">env-sound</a> (envelope :optional samp samps env-base snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+env-sound applies the amplitude 'envelope' to the given channel starting
+at sample 'samp' for 'samps' samples with connecting segments
+based on 'env-base'. 'env-base' defaults to 1.0.
+'samp' defaults to 0. 'samps' defaults to the full duration.
+'envelope' is a list containing the breakpoint values
+(as in CLM) or an env generator.
+
+<table hspace=20 cellpadding=5><tr><td>
+<img src="pix/ampenv1.png" alt="ampenvs" vpsace=10>
+</td><td>
+<pre>
+(env-sound '(0 0 1 1 2 0))
+
+env_sound([0.0, 0.0, 1.0, 1.0, 2.0, 0.0])
+
+'( 0.0 0.0 1.0 1.0 2.0 0.0 ) env-sound
+</pre>
+</td><td>
+<img src="pix/ampenv2.png" alt="ampenvs">
+</td></tr></table>
+
+As mentioned in <a href="sndclm.html#make-env">sndclm.html</a>,
+'env-base' determines how the break-points are connected. If it is 1.0 (the
+default), you get straight line segments. 'env-base' = 0.0 gives a step
+function (the envelope changes its value suddenly to the new one without any
+interpolation). Any other positive value becomes the exponent of the exponential curve
+connecting the points. 'env-base' &lt; 1.0 gives convex curves (i.e. bowed
+out), and 'env-base' &gt; 1.0 gives concave curves (i.e. sagging).
+If you'd rather think in terms of e^-kt, set 'env-base' to (exp k).
+See env.lisp for a CLM instrument that shows the relation between the connecting
+curve's exponent and 'env-base'. Here's a brief restatement:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (compare-exp k)
+ (let ((e (<a class=quiet href="sndclm.html#make-env" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_env_tip)">make-env</a> (list 0 1 1 (exp (- k))) :base (exp k) :length 11)))
+ (do ((i 0 (+ 1 i )))
+ ((= i 10))
+ (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~A ~A~%" (<a class=quiet href="sndclm.html#env" onmouseout="UnTip()" onmouseover="Tip(sndclm_env_tip)">env</a> e) (exp (* (- k) (/ i 10.0))))))))
+</pre></td></tr></table>
+
+If 'envelope' is a CLM env generator, 'env-base'
+is ignored.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- fft-log-frequency -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fftlogfrequency">fft-log-frequency</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This returns whether the spectrum frequency axis is logarithmic (#t) or linear (#f, the default). If logarithmic, the lower end
+is set by <a href="#logfreqstart">log-freq-start</a> which defaults to 32Hz.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- fft-log-magnitude -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fftlogmagnitude">fft-log-magnitude</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This returns whether the spectrum magnitude axis is in decibels (#t) or linear (#f, the default). If in decibels, the
+minimum displayed is set by <a href="#mindb">min-dB</a> which defaults to -60.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- fft-window -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fftwindow">fft-window</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This sets the choice of fft data window (default: <code>blackman2-window</code>)
+<pre>
+ bartlett-hann-window bartlett-window blackman2-window blackman3-window
+ blackman4-window bohman-window cauchy-window connes-window
+ dolph-chebyshev-window exponential-window flat-top-window gaussian-window
+ hamming-window hann-poisson-window hann-window kaiser-window
+ parzen-window poisson-window rectangular-window riemann-window
+ samaraki-window tukey-window ultraspherical-window welch-window
+ blackman5-window blackman6-window blackman7-window blackman8-window
+ blackman9-window blackman10-window rv2-window rv3-window
+ rv4-window mlt-sine-window papoulis-window dpss-window
+ sinc-window
+</pre>
+<p>The Hann window is sometimes called Hanning in the DSP literature, apparently
+as an in-joke. For an extensive discussion of these windows, see
+Fredric J. Harris, "On the Use of Windows for Harmonic Analysis with the Discrete Fourier Transform", Proceedings of the
+IEEE, Vol. 66, No. 1, January 1978, with updates from: Albert H. Nuttall, "Some Windows with Very Good Sidelobe Behaviour", IEEE Transactions
+of Acoustics, Speech, and Signal Processing, Vol. ASSP-29, 1, February 1981, and of course, Julius Smith's DSP web site.
+</p>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- fft-window-alpha -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fftalpha">fft-window-alpha</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+The ultraspherical window has two "family" parameters; the one named "mu" is called "beta" here,
+to parallel its use in related windows; the other one, named "x<sub>mu</sub>" is named "alpha" here,
+for no good reason. fft-window-alpha sets the shape of the side lobes; see
+"Design of Ultraspherical Window Functions with Prescribed Spectral Characteristics", Bergen and Antoniou, EURASIP JASP 2004
+(also available on-line) for details.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- fft-window-beta -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fftbeta">fft-window-beta</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+Some fft windows have a parameter, often named alpha or beta, that chooses one from a family of possible windows.
+The actual (underlying) beta values are dependent on the window choice, but
+in Snd, fft-window-beta is scaled to fit the current window's range of values, so
+its value here should fall between 0.0 and 1.0.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- fft-with-phases -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fftwithphases">fft-with-phases</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This returns whether the single FFT display includes phase information (the default is #f).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- file-name -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filename">file-name</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This returns the sound's complete (or "absolute") file name; the directory is included; see <a href="#shortfilename">short-file-name</a>
+if you don't want all the directory junk. See examp.scm for many examples.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- filter-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filterchannel">filter-channel</a> (env :optional order beg dur snd chn edpos trunc origin)</code>
+</td></tr><tr><td></td><td>
+The regularized version of filter-sound. If the end of the filtered portion is not the end of the sound,
+the 'trunc' argument determines whether the filtered sound is truncated at that point (the default: #t),
+or mixed with the overlapping section, similar to the truncate argument to <a href="#filterselection">filter-selection</a>.
+'env' can be either the frequency response envelope, or a vct containing the desired coefficients.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- filter-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filtersound">filter-sound</a> (env :optional order snd chn edpos origin)</code>
+</td></tr><tr><td></td><td>
+filter-sound applies an FIR filter of order 'order' (actually one more than the nominal order)
+and frequency response 'env'
+to the given channel. 'env' can also be a vct containing the filter coefficients,
+or any CLM filtering generator
+(e.g. comb, formant, one-pole, iir-filter, etc). The generator
+is called in C, not Scheme, so this is the fastest way to apply
+CLM filtering to a sound. See also <a href="#clmchannel">clm-channel</a>.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>filter-sound</em> '(0 1 1 0) 1024) ; FIR filter given frequency response
+(<em class=red>filter-sound</em> (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> .1 .2 .3 .3 .2 .1) 6) ; FIR filter given actual coefficients
+(<em class=red>filter-sound</em> (<a class=quiet href="sndclm.html#make-fir-filter" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_fir_filter_tip)">make-fir-filter</a> 6 (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> .1 .2 .3 .3 .2 .1))) ; CLM FIR filter
+(<em class=red>filter-sound</em> (<a class=quiet href="sndclm.html#make-delay" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_delay_tip)">make-delay</a> 120)) ; CLM delay (same as insert-silence)
+(<em class=red>filter-sound</em> (<a class=quiet href="sndclm.html#make-formant" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_formant_tip)">make-formant</a> 1200 .99)) ; CLM formant
+(<em class=red>filter-sound</em> (<a class=quiet href="sndclm.html#make-filter" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_filter_tip)">make-filter</a> 2 (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> 1 -1) (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> 0 -0.99))) ; remove DC
+</pre></td></tr></table>
+
+If you want to use the cascade filter structure, rather than the canonical
+form of CLM's filter generator:
+
+<pre>
+ (define (<a class=quiet href="sndscm.html#makebiquad" onmouseout="UnTip()" onmouseover="Tip(sndscm_makebiquad_tip)">make-biquad</a> a0 a1 a2 b1 b2)
+ (<a class=quiet href="sndclm.html#make-filter" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_filter_tip)">make-filter</a> 3 (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> a0 a1 a2) (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> 0.0 b1 b2)))
+</pre>
+
+If you have coefficients for the cascade form, but have no scruples about using
+some other form, see cascade-&gt;canonical in dsp.scm, and the examples that follow.
+<br><br>
+
+<!-- INDEX filtersinsnd:Filters -->
+<TABLE border=3 bordercolor="tan" hspace=20>
+<tr><td>
+<blockquote><small>
+<br>
+<A NAME="filtersinsnd">Filters</a> in Snd:<br>
+filter a sound: <a href="#filtersound">filter-sound</a>, <a href="#filterchannel">filter-channel</a>, and <a href="#clmchannel">clm-channel</a><br>
+filter the selection: <a href="#filterselection">filter-selection</a>, <a href="sndscm.html#filterselectionandsmooth">filter-selection-and-smooth</a><br>
+CLM filter generators: <a href="sndclm.html#filterdoc">filter, one-pole, formant, comb, notch, all-pass, etc</a><br>
+lowpass filter: <a href="sndscm.html#makelowpass">make-lowpass</a> in dsp.scm<br>
+highpass filter: <a href="sndscm.html#makehighpass">make-highpass</a> in dsp.scm<br>
+bandpass filter: <a href="sndscm.html#makebandpass">make-bandpass</a> in dsp.scm<br>
+bandstop filter: <a href="sndscm.html#makebandstop">make-bandstop</a> in dsp.scm<br>
+the usual analog filters (Butterworth, Chebyshev, Bessel, Elliptic): <a href="sndscm.html#analogfilterdoc">analog-filter.scm</a><br>
+Butterworth filters: <a href="sndscm.html#makebutter">make-butter-high-pass</a>, make-butter-low etc in dsp.scm, used in new-effects.scm<br>
+IIR filters of various orders/kinds: <a href="sndscm.html#IIRfilters">dsp.scm</a><br>
+Hilbert transform: <a href="sndscm.html#makehilberttransform">make-hilbert-transform</a> in dsp.scm<br>
+differentiator: <a href="sndscm.html#makedifferentiator">make-differentiator</a> in dsp.scm<br>
+block DC: see example above, dc-block in prc95.scm, clean-channel in clean.scm, or stereo-flute in clm-ins.scm<br>
+hum elimination: see <a href="sndscm.html#IIRfilters">eliminate-hum</a> and <a href="sndscm.html#notchchannel">notch-channel</a> in dsp.scm<br>
+hiss elimination: <a href="sndscm.html#notchoutrumbleandhiss">notch-out-rumble-and-hiss</a><br>
+smoothing filters: <a href="sndclm.html#moving-average">moving-average</a>, <a href="sndclm.html#weighted-moving-average">weighted-moving-average</a>, exponentially-weighted-moving-average<br>
+notch-filters: <a href="sndscm.html#notchchannel">notch-channel</a> and <a href="sndscm.html#notchselection">notch-selection</a><br>
+arbitrary spectrum via FIR filter: <a href="sndscm.html#spectrumtocoeffs">spectrum-&gt;coeffs</a> in dsp.scm<br>
+invert an FIR filter: <a href="sndscm.html#invertfilter">invert-filter</a> in dsp.scm<br>
+filtered echo sound effect: <a href="sndscm.html#zecho">flecho</a> in examp.scm<br>
+time varying filter: fltit in examp.scm<br>
+draw frequency response: use <a href="snd.html#editenvelope">envelope editor</a> or <a href="snd.html#filtercontrol">filter control</a> in control panel<br>
+Moog filter: <a href="sndscm.html#moogdoc">moog.scm</a><br>
+Savitzky-Golay filter: <a href="sndscm.html#sgfilter">savitzky-golay-filter</a><br>
+Click reduction: <a href="sndscm.html#removeclicks">remove-clicks</a>, <a href="sndscm.html#cleanchannel">clean-channel</a><br>
+FIR filter as virtual edit: <a href="sndscm.html#virtualfilterchannel">virtual-filter-channel</a><br>
+LADSPA-based filter effects: see ladspa.scm<br>
+Max Mathews resonator: <a href="sndclm.html#firmant">firmant</a>, <a href="sndscm.html#maxfdoc">maxf.scm, maxf.rb</a><br>
+Spectral edit dialog: <a href="snd.html#editenvelope">Envelope Editor</a><br>
+graphical equalizer filter bank: <a href="sndscm.html#clminsdoc">graphEq</a><br>
+nonlinear (Volterra) filter: <a href="sndscm.html#volterrafilter">volterra-filter</a><br>
+Kalman filter: <a href="sndscm.html#kalmanfilterchannel">kalman-filter-channel</a><br>
+see also convolution, physical modeling, reverb, and <a href="sndscm.html#ssffts">fft-based filtering</a><br>
+Scheme srfi-1 filter function: %filter.<br>
+<br>
+</small></blockquote>
+</td></tr>
+</TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- find-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="findchannel">find-channel</a> (proc :optional sample snd chn edpos) </code>
+</td></tr><tr><td></td><td>
+This function finds the sample that satisfies the function 'proc'. 'sample'
+determines where to start the search.
+If 'proc' returns some non-#f value, find-channel returns a list with that value (if optimization is off) and the sample number.
+In the find dialog and in C-s or C-r searches, if the value returned is an integer, the cursor is offset by that number of samples.
+
+<pre>
+&gt;<em class=typing>(find-channel (lambda (y) (&gt; y .1)))</em>
+<em class=listener>(#t 4423)</em>
+
+&gt;<em class=typing>(find-channel (lambda (y) (and (&gt; y .1) 'a-big-sample)))</em>
+<em class=listener>(a-big-sample 4423)</em> ; if optimization is on, this will be (#t 4423)
+
+&gt;<em class=typing>lambda: &lt;{ y }&gt; 0.1 y f&lt; ; find-channel</em>
+<em class=listener>'( #t 4423 )</em>
+</pre>
+
+I didn't bring out the search direction (find-channel is built on scan-channel which assumes it is
+scanning forwards), but it's not hard to write a function to find in reverse:
+
+<pre>
+(define* (<A NAME="findchannelinreverse">find-channel-in-reverse</A> proc :optional beg snd chn edpos)
+ (let* ((sample (or beg (- (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd chn) 1))) ; or cursor?
+ (reader (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> sample snd chn -1 edpos))
+ (result #f))
+ (do ((i sample (- i 1)))
+ ((or result (&lt; i 0))
+ (and result
+ (list result (+ 1 i))))
+ (set! result (proc (reader))))))
+</pre>
+
+
+<!-- INDEX searchexamples:Searching -->
+<A NAME="searchexamples"></a>
+
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<blockquote><small>
+<br>
+find a mark: <a href="#findmark">find-mark</a><br>
+find a mix: <a href="sndscm.html#findmix">find-mix</a><br>
+find a sound: <a href="#findsound">find-sound</a><br>
+Example find procedures: <a href="sndscm.html#searchforclick">search-for-click, zero+, next-peak, find-pitch</a><br>
+Search via continuation: <a href="#scanagain">scan-again</a><br>
+Explicit access to search procedures: <a href="#searchprocedure">search-procedure</a><br>
+The Find dialog: <a href="snd.html#editoperations">Find</a> or <a href="#finddialog">find-dialog</a><br>
+find silence: <a href="#mapsilence">map-silence</a>, scramble-channel in examp.scm<br>
+find zero crossing: <a href="#newcp">find-zero</a><br>
+find any difference between two chans: <a href="sndscm.html#channelsequal">channels-equal</a><br>
+see also <a href="#countmatches">count-matches</a> and <a href="#scanchannel">scan-channel</a><br>
+search a multichannel sound: <a href="sndscm.html#scansound">scan-sound</a><br>
+find a widget: find-child in snd-motif.scm<br>
+add C-s and C-r to the listener key bindings: add-find-to-listener in snd-motif.scm<br>
+Scheme find: find-if<br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- find-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="findsound">find-sound</a> (filename :optional nth)</code>
+</td></tr><tr><td></td><td>
+find-sound returns the sound object of 'filename' or
+#f if no sound is found that matches 'filename'. If there is (or might be) more than one file
+open with the given filename, the 'nth' parameter (which defaults to 0) chooses which to return.
+Leaving aside the 'nth' parameter, find-sound could be defined as:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (find-sound name)
+ (call-with-current-continuation
+ (lambda (return)
+ (for-each
+ (lambda (snd)
+ (if (or (string=? (<a class=quiet href="#shortfilename" onmouseout="UnTip()" onmouseover="Tip(extsnd_shortfilename_tip)">short-file-name</a> snd) name)
+ (string=? (<a class=quiet href="#filename" onmouseout="UnTip()" onmouseover="Tip(extsnd_filename_tip)">file-name</a> snd) name))
+ (return snd)))
+ (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))
+ #f)))
+</pre></td></tr></table>
+
+See popup.scm, and files-popup-buffer, open-next-file-in-directory, and the "Buffer Menu" code in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- finish-progress-report -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="finishprogressreport">finish-progress-report</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This ends an on-going progress report (a visual indication of how far along some time-consuming process is).
+See <a href="#progressreport">progress-report</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- frames -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="frames">frames</a> (:optional <em class=narg>snd chn</em> edpos)</code>
+</td></tr><tr><td></td><td>
+This returns current length in samples of the channel 'chn'. Used with set!, this either truncates
+the sound or pads it with zeros at the end.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- free-player -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="freeplayer">free-player</a> (player)</code>
+</td></tr><tr><td></td><td>
+free-player frees all resources associated with 'player' and remove it from the play-list.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- graph -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="graph">graph</a> (data :optional xlabel x0 x1 y0 y1 snd chn force-display show-axes-choice)</code>
+</td></tr><tr><td></td><td>
+This function displays a graph of 'data' in a separate display per channel. The x axis
+is labelled 'xlabel', the x axis units go from 'x0' to 'x1' (the default is 0.0 to 1.0),
+the y axis goes from 'y0' to 'y1' (the default fits the data), and the display is
+associated with channel 'chn' in 'snd'.
+<pre>
+ (graph (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> 0 .1 .2 .3 .4 .3 .2 .1 0) "roof")
+</pre>
+The current slider values can be read from <a href="#xpositionslider">x-position-slider</a>,
+<a href="#xzoomslider">x-zoom-slider</a>, etc. The 'data' argument can be a list of vcts; each is graphed at the same time, following the sequence of
+colors used when channels are superimposed. If 'data'
+is a list of numbers, it is assumed to be an envelope (a list of breakpoints).
+If 'force-display' is #f (the default is #t), the graph is not
+explicitly drawn; this is useful when you're calling graph from
+the lisp-graph-hook, where the redisplay is automatic.
+'show-axes-choice' sets the <a href="#showaxes">show-axes</a> choice for the lisp graph.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define <A NAME="xdisplayenergy">display-energy</A>
+ ;; y-zoom-slider controls the graph amp
+ (lambda (snd chn)
+ "display time domain data as energy"
+ (let* ((ls (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a>))
+ (rs (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a>))
+ (datal (<a class=quiet href="#makegraphdata" onmouseout="UnTip()" onmouseover="Tip(extsnd_makegraphdata_tip)">make-graph-data</a> snd chn))
+ (data (if (<a class=quiet href="#vctp" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctp_tip)">vct?</a> datal) datal (cadr datal)))
+ (len (length data))
+ (sr (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> snd))
+ (y-max (<a class=quiet href="#yzoomslider" onmouseout="UnTip()" onmouseover="Tip(extsnd_yzoomslider_tip)">y-zoom-slider</a> snd chn)))
+ (<a class=quiet href="#vctmultiply" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctmultiply_tip)">vct-multiply!</a> data data)
+ (<em class=red>graph</em> data "energy" (/ ls sr) (/ rs sr) 0.0 (* y-max y-max) snd chn #f))))
+
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a href="#lispgraphhook">lisp-graph-hook</a> display-energy)
+</pre></td></tr></table>
+<img src="pix/energy.png" alt="picture of examp.scm in action">
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- graph-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="graphstyle">graph-style</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+graph-style determines how sound data is displayed (default: <code>graph-lines</code>).
+The choices are:
+<pre>
+ graph-lines graph-dots graph-filled graph-lollipops graph-dots-and-lines
+</pre>
+In the set! case, if no 'snd' is specified, all graph-styles are set to the
+new value. If 'snd' is given, the three graph styles for that sound's channels (or channel 'chn') are
+set. See <a href="#timegraphstyle">time-graph-style</a>, <a href="#lispgraphstyle">lisp-graph-style</a>, and
+<a href="#transformgraphstyle">transform-graph-style</a> to override the default for a specific graph.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- graphs-horizontal -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="graphshorizontal">graphs-horizontal</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This determines whether channel graphs (the time domain, spectrum, and lisp graphs)
+are arranged
+<A class=quiet onmouseout="UnTip()" onmouseover="Tip('<img src=\'pix/bgd.png\' width=\'540\' height=\'360\'>', TITLE, '<code>(set! (graphs-horizontal) #f)</code>', ABOVE, true)">vertically</A>
+or horizontally (the latter is the default).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- grid-density -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="griddensity">grid-density</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This controls the spacing of axis ticks; the default is 1.0. If grid-density is less than 1.0, more ticks are squeezed
+in; if greater than 1.0, fewer ticks are displayed. This mainly affects the grid display
+(<a href="#showgrid">show-grid</a>).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- header-type -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="headertype">header-type</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This returns the header type (e.g. <code>mus-aiff</code>) of the file that underlies 'snd'.
+Snd can read about 60 header types, and write 7 or so.
+"aiff" and "aifc" come from Apple, "riff" is the Microsoft "wave" header,
+"rf64" is the European Broadcast Union's 64-bit RIFF replacement,
+"nist" comes from the NIST-Sphere package, "next" or "sun" is the Next/Sun
+(".au") header, "ircam" is IRCAM's extension of the Next header,
+"caf" is Apple's 64-bit AIFC replacement,
+and "raw"
+means the sound file has no header. If you change the header type to "raw",
+any existing header is removed.
+Each header type has its own peculiarities; if in doubt, use <code>mus-next</code> because it is simple,
+and can handle any data format that Snd can write (whereas each of the others is restricted in this regard).
+The writable header types are <code>mus-next</code>, <code>mus-nist</code>,
+<code>mus-aiff</code> (obsolete, rarely needed), <code>mus-aifc</code>, <code>mus-riff</code>, <code>mus-rf64</code>, <code>mus-caff</code>,
+<code>mus-ircam</code>, and <code>mus-raw</code> (no header). For technical descriptions of the headers,
+see headers.c; for actual sound files, see sf.tar.gz at ccrma-ftp.
+<br><br>
+To turn a header type number into a string, use <a href="#musheadertypename">mus-header-type-name</a>. To get
+the header type of some sound file, use <a href="#mussoundheadertype">mus-sound-header-type</a>.
+If you set the header-type, the sound file is rewritten with the new header. The default output
+(<a class=quiet href="#newsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_newsound_tip)">new-sound</a>, and
+<a class=quiet href="#savesoundas" onmouseout="UnTip()" onmouseover="Tip(extsnd_savesoundas_tip)">save-sound-as</a>) header type is <a href="#defaultoutputheadertype">default-output-header-type</a>.
+<br><br>
+To read or write your own headers (or some header that isn't built-in),
+I recommend using either <a href="#openhook">open-hook</a> or <a href="#openrawsoundhook">open-raw-sound-hook</a>:
+in the latter case, when you open the file with the unsupported header,
+Snd will throw up its hands and say "maybe it's a raw (headerless)
+sound"; it will then look at open-raw-sound-hook before trying
+other fallbacks (such as the Raw File Dialog).
+See examp.scm or misc.scm (MPEG, OGG, etc).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- insert-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="insertsample">insert-sample</a> (samp value :optional snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+This inserts sample 'value' at sample 'samp' in the given channel
+
+<!-- INDEX insertionexamples:Insertions -->
+<A NAME="insertionexamples"></a>
+
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<small><blockquote>
+insert some portion of a channel: <a href="sndscm.html#insertchannel">insert-channel</a><br>
+insert a silence: <a href="#padchannel">pad-channel</a>, <a href="#insertsilence">insert-silence</a>, <a href="sndscm.html#padsound">pad-sound</a><br>
+insert a region: <a href="#insertregion">insert-region</a><br>
+insert the selection: <a href="#insertselection">insert-selection</a><br>
+insert a vct of samples: <a href="#insertsamples">insert-samples</a>, <a href="sndscm.html#insertvct">insert-vct</a><br>
+insert a sound: <a href="#insertsound">insert-sound</a> or <a href="#insertfiledialog">insert-file-dialog</a><br>
+append a sound and silence: <a href="#appendsound">append-sound</a><br>
+insert a frame: <a href="sndscm.html#insertframe">insert-frame</a><br>
+insert sound-data: <a href="sndscm.html#insertsounddata">insert-sound-data</a><br>
+</blockquote></small>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- insert-samples -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="insertsamples">insert-samples</a> (samp samps data :optional snd chn edpos auto-delete origin)</code>
+</td></tr><tr><td></td><td>
+This inserts 'samps' samples of 'data' (normally a vct) starting at sample 'samp' in the given channel.
+'data' can be a filename.
+The regularized version of this is:<br>
+<pre>
+ (define* (<a class=quiet href="sndscm.html#insertchannel" onmouseout="UnTip()" onmouseover="Tip(sndscm_insertchannel_tip)">insert-channel</a> data :optional beg dur snd chn edpos)
+ (insert-samples beg dur data snd chn edpos))
+</pre>
+To insert a block of samples of a given value: <code>(insert-samples beg dur (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> dur val))</code>
+If 'data' is a file, it is not deleted by Snd unless 'auto-delete' is #t.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- insert-silence -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="insertsilence">insert-silence</a> (beg num :optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This inserts 'num' zeros at 'beg' in the given channel. <a href="#padchannel">pad-channel</a> is the regularized version,
+with one small change: insert-silence forces 'beg' to be within the current sound, but pad-channel pads out to 'beg' if
+'beg' is past the end of the sound. (And, as usual in these cases, insert-silence follows the <a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a>
+field, whereas <a class=quiet href="#padchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_padchannel_tip)">pad-channel</a> ignores it).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- insert-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="insertsound">insert-sound</a> (file :optional beg in-chan snd chn edpos auto-delete)</code>
+</td></tr><tr><td></td><td>
+This inserts channel 'in-chan' of 'file' at sample 'beg' in the given channel.
+'beg' defaults to the cursor position; if 'in-chan' is not given, all
+channels are inserted. To append one sound to another, padding at the end with some silence:
+<pre>
+ (define* (<a name="appendsound">append-sound</a> file :optional (silence 1.0))
+ (<em class=red>insert-sound</em> file (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>))
+ (<em class=red>insert-silence</em> (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>) (inexact-&gt;exact (round (* (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>) silence)))))
+</pre>
+'file' is not deleted by Snd unless 'auto-delete' is #t.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- integer->sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="integertosound">integer-&gt;sound</a> (i)</code>
+</td></tr><tr><td></td><td>
+In olden times, a sound was handled in Snd code as an integer; nowadays, it's an object (although the integer approach still works).
+This function, and its companion <a href="#soundtointeger">sound-&gt;integer</a>, exist mainly to convert
+old code to the current style.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- left-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="leftsample">left-sample</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This returns the position in samples of the left edge of the time domain
+waveform for the given channel.
+To get the data currently displayed in the time domain window:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<a class=quiet href="sndscm.html#windowsamples" onmouseout="UnTip()" onmouseover="Tip(sndscm_windowsamples_tip)">window-samples</a>)
+ (let ((wl (<em class=red>left-sample</em>))
+ (wr (<a href="#rightsample">right-sample</a>)))
+ (<a href="#samples">samples</a> wl (+ 1 (- wr wl)))))
+</pre></td></tr></table>
+
+See also <a href="#moveonepixel">move-one-pixel</a>.
+
+<!-- INDEX movingwindows:Window size and position -->
+<A NAME="movingwindows"></a>
+
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<blockquote><small>
+<br>
+time domain window:<br>
+Built-in keyboard commands: <a href="snd.html#movewindow">Moving the Window</a><br>
+Specialized keyboard commands: <a href="#bindkey">bind-key</a><br>
+Window size: <a href="#xzoomslider">x-zoom-slider</a>, <a href="#zoomonepixel">zoom-one-pixel</a>, <br>
+Window position: <a href="#xpositionslider">x-position-slider</a>, <a href="#moveonepixel">move-one-pixel</a><br>
+Window left edge: <a href="#leftsample">left-sample</a><br>
+Window right edge: <a href="#rightsample">right-sample</a><br>
+<br>
+fft window:<br>
+window size: drag x axis, <a href="#spectrumend">spectrum-end</a><br>
+window start: <a href="#spectrumstart">spectrum-start</a><br>
+relation to time domain: <a href="#beforetransformhook">before-transform-hook</a><br>
+selection fft: <a href="#showselectiontransform">show-selection-transform</a><br>
+<br>
+general info:<br>
+Axis description: <a href="#axisinfo">axis-info</a><br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- lisp-graph? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="lispgraphp">lisp-graph?</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+lisp-graph? returns #t if the lisp-generated graph is currently displayed ("lisp" here means any extension language).
+The lisp graph section is also active if there's a drawing function
+on the <a href="#lispgraphhook">lisp-graph-hook</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- lisp-graph-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="lispgraphstyle">lisp-graph-style</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This determines how lisp-generated data is displayed.
+The choices are:
+<pre>
+ graph-lines graph-dots graph-filled graph-lollipops graph-dots-and-lines
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- make-player -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="makeplayer">make-player</a> (snd chn)</code>
+</td></tr><tr><td></td><td>
+This function makes a new player associated with the given channel.
+A player is a sort of wrapper for a channel of a sound that supports
+all the control-panel functions. Once created, you can set these
+fields, then call <a href="#addplayer">add-player</a> to add this channel to the list of
+channels either being played (if a play is in progress) or about
+to be played. Once some player is in the play-list, you can start
+the play with <a href="#startplaying">start-playing</a>, and stop it prematurely with either
+<a href="#stopplayer">stop-player</a> or <a href="#stopplaying">stop-playing</a>. These functions make it possible
+to build custom control panels. Here's an example that plays a
+sound with individual amplitudes for the channels:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define play-with-amps
+ (lambda (sound . amps)
+ (let ((chans (<a class=quiet href="#chans" onmouseout="UnTip()" onmouseover="Tip(extsnd_chans_tip)">channels</a> sound)))
+ (do ((chan 0 (+ 1 chan)))
+ ((= chan chans))
+ (let ((player (<em class=red>make-player</em> sound chan)))
+ (set! (<a class=quiet href="#ampcontrol" onmouseout="UnTip()" onmouseover="Tip(extsnd_ampcontrol_tip)">amp-control</a> player) (list-ref amps chan))
+ (<em class=red>add-player</em> player)))
+ (<em class=red>start-playing</em> chans (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> sound)))))
+
+(play-with-amps 0 1.0 0.5) ;plays channel 2 of stereo sound at half amplitude
+</pre></td></tr></table>
+</td></tr>
+
+<tr><td></td><td>
+See play-with-envs in enved.scm,
+play-syncd-marks in marks.scm, start-dac in play.scm,
+and add-amp-controls in <a href="sndscm.html#sndmotifdoc">snd-motif.scm</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- make-variable-graph -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="makevariablegraph">make-variable-graph</a> (container :optional name length srate)</code>
+</td></tr><tr><td></td><td>
+make-variable-graph is a part of the <a href="sndscm.html#variabledisplay" onmouseout="UnTip()" onmouseover="Tip('<img src=\'pix/vardpy.png\' width=\'250\' height=\'250\'>', TITLE, 'make-variable-display in snd-motif', ABOVE, true)">variable-display</a> mechanism in snd-motif.scm. It creates the
+sound/channel pair that displays a graph or spectrum of the arbitrary data accessed via <a href="#channeldata">channel-data</a>.
+See oscope.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- map-chan -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>map-chan</a> (func :optional start end edname snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+map-chan applies 'func' to samples in the specified channel.
+It is the old ("irregular") version of <a href="#mapchannel">map-channel</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- map-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="mapchannel">map-channel</a> (func :optional beg dur snd chn edpos origin)</code>
+</td></tr><tr><td></td><td>
+map-channel is one of the standard ways to change a sound. It applies 'func' to each sample
+replacing the current value with whatever 'func' returns.
+As usual, 'beg' defaults to 0, 'dur' defaults to the full length of the sound,
+'snd' and 'chn' default to the currently selected sound, and 'edpos' to the
+current edit history list position. 'origin' is the edit history name of the current
+operation.
+<br><br>
+'func', a procedure of one argument (the current sample),
+can return #f, which means that the data passed in is
+deleted (replaced by nothing), or a number which replaces the
+current sample,
+or #t which halts the mapping operation, leaving trailing samples
+unaffected, or a vct
+the contents of which are spliced into the edited version, effectively
+replacing the current sample with any number of samples. This sounds
+more complicated than it is! Basically, a map-channel function receives
+each sample and returns either #f (no corresponding output), a number
+(the new output), or a bunch of numbers.
+If every value returned for a given channel is #f, the data is not edited.
+Here we add 0.2 to every sample in a channel:
+<br>
+
+<pre>
+Scheme:
+ &gt;<em class=typing>(map-channel (lambda (y) (+ y 0.2)))</em>
+ <em class=listener>0</em>
+
+Ruby:
+ &gt;<em class=typing>map_channel(lambda do |y| y + 0.2 end)</em>
+ <em class=listener>-0.0015869140625</em>
+
+Forth:
+ &gt;<em class=typing>lambda: &lt;{ y }&gt; y 0.2 f+ ; map-channel</em>
+ <em class=listener>-0.00158691</em>
+</pre>
+
+<p>
+In the next sequence, we replace a sound by the difference between successive
+samples (a high-pass effect), then undo that by adding them back together,
+then check to see how close our reconstruction is to the original:
+</p>
+
+<pre>
+<em class=listener>&gt;</em> <em class=typing>(let ((y0 0.0)) (map-channel (lambda (y) (let ((diff (- y y0))) (set! y0 y) diff))))</em>
+<em class=listener>0</em>
+<em class=listener>&gt;</em> <em class=typing>(let ((y0 0.0)) (map-channel (lambda (y) (let ((add (+ y y0))) (set! y0 add) add))))</em>
+<em class=listener>0</em>
+<em class=listener>&gt;</em> <em class=typing>(let ((rd (make-sampler 0 0 0 1 0))) (map-channel (lambda (y) (- y (rd)))))</em>
+<em class=listener>0</em> ; the sampler is reading the unedited form of the sound
+<em class=listener>&gt;</em> <em class=typing>(maxamp)</em> ; i.e. how big is the biggest difference
+<em class=listener>0.0</em>
+</pre>
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<A NAME="cosinechannel">cosine-channel</a> :optional (beg 0) dur snd chn edpos)
+ (<em class=red>map-channel</em>
+ (let* ((samps (or dur (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd chn)))
+ (incr (/ pi samps))
+ (angle (* -0.5 pi)))
+ (lambda (y)
+ (let ((val (* y (cos angle))))
+ (set! angle (+ angle incr))
+ val)))
+ beg dur snd chn edpos))
+</pre></td></tr></table>
+
+Here's a slightly more involved example;
+we define a function that finds silent portions and replaces them with
+something:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<A NAME="mapsilence">map-silence</a> in-silence replacement)
+ (let ((buffer (<a class=quiet href="sndclm.html#make-moving-average" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_moving_average_tip)">make-moving-average</a> 128))
+ (silence (/ in-silence 128)))
+ (lambda (y)
+ (let ((sum-of-squares (<a class=quiet href="sndclm.html#moving-average" onmouseout="UnTip()" onmouseover="Tip(sndclm_moving_average_tip)">moving-average</a> buffer (* y y))))
+ (if (&gt; sum-of-squares silence) y replacement)))))
+
+(<em class=red>map-channel</em> (map-silence .01 0.0)) ; squelch background noise
+(<em class=red>map-channel</em> (map-silence .001 #f)) ; remove silences altogether
+</pre></td></tr></table>
+
+Here we're using 'buffer', a CLM <a href="sndclm.html#moving-average">moving-average</a> generator, to track the
+RMS value of the last 128 input samples.
+When that falls below
+the argument 'silence', we replace the current sample with 'replacement'.
+It may be easier in complex cases to use with-sound rather than map-channel.
+See <a href="#setsamples">step-src</a> for example.
+<br><br>
+It is possible to break out of a map, flushing any edits, via call-with-current-continuation:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define ctr 0)
+(call-with-current-continuation
+ (lambda (return)
+ (<em class=red>map-channel</em> (lambda (val)
+ (set! ctr (+ 1 ctr))
+ (if (&gt; ctr 100)
+ (return "quitting!")
+ val)))))
+</pre></td></tr></table>
+
+It is also possible to stop, then continue map-channel:
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define go-on #f)
+(<em class=red>map-channel</em> (lambda (y)
+ (call-with-current-continuation
+ (lambda (stop)
+ (if (&gt; y 1.0)
+ (begin
+ (set! go-on stop)
+ (throw 'oops)))))
+ .2))
+</pre></td></tr></table>
+
+If this hits a sample &gt; 1.0, it will print 'oops and put the continuation in the variable 'go-on'.
+<code>(go-on)</code> will continue where you left off. (I'm not sure how far this can be pushed, or
+whether it's a good idea &mdash; you may end up with unclosed files and so on).
+<br><br>
+If the editing action is not mapping something over the current sound, it is
+safest to write a temp file with the new data, then pass that to set-samples
+with the 'trunc' argument set to #t. This way you don't assume the new sound
+will fit in memory (as in using <a class=quiet href="#vcttochannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_vcttochannel_tip)">vct-&gt;channel</a> for example).
+Use <a href="#sndtempnam">snd-tempnam</a> to get a temporary filename that reflects the current
+temp-dir setting. The env-sound-interp function in <a href="sndscm.html#envsoundinterp">examp.scm</a>
+is an example of this.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (map-sound-chans proc :optional (beg 0) dur snd edpos origin)
+ (do ((i 0 (+ 1 i)))
+ ((= i (<a class=quiet href="#chans" onmouseout="UnTip()" onmouseover="Tip(extsnd_chans_tip)">channels</a> snd)))
+ (<em class=red>map-channel</em> proc beg dur snd i edpos origin)))
+</pre></td></tr></table>
+
+An esoteric aside: map-channel sets up the sampler before calling the procedure, so if that procedure edits
+the sound itself (independent of map-channel), the result will be all such edits after the current edit, then the map-channel result
+applied to the original (not the newly edited) data. That is,<br><pre>
+(let ((first #t))
+ (<em class=red>map-channel</em> (lambda (y)
+ (if first (set! (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> 0) 1.0))
+ (set! first #f)
+ (* y 2))))
+</pre>
+will return with two edits registered in the edit history list; the map-channel result will be the original data doubled;
+the preceding edit in the list will be the <code>(set! (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> 0) 1.0)</code> which the map-channel ignores.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- maxamp -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="maxamp">maxamp</a> (:optional <em class=narg>snd chn</em> edpos)</code>
+</td></tr><tr><td></td><td>
+This returns the max amp of the given channel. Used with set!, it is equivalent to <a class=quiet href="#scaleto" onmouseout="UnTip()" onmouseover="Tip(extsnd_scaleto_tip)">scale-to</a>.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (maxamp-all)
+ "(maxamp-all) returns the current maxamp of all currently open sounds"
+ (apply max (map (lambda (snd) (apply max (<em class=red>maxamp</em> snd #t))) (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+</pre></td></tr></table>
+
+<!-- INDEX maxampexamples:Maxamps -->
+<A NAME="maxampexamples"></a>
+
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<blockquote><small>
+<br>
+Sound file maxamp: <a href="#mussoundmaxamp">mus-sound-maxamp</a><br>
+Region maxamp: <a href="#regionmaxamp">region-maxamp</a><br>
+Selection maxamp: <a href="#selectionmaxamp">selection-maxamp</a><br>
+Sound data object maxamp: <a href="#sounddatamaxamp">sound-data-maxamp</a><br>
+Vct maxamp: <a href="#vctpeak">vct-peak</a><br>
+To set the y axis bounds to reflect the channel's maxamp: <a href="#ybounds">y-bounds</a><br>
+Mix maxamp: <a href="sndscm.html#mixmaxamp">mix-maxamp</a><br>
+maxamp locations: <a href="#maxampposition">maxamp-position</a>, <a href="#regionmaxampposition">region-maxamp-position</a>, <a href="#selectionmaxampposition">selection-maxamp-position</a>
+<br><br>
+</small></blockquote>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- maxamp-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="maxampposition">maxamp-position</a> (:optional <em class=narg>snd chn</em> edpos)</code>
+</td></tr><tr><td></td><td>
+This gives the location (sample number) of the maximum sample in the given channel.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- max-transform-peaks -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="maxfftpeaks">max-transform-peaks</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This returns the maximum number of transform peaks reported.
+The default is 100. max-transform-peaks affects both the fft display (if <a href="#showtransformpeaks">show-transform-peaks</a>)
+and the <a href="#peaks">peaks</a> function.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- min-dB -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="mindb">min-dB</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This sets the minimum dB value displayed in various graphs (the default is -60.0).
+Due to problems with arithmetic underflows in sqrt, the spectrum functions set the lowest
+actual dB value calculated to -140.0 or -180.0 (depending on which function is called and so on).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- new-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="newsound">new-sound</a> (<a class=quiet href="sndclm.html#optional-key" onmouseout="UnTip()" onmouseover="Tip(sndclm_optional_key_tip)">&amp;optional-key</a> :file :header-type :data-format :srate :channels :comment :size)</code>
+</td></tr><tr><td></td><td>
+new-sound creates a new sound named 'file'. The following function opens a new sound named "test.snd",
+extends it to 'dur' samples, and initializes all samples to 'val':
+<pre>
+ (define (init-sound val dur)
+ (let ((ind (<em class=red>new-sound</em> "test.snd" :size dur)))
+ (<a class=quiet href="#mapchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_mapchannel_tip)">map-channel</a> (lambda (y) val))
+ ind))
+</pre>
+If the 'header-type' and other
+arguments are not specified, they
+default to the current <a href="#defaultoutputheadertype">default-output-header-type</a> and
+related settings. Data formats are (b=big-endian, l=little, u=unsigned):
+<pre>
+ mus-bshort mus-lshort mus-mulaw mus-alaw mus-byte mus-ubyte mus-bfloat
+ mus-lfloat mus-bint mus-lint mus-b24int mus-l24int mus-bdouble mus-ldouble
+ mus-ubshort mus-ulshort
+</pre>
+Header-types are:
+<pre>
+ mus-next mus-aifc mus-riff mus-rf64 mus-nist mus-raw mus-ircam mus-aiff
+ mus-soundfont mus-bicsf mus-voc mus-svx mus-caff
+</pre>
+To be informed whenever a new sound is created, use <a href="#newsoundhook">new-sound-hook</a> (see ws.scm).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- normalize-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="normalizechannel">normalize-channel</a> (norm :optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+normalize-channel
+scales (changes the amplitude) of a sound so that its new peak amplitude is 'norm'. This
+is the "regularized" form of <a href="#scaleto">scale-to</a>.
+The multichannel version is <a href="sndscm.html#normalizesound">normalize-sound</a> in extensions.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- open-raw-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="openrawsound">open-raw-sound</a> (<a class=quiet href="sndclm.html#optional-key" onmouseout="UnTip()" onmouseover="Tip(sndclm_optional_key_tip)">&amp;optional-key</a> :file :channels :srate :data-format)</code>
+</td></tr><tr><td></td><td>
+This opens 'file' as a raw (no header) sound in the layout specified.
+If the file has a header, it is not ignored (use <code>(set! (<a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_dataformat_tip)">data-format</a> ...))</code>
+and friends to get around this). If the header is messed up, you can override its settings by
+giving the correct values in the call to open-raw-sound.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define mpg
+ (lambda (mpgfile rawfile chans)
+ "(<a class=quiet href="sndscm.html#mpg" onmouseout="UnTip()" onmouseover="Tip(sndscm_mpg_tip)">mpg</a> file tmpname chans) converts file from MPEG-3 to raw 16-bit samples using mpg123"
+ (system (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "mpg123 -s ~A &gt; ~A" mpgfile rawfile))
+ (<em class=red>open-raw-sound</em> rawfile 1 44100 (if (<a class=quiet onmouseout="UnTip()" onmouseover="Tip('little-endian? returns #t if the host uses that byte order')">little-endian?</a>) <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_muslshort_tip)">mus-lshort</a> <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_musbshort_tip)">mus-bshort</a>))))
+</pre></td></tr></table>
+
+There's a more elaborate version of this function in examp.scm. See also <a href="#openrawsoundhook">open-raw-sound-hook</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- open-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="opensound">open-sound</a> (filename)</code>
+</td></tr><tr><td></td><td>
+open-sound opens 'filename' and returns the sound object; this is equivalent to the File:Open option. <a href="#viewsound">view-sound</a>
+opens a sound read-only, or you can set <a class=quiet href="#readonly" onmouseout="UnTip()" onmouseover="Tip(extsnd_readonly_tip)">read-only</a> by hand. <a class=quiet href="#closesound" onmouseout="UnTip()" onmouseover="Tip(extsnd_closesound_tip)">close-sound</a>
+closes a file opened by open-sound. There are a variety of hooks that are invoked during the sound opening process:
+<a class=quiet href="#duringopenhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_duringopenhook_tip)">during-open-hook</a>, <a class=quiet href="#openhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openhook_tip)">open-hook</a>,
+<a class=quiet href="#afteropenhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_afteropenhook_tip)">after-open-hook</a>,
+<a class=quiet href="#initialgraphhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_initialgraphhook_tip)">initial-graph-hook</a>, <a class=quiet href="#openrawsoundhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openrawsoundhook_tip)">open-raw-sound-hook</a>.
+The sequence of actions is:
+<pre>
+ bad header?: <a class=quiet href="#badheaderhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_badheaderhook_tip)">bad-header-hook</a> &mdash; can cancel request
+ no header?: <a class=quiet href="#openrawsoundhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openrawsoundhook_tip)">open-raw-sound-hook</a> &mdash; can cancel request
+ file ok:
+ <a class=quiet href="#openhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openhook_tip)">open-hook</a> &mdash; can change filename
+ file opened (no data read yet)
+ <a class=quiet href="#duringopenhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_duringopenhook_tip)">during-open-hook</a> (can set prescaling etc)
+ data read, no graphics yet
+ <a class=quiet href="#afteropenhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_afteropenhook_tip)">after-open-hook</a>
+ <a class=quiet href="#initialgraphhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_initialgraphhook_tip)">initial-graph-hook</a>
+</pre>
+There are
+other ways to get at sound file data: <a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> can be given a filename,
+rather than a sound; file-&gt;vct in examp.scm;
+<a class=quiet href="#mussoundopeninput" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundopeninput_tip)">mus-sound-open-input</a> and
+there are a variety of CLM-based functions such as
+<a class=quiet href="sndclm.html#filetosample" onmouseout="UnTip()" onmouseover="Tip(sndclm_filetosample_tip)">file-&gt;sample</a> and
+<a class=quiet href="sndclm.html#filetoarray" onmouseout="UnTip()" onmouseover="Tip(sndclm_filetoarray_tip)">file-&gt;array</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- pad-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="padchannel">pad-channel</a> (beg dur :optional snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+pad-channel inserts 'dur' zeros at 'beg' in the given channel. This is the <a class=quiet href="#regularizedargs" onmouseout="UnTip()" onmouseover="Tip(extsnd_regularizedargs_tip)">regularized</a>
+version of <a href="#insertsilence">insert-silence</a>. To set a block of samples to zero, use
+<a href="#scalechannel">scale-channel</a> with a scaler of 0.0.
+To insert a block of arbitrary-valued samples:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<A NAME="blockchannel">block-channel</a> value :optional (beg 0) dur snd chn edpos)
+ (<em class=red>pad-channel</em> beg dur snd chn edpos) ; insert 'dur' samples, ptree-channel sets their values
+ (<a class=quiet href="#ptreechannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_ptreechannel_tip)">ptree-channel</a> (lambda (y) value) beg dur snd chn))
+</pre></td></tr></table>
+
+We could also use map-channel here (rather than ptree-channel), but this version
+uses only virtual edits, so no matter how big the block of samples we insert,
+no disk space or memory is needed.
+The multichannel version is <a href="sndscm.html#padsound">pad-sound</a> in frame.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- pausing -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="pausing">pausing</a> ()</code>
+</td></tr><tr><td></td><td>
+pausing is #t if sound output is currently paused. You can unpause the sound by setting pausing to #f,
+and pause it by setting pausing to #t. If you pause a sound (via C-click of the play button, for example),
+then call <a href="#play">play</a> (via a key binding perhaps), the sound remains paused by default. To
+cancel the current pause and restart with the new play command:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> (char-&gt;integer #\p) 0
+ (lambda ()
+ (if (<em class=red>pausing</em>) (<a class=quiet href="#stopplaying" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopplaying_tip)">stop-playing</a>))
+ (<a class=quiet href="#play" onmouseout="UnTip()" onmouseover="Tip(extsnd_play_tip)">play</a>)))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- peak-env-info -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="peakenvinfo">peak-env-info</a> (:optional snd chn pos)</code>
+</td></tr><tr><td></td><td>
+This returns some of the overall amplitude envelope data for the given channel
+at the given edit list position. The data currently returned are whether
+the envelopes are complete (they are the result of a background process), and the min and max data values.
+This is aimed at initial graph setup code that wants to fit the graph bounds to the data.
+See <a href="#initialgraphhook">initial-graph-hook</a> and peak-env.scm.
+The complete peak-env graphs are returned by <a href="#channelampenvs">channel-amp-envs</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- peaks -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="peaks">peaks</a> (:optional file snd chn)</code>
+</td></tr><tr><td></td><td>
+peaks displays fft peak information. If 'file' is not null, it writes
+the information to that file, otherwise it posts the data in a help window
+(where it can be selected and pasted elsewhere). The maximum number of peaks reported is set
+by <a href="#maxfftpeaks">max-transform-peaks</a>.
+
+<pre>
+(add-hook! <a class=quiet href="#aftertransformhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_aftertransformhook_tip)">after-transform-hook</a> (lambda (a b c)
+ (<em class=red>peaks</em>))) ; post a detailed list of peaks after each FFT
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- play -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="play">play</a> (:optional samp snd chn sync end edpos stop-proc out-chan)</code>
+</td></tr><tr><td></td><td>
+This function plays the given channel starting from sample 'samp'.
+If 'sync' is #t, it plays all sounds sync'd to 'snd'. If 'end' is not given or is #f,
+it plays until the end of the sound. If 'end' is given (as a sample number), the
+actual end point may be off by a few samples; Snd only checks on
+dac-buffer boundaries (normally around 256 samples).
+<pre>
+ (play) ; play current sound, all chans from start to end
+ (play (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>)) ; play starting from the cursor
+ (play (round (* 3.0 (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>))) 1 3) ; play snd 1, chan 3 (4th chan), start at 3.0 secs
+ (play 0 #f #f #t) ; play sync'd sounds
+ (play 0 #f #f #f (round (* 3.0 (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>)))) ; play from start for 3.0 secs
+ (play 0 #f #f #f #f 2) ; play the version at edit history position 2
+ (play 0 0 2 #f #f #f #f 0) ; play chan 2, but send it to DAC chan 0
+ (play (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> 0) #f #f #f (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> 1)); play between marks 0 and 1
+ (play (<a class=quiet href="#selectionposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionposition_tip)">selection-position</a>) #f #f (+ (<a class=quiet href="#selectionposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionposition_tip)">selection-position</a>) (<a class=quiet href="#selectionframes" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionframes_tip)">selection-frames</a>))) ; play selection
+</pre>
+'samp' can
+also be a filename (a string). In this case, 'snd' can be the start
+sample (default 0), and 'chn' can be the end sample (default end-of-file).
+
+<pre>
+ (play "1a.snd") ; play 1a.snd
+ (play "1a.snd" 1000 4000) ; play 1a.snd from sample 1000 to 4000
+</pre>
+
+If 'chn' is not given, or is a boolean, play plays all channels together.
+If 'pos' is given, it plays at that edit position.
+If 'stop-proc' is a procedure of one argument, it is called when the play process stops.
+The argument passed to 'stop-proc' provides the reason the play is stopping; it will be 0 if the play completed normally.
+'stop-proc' is intended mainly for looping plays, as in <a href="sndscm.html#playoften">play-often</a>.
+<pre>
+ (play 0 #f #f #f #f #f
+ (lambda (reason) ; if interrupted, say so in the listener
+ (if (not (= reason 0))
+ (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> ";play interrupted"))))
+</pre>
+
+The 'pos' argument makes it easier to try "A:B" comparisons; this plays the version before the latest edit:
+<pre>
+ (play 0 #f #f #f #f (- (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a>) 1))
+</pre>
+
+The following code binds the "p" key to play all channels of the current sound from the cursor, and
+the "P" key to play the previous version of the current sound:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (play-from-cursor current)
+ (<em class=red>play</em> (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) #f #f #f #f (if current #f (- (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a>) 1))))
+
+(<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> (char-&gt;integer #\p) 0
+ (lambda () "play from cursor" (play-from-cursor #t) <a class=quiet onmouseout="UnTip()" onmouseover="Tip(extsnd_keyboard_no_action_tip)">keyboard-no-action</a>))
+
+(<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> (char-&gt;integer #\P) 0
+ (lambda () "play previous version from cursor" (play-from-cursor #f) <a class=quiet onmouseout="UnTip()" onmouseover="Tip(extsnd_keyboard_no_action_tip)">keyboard-no-action</a>))
+</pre></td></tr></table>
+
+And here we play from the cursor with a moving ("tracking") cursor:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<A NAME="pfc">pfc</a>)
+ (let ((old-tracking (<a class=quiet href="#withtrackingcursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_withtrackingcursor_tip)">with-tracking-cursor</a>)))
+ (set! (<a class=quiet href="#withtrackingcursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_withtrackingcursor_tip)">with-tracking-cursor</a>) #t)
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#stopplayinghook" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopplayinghook_tip)">stop-playing-hook</a>
+ (lambda (snd)
+ (set! (<a class=quiet href="#withtrackingcursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_withtrackingcursor_tip)">with-tracking-cursor</a>) old-tracking)))
+ (<em class=red>play</em> (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>))))
+</pre></td></tr></table>
+
+Finally, if 'samp' is a function, it is called on every sample; if it returns a number, that number is
+sent to the DAC; if it returns #f, it stops. <a href="sndscm.html#playmixes">play-mixes</a> uses this
+function option to time the playing each mix in a sequence of mixes. Another example is <a href="sndscm.html#playsine">play-sine</a>:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (play-sine freq amp)
+ "(play-sine freq amp) plays a 1 second sinewave at freq and amp"
+ (let* ((len 22050)
+ (osc (<a class=quiet href="sndclm.html#make-oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_oscil_tip)">make-oscil</a> freq)))
+ (<em class=red>play</em> (lambda ()
+ (set! len (- len 1))
+ (if (&lt;= len 0) ; we've sent 22050 samples, so it's time to stop
+ #f
+ (* amp (<a class=quiet href="sndclm.html#oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_oscil_tip)">oscil</a> osc)))))))
+</pre></td></tr></table>
+
+<!-- INDEX playexamples:Playing -->
+<A NAME="playexamples"></a>
+
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<small><blockquote>
+play one channel: <a href="#playchannel">play-channel</a>, play button in control panel or files dialog<br>
+play from cursor: C-q and example above<br>
+play from cursor with tracking cursor: <a href="#pfc">pfc</a> above<br>
+play the selection: <a href="#playselection">play-selection</a>, <a href="snd.html#cxp">C-x p</a><br>
+play a region: <a href="#playregion">play-region</a>, <a href="snd.html#cxp">C-x p</a>, play button in Region dialog<br>
+play a mix: <a href="#playmix">play-mix</a>, play button in Mix dialog<br>
+play a sequence of mixes: <a href="sndscm.html#playmixes">play-mixes</a><br>
+play from mark: click or drag triangle (control-click for all chans)<br>
+play continuously between two marks: <a href="sndscm.html#loopbetweenmarks">loop-it</a><br>
+stop playing: C-g, C-t, <a href="#stopplaying">stop-playing</a>, set <a href="#playing">playing</a> to #f<br>
+pause or resume playback: space, set <a href="#pausing">pausing</a><br>
+play repeatedly: <a href="sndscm.html#playoften">play-often</a><br>
+play repeatedly until C-g: <a href="sndscm.html#playuntilcg">play-until-c-g</a><br>
+play region repeatedly: <a href="sndscm.html#playregionforever">play-region-forever</a><br>
+play a file upon a keystroke: <a href="#extendedpiano">bind-key</a><br>
+play using an external program: (system "sndplay wood16.wav")<br>
+play a sine-wave or spectrum: <a href="sndscm.html#playsine">play-sine</a> and <a href="sndscm.html#playsines">play-sines</a><br>
+play arbitrary mixtures of things: <a href="#makeplayer">make-player</a> and related functions, <a href="sndscm.html#playsyncdmarks">play-syncd-marks</a><br>
+send arbitrary data to the DAC: <a href="#musaudiowrite">mus-audio-write</a>, <a href="sndscm.html#startdac">start-dac</a><br>
+play after sending the data through some function: <a href="sndscm.html#playsound">play-sound</a><br>
+play with applied amplitude envelope: <a href="sndscm.html#playwithenvs">play-with-envs</a>, <a href="sndscm.html#playpanned">play-panned</a><br>
+play an external file: (play "file")<br>
+<br>
+</blockquote></small>
+</td></tr></TABLE>
+
+<A NAME="stopplayreasons"></a>
+<pre>
+The "reasons" that might be passed to the stop-procedure are:
+
+ 0 play completed normally
+ 1 file is being closed
+ 2 play button unset
+ 3 stop-playing function called
+ 4 C-g
+ 5 DAC error (no available channel)
+ 6 play error (audio setup problem)
+ 7 apply requested (control panel)
+ 8 file edited
+ 9 C-t
+</pre>
+
+The hooks called during a play operation are:
+<pre>
+ when a play request occurs: <a class=quiet href="#startplayinghook" onmouseout="UnTip()" onmouseover="Tip(extsnd_startplayinghook_tip)">start-playing-hook</a> &mdash; can cancel the request,
+ also <a class=quiet href="#startplayingselectionhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_startplayingselectionhook_tip)">start-playing-selection-hook</a>
+ (any number of sounds can be playing at once)
+ as each buffer is sent to the audio device: <a class=quiet href="#playhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_playhook_tip)">play-hook</a> and <a class=quiet href="#dachook" onmouseout="UnTip()" onmouseover="Tip(extsnd_dachook_tip)">dac-hook</a>
+ as each sound ends: <a class=quiet href="#stopplayinghook" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopplayinghook_tip)">stop-playing-hook</a>, <a class=quiet href="#stopplayingselectionhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopplayingselectionhook_tip)">stop-playing-selection-hook</a>
+ close audio device: <a class=quiet href="#stopdachook" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopdachook_tip)">stop-dac-hook</a>
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- play-and-wait -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="playandwait">play-and-wait</a> (:optional samp snd chn sync end edpos stop-proc out-chan)</code>
+</td></tr><tr><td></td><td>
+This plays the given channel starting from sample 'samp' and waits
+for it to finish. <a href="#play">play</a> on the other hand returns immediately so subsequent calls on play
+mix multiple sample streams together, rather than playing them one after the other.
+If 'pos' is given, play-and-wait plays at that edit position.
+'stop-proc' is explained under 'play' above; it's not really needed here, but "consistency is a virtue", I guess.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- play-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="playchannel">play-channel</a> (:optional beg dur snd chn edpos stop-proc out-chan)</code>
+</td></tr><tr><td></td><td>
+play-channel is the <a class=quiet href="#regularizedargs" onmouseout="UnTip()" onmouseover="Tip(extsnd_regularizedargs_tip)">regularized</a> version of <a href="#play">play</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- player-home -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="playerhome">player-home</a> (player)</code>
+</td></tr><tr><td></td><td>
+This returns a list of the sound and channel number associated with <a href="#makeplayer">player</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- playing -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="playing">playing</a> ()</code>
+</td></tr><tr><td></td><td>
+This returns #t if sound output is currently in progress. You can also start playing by setting playing to #t (equivalent
+to calling <a href="#startplaying">start-playing</a> with default arguments), and stop by setting it to #f
+(equivalent to <a href="#stopplaying">stop-playing</a>).
+playing only notices Snd-instigated "play" processes;
+<a href="#musaudioopenoutput">mus-audio-open-output</a> is invisible to it.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- players -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="players">players</a> ()</code>
+</td></tr><tr><td></td><td>
+This returns a list of currently active <a href="#makeplayer">players</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- player? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="playerQ">player?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+This returns #t if 'obj' is an active <a href="#makeplayer">player</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- position->x -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="positiontox">position-&gt;x</a> (xpos snd chn axis)</code>
+</td></tr><tr><td></td><td>
+This returns the x axis value that corresponds to the graph (screen pixel) position 'xpos'.
+To find the sample that the mouse is pointing at, given the current mouse position,
+<pre>
+ (inexact-&gt;exact (round (* (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> snd) (position-&gt;x x snd chn))))
+</pre>
+See gui.scm for examples.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- position->y -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="positiontoy">position-&gt;y</a> (ypos snd chn axis)</code>
+</td></tr><tr><td></td><td>
+This returns the y axis value that corresponds to the graph (screen pixel) position 'ypos'.
+See gui.scm for examples.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- progress-report -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="progressreport">progress-report</a> (pct :optional snd chn)</code>
+</td></tr><tr><td></td><td>
+The functions <a href="#startprogressreport">start-progress-report</a>, progress-report, and
+<a href="#finishprogressreport">finish-progress-report</a> handle the animated hour-glass icon
+that hopes to amuse the idle user while some long computation is in progress.
+The 'pct' argument is a float between 0.0 and 1.0 which indicates how
+far along we are in the computation; there are only 20 separate
+icons, so there's no point in calling this more often than that.
+<a href="#startprogressreport">start-progress-report</a> posts the initial icon, and <a href="#finishprogressreport">finish-progress-report</a>
+removes it. If the icons are not available, a message is posted in
+the sound's minibuffer using 'name' to identify itself.
+See ladspa.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- prompt-in-minibuffer -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="promptinminibuffer">prompt-in-minibuffer</a> (msg :optional callback snd raw)</code>
+</td></tr><tr><td></td><td>
+This posts 'msg' in the sound's minibuffer and when you respond,
+it calls 'callback' with the response as the callback's argument.
+If 'callback' is specified it should be either #f or a function of
+one argument: the raw response if 'raw' is #t, otherwise the evaluated response.
+For example, the following fragment asks for
+a yes-or-no response, then takes some action:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+ (define* (yes-or-no question action-if-yes action-if-no :optional snd)
+ (<em class=red>prompt-in-minibuffer</em> question
+ (lambda (response)
+ (<a class=quiet href="#clearminibuffer" onmouseout="UnTip()" onmouseover="Tip(extsnd_clearminibuffer_tip)">clear-minibuffer</a>)
+ (if (string=? response "yes")
+ (action-if-yes snd)
+ (action-if-no snd)))
+ snd #t))
+</pre></td></tr></table>
+
+See eval-over-selection in <a href="sndscm.html#extensionsdoc">extensions.scm</a> for a more useful example.
+We could also use a continuation here:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (prompt msg default)
+ (call-with-current-continuation
+ (lambda (rsvp)
+ (<em class=red>prompt-in-minibuffer</em> msg rsvp)
+ default)))
+</pre></td></tr></table>
+
+The 'raw' argument is useful when we want to prompt for yes or no, without forcing the
+user to put the answer in double quotes. In the next example, we replace Snd's
+built-in C-x k action (which immediately closes the sound) with one that is
+more like Emacs (it prompts for confirmation first):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> (char-&gt;integer #\k) 0
+ (lambda ()
+ "close sound"
+ (<a class=quiet href="#clearminibuffer" onmouseout="UnTip()" onmouseover="Tip(extsnd_clearminibuffer_tip)">clear-minibuffer</a>)
+ (<em class=red>prompt-in-minibuffer</em>
+ (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "close ~S (cr=yes)?" (<a class=quiet href="#shortfilename" onmouseout="UnTip()" onmouseover="Tip(extsnd_shortfilename_tip)">short-file-name</a>))
+ (lambda (response)
+ (if (and (not (<a class=quiet href="#cgp" onmouseout="UnTip()" onmouseover="Tip(extsnd_cgp_tip)">c-g?</a>)) ; C-g =&gt; no
+ (or (not (string? response))
+ (= (string-length response) 0)
+ (char=? (string-ref response 0) #\y)))
+ (<a class=quiet href="#closesound" onmouseout="UnTip()" onmouseover="Tip(extsnd_closesound_tip)">close-sound</a>)))
+ #f ; selected sound
+ #t)) ; treat as string (i.e. don't require double quotes)
+ #t) ; C-x ...
+</pre></td></tr></table></td></tr>
+<tr><td colspan=2 height=18></td></tr>
+
+
+<!-- INDEX ptreechannel:Virtual Edits -->
+<!-- ptree-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="ptreechannel">ptree-channel</a> (proc :optional beg dur snd chn edpos env-too init-func origin)</code>
+</td></tr><tr><td></td><td>
+ptree-channel
+applies the function 'proc' as a 'virtual edit'; that is, the effect of 'proc'
+comes about as an implicit change in the way the data is read.
+
+<br><br>
+To be less Orphic:
+all the data accesses in Snd go through the edit-history list. The currently
+active member of that list
+chooses a channel data accessor based on the type of edit. A multiply by 2, for
+example, does not multiply anything by 2 internally; it just chooses
+the accessor that multiplies by 2 on any read. Since every other data access goes through this reader, from any other
+point of view, the data has been multiplied. These accessors make it
+unnecessary to save any data in temp files or internal arrays, and editing the edit-history list is very
+fast &mdash; we just tack a new accessor choice onto the edit-history list, so the edit operation
+appears to be instantaneous and memory-less. Lots of other operations
+are already being done this way in Snd (deletions, scaling, most
+envelopes, some channel swaps, etc). ptree-channel extends the idea to (nearly) arbitrary
+functions. When you call
+<pre>
+ (ptree-channel (lambda (y) (* y 2)))
+</pre>
+which has the same effect as
+<pre>
+ (<a class=quiet href="#mapchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_mapchannel_tip)">map-channel</a> (lambda (y) (* y 2)))
+</pre>
+the
+optimizer makes the parse-tree that represents <code>(lambda (y) (* y 2))</code>, then the
+data accessor system uses that parse-tree every time the data is
+read.
+<br><br>
+
+If the argument 'env-too' is #t,
+the same function is applied to the peak env values to get the new version of the peak env data.
+The default is #f, and should be #t only if the old max and min values as processed through 'proc'
+will be the new max and min values.
+Snd uses the peak env values when the graph of the sound covers very large amounts of data.
+If 'env-too' is #f, a background process is launched reading all the sound data through
+'proc'; this can be time-consuming, so if you're viewing a half-hour of sound data,
+it can take awhile for the ptree-channel results to be displayed.
+<br><br>
+
+Here is an example that adds a constant to each sample in a file.
+<pre>
+ (define* (offset-channel dc :optional (beg 0) dur snd chn edpos)
+ (<em class=red>ptree-channel</em> (lambda (y) (+ y dc)) beg dur snd chn edpos <em class=red>#t</em>))
+</pre>
+The actual edit that takes place is <code>(+ y dc)</code>; that is, 'dc' is added to
+every sample. As subsequent editing takes place, the entries representing the 'offset-channel'
+call can become thoroughly fragmented.
+If your editing operation has any state (i.e. needs to
+know where it is in the data), you need to add an 'init-func' (the 8th argument to ptree-channel).
+The 'init-func' takes two arguments, the begin time of the read operation, relative to
+the original start of the fragment, and the original fragment duration (both in samples).
+It should return
+the information the main function ('proc' above) needs to
+handle the current fragment correctly. Global variables are not guaranteed to
+be set within the body of 'proc', so use a vct for local values that change
+as the read operation progresses.
+<br><br>
+
+The other new argument to 'proc'
+is the read direction; the read operations can change direction at any
+time, and any ptree-channel function needs to know how to deal with that.
+So, in the complicated, 3 argument case,
+the sequence of operations is:
+a read is requested, 'init-func' is called with the read start point (relative to the
+original segment start),
+it returns any state that 'proc' may need
+to refer to, then each time a sample is needed from the current sample
+reader, 'proc' is called passing it the current underlying sample, the return value of 'init-func',
+and the read direction.
+Here is an example that mixes a sine wave into the current channel:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (sine-channel freq amp :optional (beg 0) dur snd chn edpos)
+ (<em class=red>ptree-channel</em>
+ (lambda (y data forward)
+ (let* ((angle (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 0))
+ (incr (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 1))
+ (val (+ y (* (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 2) (sin angle)))))
+ (if forward
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data 0 (+ angle incr))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data 0 (- angle incr)))
+ val))
+ beg dur snd chn edpos #f
+ (lambda (frag-beg frag-dur)
+ (let ((incr (/ (* 2 pi freq) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>))))
+ (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> (<a class=quiet onmouseout="UnTip()" onmouseover="Tip('fmod is mod with float arguments')">fmod</a> (* frag-beg incr) (* 2 pi)) incr amp))))) ; fmod from C
+</pre></td></tr></table>
+
+In the normal case,
+this function simply mixes in a sine wave: <code>(+ y (* (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 2) (sin angle)))</code>
+where the amplitude scaler is stored in <code>(<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 2)</code>. In subsequent
+reads, the init-func sets up a vct with the current phase (dependent on the frequency
+and the fragment begin sample), the phase increment (dependent on the frequency), and
+the amplitude (passed as an argument to sine-channel, but stored in the vct since
+the outer function's arguments won't be accessible in the main function ('proc')).
+See 'sine-ramp' in extensions.scm for another example.
+<br><br>
+
+In our 'sine-channel' function, we passed #f as the 'env-too' argument,
+to make sure Snd doesn't blithely apply the sine mix to the peak amplitude
+envelopes. When 'env-too' is #t,
+'proc' is evaluated over the peak env data, rather than the
+original data. This makes redisplay much faster whenever a lot of data
+is being displayed, but only works if the function's output at the peak
+env min and max values are still the min and max values in the actual
+data (this is the case in the sinusoidal envelope, sine-ramp, mentioned above).
+When 'proc' is being called to calculate the new peak env,
+the duration passed to the init-func is the envelope size.
+Here is a
+version of cosine-channel given under
+<a href="#mapchannel">map-channel</a> that can handle peak-envs:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<A NAME="cosinechannelviaptree">cosine-channel-via-ptree</a> :optional (beg 0) dur snd chn edpos)
+ ;; vct: angle increment
+ (<em class=red>ptree-channel</em>
+ (lambda (y data forward)
+ (let* ((angle (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 0))
+ (incr (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 1))
+ (val (* y (cos angle))))
+ (if forward
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data 0 (+ angle incr))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data 0 (- angle incr)))
+ val))
+ beg dur snd chn edpos <em class=red>#t</em>
+ (lambda (frag-beg frag-dur)
+ (let ((incr (/ pi <em class=red>frag-dur</em>)))
+ (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> (+ (* -0.5 pi) (* frag-beg incr))
+ incr)))))
+</pre></td></tr></table>
+
+If the underlying data
+has too many previous ptree operations (more than <a href="#maxvirtualptrees">max-virtual-ptrees</a>), map-channel is called instead and the new
+data is saved in the normal manner.
+
+<br><br>
+
+If no 'init-func' is specified, the editing procedure ('proc') should not assume anything about
+the context in which it is called; in this case, there's no way for 'proc' to know where it starts, or when it is being restarted,
+or which direction it is running, so,
+the following call:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+ (let ((ctr 0))
+ (<em class=red>ptree-channel</em> (lambda (y)
+ (set! ctr (+ 1 ctr))
+ (* ctr .0001))))
+</pre></td></tr></table>
+
+will never reset ctr to 0! Every time a portion of the data is read by Snd, the samples will be
+higher. But, the notion of an accessor that returns a different thing each time a sample
+is accessed is not foolish:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (dither-channel :optional (amount .00006) beg dur snd chn edpos)
+ (let ((dither (* .5 amount)))
+ (<em class=red>ptree-channel</em>
+ (lambda (y)
+ (+ y (<a class=quiet href="sndclm.html#mus-random" onmouseout="UnTip()" onmouseover="Tip(sndclm_mus_random_tip)">mus-random</a> dither) (<a class=quiet href="sndclm.html#mus-random" onmouseout="UnTip()" onmouseover="Tip(sndclm_mus_random_tip)">mus-random</a> dither)))
+ beg dur snd chn edpos #t)))
+</pre></td></tr></table>
+
+This gives a slightly different take on the sound each time you look at it or listen to it;
+the dithering is never exactly the same. But if the details of the noise don't
+matter (presumably the case with dithering), the difference is unproblematic. You're editing a sort
+of mobile in sound (analogous to mobile sculpture).
+<br><br>
+One major limitation of ptree-channel with an 'init-func' is that <a href="#savestate">save-state</a>
+currently doesn't know how to save the enclosing environment along with the init-func. So,
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+ (let ((outer 0.5))
+ (<em class=red>ptree-channel</em> (lambda (y data forward)
+ (<a class=quiet href="#declare" onmouseout="UnTip()" onmouseover="Tip(extsnd_declare_tip)">declare</a> (y real) (data float) (forward boolean))
+ (* y data))
+ 0 #f ind 0 #f #f
+ (lambda (pos dur)
+ outer)))
+</pre></td></tr></table>
+
+will not save the "outer" declaration in the saved state file.
+This is a general problem with save-state; there's no obvious way in Guile to
+save the current closure as text.
+You can fix the saved state file by hand (it is just Scheme, Ruby, or Forth code, of course),
+but that's not a very elegant solution.
+<br><br>
+
+The real limitation in using ptree-channel, however, arises from the fact that the read direction
+can not only be backwards, but it can also change at any time. In conjunction with
+the fragmentation during editing, this makes it
+hard to use CLM generators, or anything that depends on previous samples.
+Since the run macro (on which ptree-channel depends) is currently limited in
+the kinds of vector or list elements it can decipher, you're pretty tightly
+constricted in this context.
+The read direction argument can be ignored if you know you're not going to read backwards.
+The only hidden reverse read is in the src generator where a negative increment can be
+generated in a variety of ways (for example, src driven by oscil). A one zero filter
+could in this case be:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+ (<em class=red>ptree-channel</em> (lambda (y data forward)
+ (let ((val (* 0.5 (+ y (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 0)))))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data 0 y)
+ val))
+ 0 (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>) ind 0 #f #f ; "ind" is the sound
+ (let ((edpos (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> ind 0)))
+ (lambda (pos dur)
+ (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> (if (= pos 0) 0.0
+ (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> (- pos 1) ind 0 edpos))))))
+</pre></td></tr></table>
+
+See also virtual-filter-channel in snd-test.scm; it uses the optional third argument to the init function
+to set up the filter state correctly, and has code to run the filter backwards if necessary.
+Here are several more examples:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (ptree-scale scl :optional (beg 0) dur snd chn edpos)
+ "ptree-channel version of scale-channel"
+ (<em class=red>ptree-channel</em>
+ (lambda (y)
+ (* scl y))
+ beg dur snd chn edpos #t))
+
+(define* (ptree-xramp r0 r1 ubase :optional (beg 0) dur snd chn edpos)
+ "exponential version of ramp-channel"
+ ;; this is essentially what CLM's exponential envelope generator is doing
+ ;; to accommodate C, it uses (exp (* power (log base))) prescaling power by (log base)
+ (let* ((base (if (&gt; r0 r1) (/ 1.0 ubase) ubase)))
+ (<em class=red>ptree-channel</em>
+ (lambda (y data forward)
+ (let* ((lr0 (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 0))
+ (lbase (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 1))
+ (incr (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 2))
+ (scl (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 3))
+ (power (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data 4))
+ (val (* y (+ lr0 (* scl (- (expt lbase power) 1.0))))))
+ (if forward
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data 4 (+ power incr))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data 4 (- power incr)))
+ val))
+ beg dur snd chn edpos #t
+ (lambda (frag-beg frag-dur)
+ ;; r0, base, incr, (/ (- r1 r0) (- base 1.0)), current power
+ (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> r0
+ base
+ (/ 1.0 frag-dur)
+ (/ (- r1 r0) (- base 1.0))
+ (/ frag-beg frag-dur))))))
+
+(define* (virtual-mix file beg :optional snd chn)
+ (let ((len (<a class=quiet href="#mussoundframes" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundframes_tip)">mus-sound-frames</a> file)))
+ (<em class=red>ptree-channel</em>
+ (lambda (y state forward)
+ (<a class=quiet href="#declare" onmouseout="UnTip()" onmouseover="Tip(extsnd_declare_tip)">declare</a> (y real) (state sampler) (forward boolean))
+ (+ y (if forward (<a class=quiet href="#nextsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_nextsample_tip)">next-sample</a> state) (<a class=quiet href="#previoussample" onmouseout="UnTip()" onmouseover="Tip(extsnd_previoussample_tip)">previous-sample</a> state))))
+ beg len snd chn -1 #f
+ (lambda (frag-beg frag-dur)
+ (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> frag-beg file)))))
+
+</pre></td></tr></table>
+
+To handle an envelope in a ptree-channel application, it's probably
+easiest to split it up into a sequence of ramps, each ramp keeping track
+of its local begin point and increment. This is how sine-env-channel
+works, not to mention the built-in linear and exponential envelopes.
+The underlying procedure is <a href="sndscm.html#anyenvchannel">any-env-channel</a>
+which needs only the segment connecting function, and handles the rest itself.
+Here is an implementation of Anders Vinjar's power-envelope (a list
+of breakpoints with an added base for each segment), that splits
+the envelope into a sequence of <a href="#xrampchannel">xramp-channel</a>
+calls. It also uses <a href="#asoneedit">as-one-edit</a> to make the
+result appear to be one operation in the edit history list.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+<A NAME="powenvchannel"></a>(define* (powenv-channel envelope :optional (beg 0) dur snd chn edpos)
+ ;; envelope with a separate base for each segment:
+ ;; (powenv-channel '(0 0 .325 1 1 32.0 2 0 32.0))
+ (let* ((curbeg beg)
+ (fulldur (or dur (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd chn edpos)))
+ (len (length envelope))
+ (x1 (car envelope))
+ (xrange (- (list-ref envelope (- len 3)) x1))
+ (y1 (cadr envelope))
+ (base (caddr envelope))
+ (x0 0.0)
+ (y0 0.0))
+ (if (= len 3)
+ (<a class=quiet href="#scalechannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_scalechannel_tip)">scale-channel</a> y1 beg dur snd chn edpos)
+ (<em class=red>as-one-edit</em>
+ (lambda ()
+ (do ((i 3 (+ i 3)))
+ ((= i len))
+ (set! x0 x1)
+ (set! y0 y1)
+ (set! x1 (list-ref envelope i))
+ (set! y1 (list-ref envelope (+ i 1)))
+ (let* ((curdur (inexact-&gt;exact (round (* fulldur (/ (- x1 x0) xrange))))))
+ (<em class=red>xramp-channel</em> y0 y1 base curbeg curdur snd chn edpos)
+ (set! curbeg (+ curbeg curdur)))
+ (set! base (list-ref envelope (+ i 2)))))))))
+</pre></td></tr></table>
+
+If the init-func returns something other than a vct, you need to declare its type
+for the run macro. There are several examples in snd-test.scm.
+
+
+<table border=3 bordercolor="tan" hspace=20 vspace=20><tr><td>
+<blockquote><small>
+<br>
+more ptree-channel examples:<br>
+smoothing: smooth-channel-via-ptree (examp.scm)<br>
+compander: <a href="sndscm.html#compandchannel">compand-channel</a> (examp.scm)<br>
+insert a block of arbitrary-valued samples: <a href="#blockchannel">block-channel</a><br>
+sinusoidal ramp: <a href="sndscm.html#sineramp">sine-ramp</a> (extensions.scm)<br>
+sinusoidal envelope: <a href="sndscm.html#sineenvchannel">sine-env-channel</a> (extensions.scm)<br>
+CLM-style contrast-enhancement: <a href="sndscm.html#contrastchannel">contrast-channel</a> (extensions.scm)<br>
+add a constant to every sample: <a href="sndscm.html#offsetchannel">offset-channel</a> (extensions.scm)<br>
+ring modulation: ring-modulate-channel (examp.scm)<br>
+delay by n samples (an experiment!): delay-channel in extensions.scm<br>
+dithering: <a href="sndscm.html#ditherchannel">dither-channel</a> (extensions.scm)<br>
+FIR filter: <a href="sndscm.html#virtualfilterchannel">virtual-filter-channel</a> (examp.scm)<br>
+<br>
+</small></blockquote>
+</td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- ramp-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="rampchannel">ramp-channel</a> (rmp0 rmp1 :optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+ramp-channel is a slight extension of scale-channel. It scales samples in the given sound/channel
+between 'beg' and 'beg' + 'dur' by a (linear) ramp going from 'rmp0' to 'rmp1'.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- read-only -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="readonly">read-only</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This returns #t if 'snd' is read-only, #f otherwise. If you open
+a file with <a href="#viewsound">view-sound</a>, read-only is set to #t.
+read-only does not reflect (or affect) the write permission state of the underlying file; it is a way
+to keep from accidentally clobbering an otherwise writable file.
+If it is #t (or if the file is not writable), a lock icon is displayed beside the file name.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- read-peak-env-info-file -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="readpeakenvinfofile">read-peak-env-info-file</a> (snd chn filename)</code>
+</td></tr><tr><td></td><td>
+This opens and reads the data in 'filename', assumed to be the peak-env amp info written by <a href="#writepeakenvinfofile">write-peak-env-info-file</a>
+for the given channel. It expects to be called within <a href="#initialgraphhook">initial-graph-hook</a>. See peak-env.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- redo -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="redo">redo</a> (:optional edits snd chn)</code>
+</td></tr><tr><td></td><td>
+This re-activates 'edits' edits (the default is 1) in the given channel.
+Redo follows the <a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> field if it
+is not 0. The following might be a more reasonable redo function:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<a name="redochannel">redo-channel</a> :optional (<a class=quiet href="#edits" onmouseout="UnTip()" onmouseover="Tip(extsnd_edits_tip)">edits</a> 1) snd chn)
+ (if (and snd (not (= (<a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> snd) 0)) chn)
+ (set! (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> snd chn) (+ (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> snd chn) edits))
+ (<em class=red>redo</em> edits snd)))
+</pre></td></tr></table>
+
+redo moves forward in the edit history list, whereas
+<a href="#undo">undo</a> backs up, and <a href="#revertsound">revert-sound</a> resets the current
+edit position to the start of the list.
+For more about the edit history list, see <a href="#editlists">Edit Lists</a>.
+<br><br>
+In Ruby, redo is a part of the loop handling, so Snd's redo is renamed redo_edit.
+<a name="redoedit">redo-edit</a> also exists in Scheme, for consistency.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- report-in-minibuffer -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reportinminibuffer">report-in-minibuffer</a> (msg :optional snd as-error)</code>
+</td></tr><tr><td></td><td>
+This posts 'msg' in the sound's minibuffer. The 'minibuffer' is the text widget between the sound's filename and the buttons
+on the right, beneath the graph. It is intended to mimic Emacs' minibuffer, being useful mainly for short,
+temporary messages. C-g clears it, as does <a href="#clearminibuffer">clear-minibuffer</a>.
+If 'as-error' is #t, the message is placed in the minibuffer error label, rather than in the usual text area.
+See also <a href="#promptinminibuffer">prompt-in-minibuffer</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- reverse-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reversechannel">reverse-channel</a> (:optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+reverse-channel is the <a class=quiet href="#regularizedargs" onmouseout="UnTip()" onmouseover="Tip(extsnd_regularizedargs_tip)">regularized</a> version of <a href="#reversesound">reverse-sound</a>.
+<!-- INDEX reverseexamples:Reversing -->
+
+<A NAME="reverseexamples"></a>
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<blockquote><small>
+<br>
+reverse selected portion: <a href="#reverseselection">reverse-selection</a><br>
+read samples in reverse: use <a href="#makesampler">make-sampler</a> with direction -1<br>
+reverse at new sampling rate: use <a href="#srcchannel">src-channel</a> with a negative ratio<br>
+Reverse in control panel: <a href="snd.html#speed">control panel</a> and <a href="#speedcontrol">speed-control</a> variable<br>
+reverse an envelope: <a href="sndscm.html#reverseenvelope">reverse-envelope</a><br>
+reverse block-wise: <a href="sndscm.html#reversebyblocks">reverse-by-blocks and reverse-within-blocks</a><br>
+reverse via FFT: <a href="#sillyreverse">silly-reverse</a><br>
+reverse order of channels: <a href="#reversechannels">reverse-channels</a><br>
+reverse a list: reverse and reverse!<br>
+reverse a string: in Guile or Forth: string-reverse, in Ruby: reverse<br>
+reverse a vct: <a href="#vctreverse">vct-reverse!</a><br>
+reverse a frame: <a href="sndscm.html#framereverse">frame-reverse</a><br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+<!-- reverse-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reversesound">reverse-sound</a> (:optional snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+reverse-sound reverses the sound data in the given channel. There are some interesting non-causal effects you can get with this:
+take a voice sound, reverse it, reverberate it, reverse it again, and you get the original with
+reversed reverb. As a hack, you can reverse a sound (modulo a one sample rotation) by doing two ffts
+(DSP-ers call this a "flip"):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<A NAME="sillyreverse">silly-reverse</a> :optional snd)
+ (let* ((len (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> snd 0))
+ (fsize (expt 2 (ceiling (/ (log len) (log 2)))))
+ (rl (<a class=quiet href="#channeltovct" onmouseout="UnTip()" onmouseover="Tip(extsnd_channeltovct_tip)">channel-&gt;vct</a> 0 fsize snd 0))
+ (im (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> fsize)))
+ (<a class=quiet href="sndclm.html#fft" onmouseout="UnTip()" onmouseover="Tip(sndclm_fft_tip)">mus-fft</a> rl im fsize)
+ (<a class=quiet href="sndclm.html#fft" onmouseout="UnTip()" onmouseover="Tip(sndclm_fft_tip)">mus-fft</a> rl im fsize)
+ (<a class=quiet href="#vctscale" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctscale_tip)">vct-scale!</a> rl (/ 1.0 fsize))
+ (<a class=quiet href="#vcttochannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_vcttochannel_tip)">vct-&gt;channel</a> (<a class=quiet href="#vctsubseq" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctsubseq_tip)">vct-subseq</a> rl (- fsize len) fsize) 0 len snd 0)))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- revert-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="revertsound">revert-sound</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+This reverts 'snd' to its saved (unedited) state. A channel-specific version:
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (revert-channel :optional snd chn)
+ (set! (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> snd chn) 0))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- right-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="rightsample">right-sample</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This returns the position (in samples) of right edge of the time domain waveform. See <a href="#leftsample">left-sample</a>,
+<a href="#moveonepixel">move-one-pixel</a>, and many examples in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- run -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="run">run</a> (thunk)</code>
+</td></tr><tr><td></td><td>
+run is the Snd equivalent of the CL/CLM run macro. You can wrap it around a numerically-intensive
+block of code, and the result will usually run 10 to 20 times faster. In the context of <a href="sndscm.html#wsdoc">with-sound</a>, run is used
+to speed up instrument bodies. My timing tests indicate that Snd+Run instruments are within a factor of two to four
+of the speed of CL+run+C in CLM. Currently, only s7 supports this optimization.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (ws-sine freq)
+ (let ((o (<a class=quiet href="sndclm.html#make-oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_oscil_tip)">make-oscil</a> freq)))
+ (<em class=red>run</em>
+ (lambda ()
+ (do ((i 0 (+ 1 i)))
+ ((= i 100))
+ (<a class=quiet href="sndclm.html#outa" onmouseout="UnTip()" onmouseover="Tip(sndclm_outa_tip)">outa</a> i (<a class=quiet href="sndclm.html#oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_oscil_tip)">oscil</a> o)))))))
+</pre></td></tr></table>
+
+<A NAME="declare"></A>
+Functions embedded within run may need to declare the type of their arguments; run assumes each variable has one type (integer by default) throughout its life.
+So, the following code
+displays "0", rather than "3.14":
+
+<pre>
+ (run (lambda () (let ((x 3.14)) (define (a b) (display b)) (a x))))
+</pre>
+
+The "b" argument to "a" is assumed to be an integer, and passing in a float
+causes nothing but confusion. To get this code to work right:
+
+<pre>
+ (run (lambda () (let ((x 3.14)) (define (a b) (<em class=red>declare</em> (b real)) (display b)) (a x))))
+</pre>
+
+The current declarable types include any <a href="sndscm.html#def-clm-struct">def-clm-struct</a> type and:
+
+<pre>
+ int float boolean char string list symbol keyword vct sampler mix-sampler
+ sound-data clm float-vector int-vector vct-vector list-vector clm-vector
+</pre>
+
+declare is modelled after Common Lisp's declare; it is specific to run.
+<br><br>
+The use of the run macro is hidden in many contexts: <a class=quiet href="#mapchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_mapchannel_tip)">map-channel</a>,
+<a class=quiet href="#findchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_findchannel_tip)">find-channel</a>, etc. Internally the Snd run macro
+uses 64-bit ints and doubles, so large sounds should not present any numerical problems.
+See <a href="#optimization">optimization</a>
+for some timings. In Ruby, it's possible to use the <a href="http://www.zenspider.com/Languages/Ruby/">RubyInline</a> module instead.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sample">sample</a> (:optional samp snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+This function gives the value of sample 'samp' in the given channel.
+<pre>
+ Scheme: (set! (sample 100) .5)
+
+ Ruby: set_sample(100, 0.5)
+
+ Forth: 100 0.5 set-sample
+</pre>
+If the desired sample happens to fall outside the current buffer
+for the indicated channel, sample grinds to a halt &mdash; if you're
+running a loop through a bunch of samples, use the <a href="#samplers">samplers</a>
+or <a href="#channeltovct">channel-&gt;vct</a> instead. 'samp' defaults to the current cursor location.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- samples -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="samples">samples</a> (:optional samp samps snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+This returns a vct of 'samps' samples starting at 'samp' in the given channel.
+'samp' defaults to 0. 'samps' defaults to frames - 'samp' (i.e. read to the end of the data).
+'pos' is the edit history position to read (it defaults to the current position).
+This is settable (as is <a href="#sample">sample</a>):
+<pre>
+ <em class=listener>:</em><em class=typing>(samples 1000 10)</em>
+ <em class=listener>#&lt;vct[len=10]: 0.033 0.035 0.034 0.031 0.026 0.020 0.013 0.009 0.005 0.004&gt;</em>
+ <em class=listener>:</em><em class=typing>(set! (samples 1000 10) (make-vct 10 .1))</em>
+ <em class=listener>#&lt;vct[len=10]: 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- save-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="savesound">save-sound</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+save-sound saves 'snd', writing the current state of the sound to its underlying sound file, (like the File menu's Save option).
+<a href="#savehook">save-hook</a> is invoked upon save-sound. After save-sound, the sound has no undoable edits in its edit history
+(this is different from Emacs, but I find Emac's way of handling this very confusing, and it's never what I want).
+
+<!-- INDEX saveexamples:Saving -->
+
+<A NAME="saveexamples"></a>
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<small><blockquote>
+save all sounds: <code>(for-each save-sound (sounds))</code><br>
+save a sound under a different name: <a href="#savesoundas">save-sound-as</a><br>
+extract one channel from a sound: <a href="#extractchannel">extract-channel</a><br>
+extract a set of channels from a sound: <a href="#extractchannels">extract-channels</a><br>
+save a sound in a different format or header: <a href="#savesoundas">save-sound-as</a><br>
+backup edits automatically: <a href="sndscm.html#autosave">autosave</a><br>
+check first for unsaved edits: <a href="sndscm.html#checkforunsavededits">check-for-unsaved-edits</a><br>
+save Snd's complete state (unsaved edits and all): <a href="#savestate">save-state</a>, <a href="#savedir">save-dir</a>, <a href="#savestatehook">save-state-hook</a>, <a href="#savestatefile">save-state-file</a><br>
+save the selection: <a href="#saveselection">save-selection</a><br>
+save a region: <a href="#saveregion">save-region</a><br>
+save a mix: <a href="sndscm.html#savemix">save-mix</a><br>
+save the control panel state: <a href="#savecontrols">save-controls</a><br>
+save currently defined envelopes (envelope editor): <a href="#saveenvelopes">save-envelopes</a><br>
+start the file save dialog: <a href="#savesounddialog">save-sound-dialog</a><br>
+start the selection save dialog: <a href="#saveselectiondialog">save-selection-dialog</a><br>
+start the region save dialog: <a href="#saveregiondialog">save-region-dialog</a><br>
+use Emacs-style save-as behavior: <a href="sndscm.html#emacsstylesaveas">emacs-style-save-as</a><br>
+save the current listener text: <a href="#savelistener">save-listener</a><br>
+save keyboard macros: <a href="#savemacros">save-macros</a><br>
+save marks: <a href="#savemarks">save-marks</a><br>
+save just the edit history: <a href="#saveedithistory">save-edit-history</a><br>
+save the peak-env data: <a href="sndscm.html#peakenvdoc">save-peak-env-info</a><br>
+take some action upon a window manager save-yourself signal: <a href="sndscm.html#uponsaveyourself">upon-save-yourself</a><br>
+save the current sound setup for a later reopen: <a href="sndscm.html#remembersoundstate">remember-sound-state</a><br>
+save the current fft peak info: <a href="#peaks">peaks</a><br>
+</blockquote></small>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- save-sound-as -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="savesoundas">save-sound-as</a> (<a class=quiet href="sndclm.html#optional-key" onmouseout="UnTip()" onmouseover="Tip(sndclm_optional_key_tip)">&amp;optional-key</a> :file :sound :header-type :data-format :srate :channel :edit-position :comment)</code>
+</td></tr><tr><td></td><td>
+This saves 'sound' as 'file' (like the 'File:Save as' menu option). If 'channel' is specified,
+only that channel is saved (it is extracted if necessary from the multichannel original).
+'edit-position', if given, specifies which edit history position to save.
+The :srate argument refers only to the new sound file's header's srate field;
+the data is not resampled. If you want to resample the data as it is saved, see
+the example under <a href="#beforesaveashook">before-save-as-hook</a>. If :data-format
+is given, the sound file is written using that data format.
+Any omitted argument's value
+is taken from the sound being saved. save-sound-as returns the new file name.
+<pre>
+ (save-sound-as "test.snd" :data-format mus-bdouble :header-type mus-aifc)
+</pre>
+saves the currently selected sound as an AIFC file using big-endian doubles for the samples.
+<br><br>
+To start a parallel editing branch on a given file, you could:
+<pre>
+ (save-sound-as "test.snd") (<a class=quiet href="#opensound" onmouseout="UnTip()" onmouseover="Tip(extsnd_opensound_tip)">open-sound</a> "test.snd")
+</pre>
+
+To define an explicit channel extraction function:<br>
+<pre>
+ Scheme:
+ (define (<a name="extractchannel">extract-channel</a> filename snd chn) (<em class=red>save-sound-as</em> filename snd :channel chn))
+
+ Ruby:
+ def extract_channel(filename, snd, chn) save_sound_as(filename, snd, :channel, chn) end
+
+ Forth:
+ : extract-channel { filename snd chn } filename snd :channel chn save-sound-as ;
+</pre>
+The hooks called during a save operation are:
+<pre>
+ <a class=quiet href="#beforesaveashook" onmouseout="UnTip()" onmouseover="Tip(extsnd_beforesaveashook_tip)">before-save-as-hook</a> &mdash; can cancel the request or set its output parameters
+ <a class=quiet href="#savehook" onmouseout="UnTip()" onmouseover="Tip(extsnd_savehook_tip)">save-hook</a>
+ sound saved
+ if any sample is clipped during save, <a class=quiet href="#cliphook" onmouseout="UnTip()" onmouseover="Tip(extsnd_cliphook_tip)">clip-hook</a>
+ <a class=quiet href="#aftersaveashook" onmouseout="UnTip()" onmouseover="Tip(extsnd_aftersaveashook_tip)">after-save-as-hook</a>
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- scale-by -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="scaleby">scale-by</a> (scalers :optional snd chn)</code>
+</td></tr><tr><td></td><td>
+scale-by <a href="snd.html#scaling">scales</a> the amplitude of 'snd' by 'scalers'. Unlike most of these functions,
+scale-by follows the 'sync' buttons and affects all currently sync'd
+channels. 'scalers' can be either a float, a list, or a vct.
+In the latter case, the values are used one by one, applying each as
+scale-by moves through the channels. If 'sync' is off, channel 'chn'
+is scaled (it defaults to the currently selected channel). <code>(scale-by 2.0)</code> doubles all samples.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- scale-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="scalechannel">scale-channel</a> (scl :optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+scale-channel
+scales (changes the amplitude) of a sound by 'scl'.
+The multichannel version is <a href="sndscm.html#scalesound">scale-sound</a> in frame.scm.
+<a href="sndscm.html#channelpolynomial">channel-polynomial</a> is a generalization of the idea.
+There are approximately a bazillion ways to scale samples in Snd; here's a potpourri of increasingly silly choices:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(scale-channel 2.0)
+(<a class=quiet href="#scaleby" onmouseout="UnTip()" onmouseover="Tip(extsnd_scaleby_tip)">scale-by</a> 2.0)
+(<a class=quiet href="#mapchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_mapchannel_tip)">map-channel</a> (lambda (val) (* val 2.0)))
+(set! (<a class=quiet href="#maxamp" onmouseout="UnTip()" onmouseover="Tip(extsnd_maxamp_tip)">maxamp</a>) (* 2 (<a class=quiet href="#maxamp" onmouseout="UnTip()" onmouseover="Tip(extsnd_maxamp_tip)">maxamp</a>)))
+(<a class=quiet href="#envsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_envsound_tip)">env-sound</a> '(0 2 1 2))
+(<a class=quiet href="#envchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_envchannel_tip)">env-channel</a> (<a class=quiet href="sndclm.html#make-env" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_env_tip)">make-env</a> '(0 1 1 1) :scaler 2.0 :length (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>)))
+(<a class=quiet href="#clmchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_clmchannel_tip)">clm-channel</a> (<a class=quiet href="sndclm.html#make-one-zero" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_one_zero_tip)">make-one-zero</a> :a0 2.0 :a1 0.0))
+(<a class=quiet href="#filterchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_filterchannel_tip)">filter-channel</a> (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> 2.0) 1)
+(<a class=quiet href="#vcttochannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_vcttochannel_tip)">vct-&gt;channel</a> (<a class=quiet href="#vctscale" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctscale_tip)">vct-scale!</a> (<a class=quiet href="#channeltovct" onmouseout="UnTip()" onmouseover="Tip(extsnd_channeltovct_tip)">channel-&gt;vct</a>) 2.0) 0)
+(<a class=quiet href="sndscm.html#sounddatatosound" onmouseout="UnTip()" onmouseover="Tip(sndscm_sounddatatosound_tip)">sound-data-&gt;sound</a> (<a class=quiet href="#sounddata*" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounddata_times_tip)">sound-data*</a> (<a class=quiet href="sndscm.html#soundtosounddata" onmouseout="UnTip()" onmouseover="Tip(sndscm_soundtosounddata_tip)">sound-&gt;sound-data</a>) 2.0))
+(begin (<a class=quiet href="#selectall" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectall_tip)">select-all</a>) (<a class=quiet href="#mixselection" onmouseout="UnTip()" onmouseover="Tip(extsnd_mixselection_tip)">mix-selection</a> 0))
+(begin (<a class=quiet href="#selectall" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectall_tip)">select-all</a>) (<a class=quiet href="#scaleselectionby" onmouseout="UnTip()" onmouseover="Tip(extsnd_scaleselectionby_tip)">scale-selection-by</a> 2.0))
+(begin (<a class=quiet href="#savesoundas" onmouseout="UnTip()" onmouseover="Tip(extsnd_savesoundas_tip)">save-sound-as</a> "temp.snd") (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> "temp.snd" 0) (delete-file "temp.snd"))
+
+(let ((flt (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> 8)))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> flt 0 2.0)
+ (let ((cnv (<a class=quiet href="sndclm.html#make-convolve" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_convolve_tip)">make-convolve</a> :filter flt))
+ (sf (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> 0)))
+ (<a class=quiet href="#mapchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_mapchannel_tip)">map-channel</a>
+ (lambda (val)
+ (<a class=quiet href="sndclm.html#convolve" onmouseout="UnTip()" onmouseover="Tip(sndclm_convolve_tip)">convolve</a> cnv (lambda (dir)
+ (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> sf)))))))
+
+(<a class=quiet href="#vcttochannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_vcttochannel_tip)">vct-&gt;channel</a> (<a class=quiet href="sndscm.html#polydoc" onmouseout="UnTip()" onmouseover="Tip(sndscm_poly_times_tip)">poly*</a> (<a class=quiet href="#channeltovct" onmouseout="UnTip()" onmouseover="Tip(extsnd_channeltovct_tip)">channel-&gt;vct</a> 0 (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>)) (<a class=quiet href="#vct" onmouseout="UnTip()" onmouseover="Tip(extsnd_vct_tip)">vct</a> 2.0))) ; poly.scm (sound = polynomial coeffs)
+
+(let* ((len (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>))
+ (fsize (expt 2 (ceiling (/ (log len) (log 2)))))
+ (rl (<a class=quiet href="#channeltovct" onmouseout="UnTip()" onmouseover="Tip(extsnd_channeltovct_tip)">channel-&gt;vct</a> 0 fsize))
+ (im (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> fsize)))
+ (<a class=quiet href="sndclm.html#fft" onmouseout="UnTip()" onmouseover="Tip(sndclm_fft_tip)">mus-fft</a> rl im fsize)
+ (<a class=quiet href="sndclm.html#fft" onmouseout="UnTip()" onmouseover="Tip(sndclm_fft_tip)">mus-fft</a> rl im fsize)
+ (<a class=quiet href="sndclm.html#fft" onmouseout="UnTip()" onmouseover="Tip(sndclm_fft_tip)">mus-fft</a> rl im fsize)
+ (<a class=quiet href="sndclm.html#fft" onmouseout="UnTip()" onmouseover="Tip(sndclm_fft_tip)">mus-fft</a> rl im fsize)
+ (<a class=quiet href="#vcttochannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_vcttochannel_tip)">vct-&gt;channel</a> (<a class=quiet href="#vctscale" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctscale_tip)">vct-scale!</a> rl (/ 2.0 (* fsize fsize))) 0 len))
+
+(do ((i 0 (+ 1 i)))
+ ((= i (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>)))
+ ;; don't actually do this! &mdash; it involves a separate edit on each sample
+ (set! (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> i) (* 2 (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> i))))
+
+(let ((make-scaler
+ (lambda (start end)
+ (letrec ((ctr start)
+ (us (lambda (them)
+ (set! (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> ctr) (* 2.0 (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> ctr)))
+ (set! ctr (+ ctr 2))
+ (if (&lt;= ctr end)
+ (them us)))))
+ us))))
+ ((make-scaler 0 (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>))
+ (make-scaler 1 (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>))))
+</pre></td></tr></table>
+</td></tr>
+
+<!-- another method that is a bit too verbose: array-interp with a ramp of slope 2
+ a similar table of ways to make a sine wave?
+ sin oscil Table-lookup polyshape ifft(spike) firmant(r=1.0), ssb-am+? formulas?
+-->
+
+<tr><td colspan=2 height=18></td></tr>
+
+
+<!-- scale-to -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="scaleto">scale-to</a> (:optional norms snd chn)</code>
+</td></tr><tr><td></td><td>
+scale-to <a href="snd.html#scaling">normalizes</a> 'snd' to 'norms' (following <a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> as in <a href="#scaleby">scale-by</a>).
+<code>(scale-to 0.5)</code> scales the current channel so that its maxamp is 0.5.
+If all the sound's samples are 0.0, scale-to returns #f and does not perform any edit.
+'norms' can be a number, a list of numbers, or a vct.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- scan-chan -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def>scan-chan</a> (func :optional start end snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+scan-chan applies 'func' to samples in the specified channel.
+It is the old ("irregular") version of <a href="#scanchannel">scan-channel</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- scan-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="scanchannel">scan-channel</a> (func :optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+scan-channel "scans" the data in the specified channel between the given sample numbers (the default
+is the entire sound) by applying 'func' to each sample.
+If 'func' returns something other than #f, the scan is halted,
+and a list is returned
+containing that value and the current sample position of the
+scan. The following call scans the
+current channel from sample 0 to the end looking for any sample greater than
+.1:<br>
+<pre>
+&gt;<em class=typing>(scan-channel (lambda (y) (&gt; y .1)))</em>
+<em class=listener>(#t 4423)</em>
+</pre>
+In this case, we found such a sample at position 4423.<br>
+<pre>
+(define every-sample?
+ (lambda (proc)
+ (let ((baddy (<em class=red>scan-channel</em> (lambda (y)
+ (not (proc y))))))
+ (if baddy (set! (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) (cadr baddy)))
+ (not baddy))))
+
+&gt;<em class=typing>(every-sample? (lambda (y) (&lt; y .5)))</em>
+<em class=listener>#t</em>
+</pre>
+To scan all the channels of a multichannel sound in parallel, see
+<a href="sndscm.html#scansound">scan-sound</a>.
+<br><br>
+In scan-chan, scan-channel, find, and count-matches (all the same underlying procedure), an attempt to jump back
+into a previous call will not work. That is,
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(let ((not-a-good-idea #f))
+ (<em class=red>scan-channel</em> (lambda (y)
+ (call-with-current-continuation
+ (lambda (call)
+ (set! not-a-good-idea call)))
+ (&gt; y .001)))
+ (not-a-good-idea))
+</pre></td></tr></table>
+
+will die with a segfault (this is fixable, with much effort and grumbling). If you want a continuable search, use a sampler:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define reader #f)
+(define last-proc #f)
+(define (<A NAME="scanagain">scan-again</a>)
+ (if (<a class=quiet href="#sampleratendQ" onmouseout="UnTip()" onmouseover="Tip(extsnd_sampleratendQ_tip)">sampler-at-end?</a> reader)
+ #f
+ (let ((val (last-proc (reader))))
+ (if val
+ (list val (- (<a class=quiet href="#samplerposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_samplerposition_tip)">sampler-position</a> reader) 1))
+ (scan-again)))))
+(define (my-scan-chan proc)
+ (set! last-proc proc)
+ (set! reader (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> 0))
+ (scan-again))
+</pre></td></tr></table>
+
+Now <code>(my-scan-chan (lambda (y) (&gt; y .1)))</code> finds the first such sample, and
+subsequent <code>(scan-again)</code> calls continue the search where the last call left off.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- search-procedure -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="searchprocedure">search-procedure</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+This gives the current global or sound-local (if 'snd' is specified) search procedure.
+<pre>
+ (set! (<a class=quiet href="#searchprocedure" onmouseout="UnTip()" onmouseover="Tip(extsnd_searchprocedure_tip)">search-procedure</a>) (lambda (y) (&gt; y .1)))
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- selected-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="selectedchannel">selected-channel</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+This gives the selected channel in 'snd'; you can set it to select a channel. It returns #f is no channel is selected in 'snd'.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- selected-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="selectedsound">selected-sound</a> ()</code>
+</td></tr><tr><td></td><td>
+This returns the currently selected sound; you can set it to select a sound. It returns #f is there is no selected sound.
+<pre>
+ (or (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>)
+ (and (not (null? (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>)))
+ (car (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+</pre>
+returns the currently selected sound, if any, and failing that, any other sound that is currently open.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- select-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="selectchannel">select-channel</a> (:optional chn)</code>
+</td></tr><tr><td></td><td>
+This selects channel 'chn' in the currently selected sound;
+equivalent to <code>(set! (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>) chn)</code>.
+See also <a href="#selectchannelhook">select-channel-hook</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- select-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="selectsound">select-sound</a> snd</code>
+</td></tr><tr><td></td><td>
+This selects sound 'snd' (a sound object or an index); equivalent to <code>(set! (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) snd)</code>.
+See also <a href="#selectsoundhook">select-sound-hook</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- set-samples -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="setsamples">set-samples</a> (samp samps data :optional snd chn trunc edname infile-chan edpos auto-delete)</code>
+</td></tr><tr><td></td><td>
+set-samples (and its related (set! (samples...)...) form) set the given channel's samples starting from
+sample 'samp' for 'samps' samples to the values in 'data'.
+<pre>
+ (set! (samples 0 100) (make-vct 100 .1))
+ (set-samples 0 100 (make-vct 100 .1))
+
+</pre>
+both change all samples between 0 and 100 to be 0.1.
+If 'samp' is beyond the end of the file, the file is first zero-padded to reach it.
+'data' can be a filename.
+<pre>
+ (set-samples 10000 20000 "oboe.snd")
+</pre>
+replaces 10000 samples with data from oboe.snd.
+If 'data' is a vct, set-samples is identical to <a href="#vcttochannel">vct-&gt;channel</a>.
+If 'trunc' is #t and 'samp' is 0, the
+sound is truncated (if necessary) to reflect the end of 'data'.
+If the in-coming data file has more than one channel, 'infile-chan'
+sets which input file to read. The in-coming data file is not deleted by Snd
+unless 'auto-delete' is #t. (If you write a temporary sound
+as an edit, it can be non-obvious when it is safe to delete that
+file; 'auto-delete' set to #t asks Snd to handle cleanup).
+<br><br>
+The form (set! (<a class=quiet href="#samples" onmouseout="UnTip()" onmouseover="Tip(extsnd_samples_tip)">samples</a> samp samps 'snd chn trunc edname infile-chan edpos auto-delete') data) can also be used.
+'env-sound-interp' in examp.scm has an example of the file version, using
+sound-data objects and mus-sound-write to create a temporary file, but
+it's probably simpler to use <a href="sndscm.html#withsound">with-sound</a> (see also linear-src-channel in dsp.scm):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (step-src)
+ (let* ((rd (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> 0))
+ (o (<a class=quiet href="sndclm.html#make-oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_oscil_tip)">make-oscil</a> 2205.0))
+ (s (<a class=quiet href="sndclm.html#make-src" onmouseout="UnTip()" onmouseover="Tip(sndclm_make_src_tip)">make-src</a> :srate 0.0))
+ (incr (+ 2.0 (<a class=quiet href="sndclm.html#oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_oscil_tip)">oscil</a> o)))
+ (tempfile (<em class=red>with-sound</em> (:output (<a class=quiet href="#sndtempnam" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndtempnam_tip)">snd-tempnam</a>) :srate (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>) :to-snd #f)
+ (<a class=quiet href="sndscm.html#run" onmouseout="UnTip()" onmouseover="Tip(sndscm_run_tip)">run</a> (lambda ()
+ (do ((samp 0 (+ 1 samp)))
+ ((or (c-g?) (<a class=quiet href="#sampleratendQ" onmouseout="UnTip()" onmouseover="Tip(extsnd_sampleratendQ_tip)">sampler-at-end?</a> rd)))
+ (<a class=quiet href="sndclm.html#out-any" onmouseout="UnTip()" onmouseover="Tip(sndclm_out_any_tip)">out-any</a> samp (<a class=quiet href="sndclm.html#src" onmouseout="UnTip()" onmouseover="Tip(sndclm_src_tip)">src</a> s incr (lambda (dir) (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> rd))) 0)
+ (if (= (modulo samp 2205) 0)
+ (set! incr (+ 2.0 (<a class=quiet href="sndclm.html#oscil" onmouseout="UnTip()" onmouseover="Tip(sndclm_oscil_tip)">oscil</a> o)))))))))
+ (len (<a class=quiet href="#mussoundframes" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundframes_tip)">mus-sound-frames</a> tempfile)))
+ (<em class=red>set-samples</em> 0 (- len 1) tempfile #f #f #t "step-src" 0 #f #t)))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- short-file-name -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="shortfilename">short-file-name</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This returns the brief (no directory) form of the sound's filename.
+
+<pre>
+ &gt;<em class=typing>(open-sound "oboe.snd")</em>
+ <em class=listener>#&lt;sound 0&gt;</em>
+ &gt;<em class=typing>(file-name (integer-&gt;sound 0))</em>
+ <em class=listener>"/home/bil/cl/oboe.snd"</em>
+ &gt;<em class=typing>(short-file-name (integer-&gt;sound 0))</em>
+ <em class=listener>"oboe.snd"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- show-axes -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="showaxes">show-axes</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This determines what axes are displayed.
+If show-axes is <code>show-all-axes</code> (the default), both the x and y axes are displayed; if it is <code>show-x-axis</code>,
+just one (bottom) x axis is displayed, reducing screen clutter.
+<code>show-no-axes</code> omits both x and y axes. To remove the x axis label, use
+either <code>show-x-axis-unlabelled</code> or <code>show-all-axes-unlabelled</code>.
+To omit all the x axis labels and ticks (but include the y axis as usual) use <code>show-bare-x-axis</code>.
+This is the View:Axes choice.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- show-grid -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="showgrid">show-grid</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If show-grid is #t (the default is #f), a background grid is displayed (default is #f). See also <a href="#griddensity">grid-density</a>.
+<br><br>
+<img src="pix/grid.png" alt="grid" onmouseout="UnTip()" onmouseover="Tip('<pre>snd -horizontal now.snd now.snd<br>(set! (show-grid) #t)<br>(set! (grid-density 1) 0.2)</pre>')">
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+<!--
+./snd -horizontal now.snd now.snd
+(set! (grid-density 1) 0.2)
+(set! (selected-graph-color) (make-color 1 1 1))
+(set! (selected-data-color) (make-color 0 0 0))
+(set! (x-axis-label 1 0) "grid-density: 0.2")
+(set! (x-axis-label 1 0) "grid-density: 0.2")
+-->
+
+
+<!-- show-marks -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="showmarks">show-marks</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If show-marks is #t (the default), marks are displayed. This is the '<a href="snd.html#marks">Show marks</a>' View menu option.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- show-mix-waveforms -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="showmixwaveforms">show-mix-waveforms</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If show-mix-waveforms is #t (the default), a mixed sound is displayed as a separate waveform above the main data. The rectangular tag
+at the start of the waveform can be dragged to move the mix, or clicked to select it for the mix dialog.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- show-sonogram-cursor -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="showsonogramcursor">show-sonogram-cursor</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If show-sonogram-cursor is #t (the default is #f), the cursor is also displayed in the sonogram.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- show-transform-peaks -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="showtransformpeaks">show-transform-peaks</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If show-transform-peaks is #t (the default is #f), transform peak information is included in the transform display.
+This is the 'peaks' button in the <a href="snd.html#viewfft">Transform</a> options dialog.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- show-y-zero -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="showyzero">show-y-zero</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If show-y-zero is #t (the default is #f), the y=0 axis is displayed. This is the '<a href="snd.html#viewy0">Show Y=0</a>' View menu option.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- smooth-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="smoothchannel">smooth-channel</a> (:optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+smooth-channel is the <a class=quiet href="#regularizedargs" onmouseout="UnTip()" onmouseover="Tip(extsnd_regularizedargs_tip)">regularized</a> version of <a href="#smoothsound">smooth-sound</a>.
+smooth-channel-via-ptree in examp.scm is the virtual form.
+
+<!-- INDEX smoothexamples:Smoothing -->
+
+<A NAME="smoothexamples"></a>
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<small><blockquote>
+smooth all channels: <a href="#smoothsound">smooth-sound</a><br>
+smooth selection: <a href="#smoothselection">smooth-selection</a><br>
+delete the selection and smooth the splice: <a href="sndscm.html#deleteselectionandsmooth">delete-selection-and-smooth</a><br>
+smoothing as virtual op: smooth-channel-via-ptree in examp.scm<br>
+smoothing via fft: <a href="sndscm.html#fftsmoother">fft-smoother</a><br>
+smooth via low-pass <a href="#filtersinsnd">filter</a><br>
+smooth over click: <a href="sndscm.html#removeclicks">remove-clicks</a> in examp.scm<br>
+</blockquote></small>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- smooth-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="smoothsound">smooth-sound</a> (beg num :optional snd chn)</code>
+</td></tr><tr><td></td><td>
+smooth-sound applies a smoothing function to the indicated data. This produces a sinusoid between
+the end points:
+
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (smoother y0 y1 num)
+ "go sinusoidally from y0 to y1 over num samps"
+ (let ((v (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> (+ 1 num)))
+ (angle (if (&gt; y1 y0) pi 0.0))
+ (off (* .5 (+ y0 y1)))
+ (scale (* 0.5 (abs (- y1 y0)))))
+ (do ((i 0 (+ 1 i)))
+ ((= i num) v)
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> v i
+ (+ off (* scale (cos (+ angle (* i (/ pi num))))))))))
+</pre></td></tr></table>
+
+<img src="pix/click.png" alt="smoother">
+<br>
+For a fancier version, see fft-smoother in examp.scm. See also <a href="sndscm.html#removeclicks">remove-clicks</a> in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- sound? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="soundp">sound?</a> snd</code>
+</td></tr><tr><td></td><td>
+sound? returns #t if 'snd' refers to an open sound.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- soundfont-info -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="soundfontinfo">soundfont-info</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+This returns a list of lists describing 'snd' as a soundfont. Each inner list
+consists of the sound name, start point, loop start, and loop end.
+<pre>
+ :<em class=typing>(soundfont-info)</em>
+ <em class=listener>(("BrSteel_E4" 0 65390 65458) ("BrSteel_B2" 65490 131458 131637) ...)</em>
+</pre>
+To set a named mark at the start of each sound with un-named marks
+at the loop points:
+
+<table border=0 cellpadding=10><tr><td>
+<table border=0><tr><td><pre>
+(define (mark-sf2)
+ (letrec
+ ((sf2it
+ (lambda (lst)
+ (if (not (null? lst))
+ (let* ((vals (car lst))
+ (m1 (<a class=quiet href="#addmark" onmouseout="UnTip()" onmouseover="Tip(extsnd_addmark_tip)">add-mark</a> (cadr vals))))
+ (set! (<a class=quiet href="#markname" onmouseout="UnTip()" onmouseover="Tip(extsnd_markname_tip)">mark-name</a> m1) (car vals)))
+ (<a class=quiet href="#addmark" onmouseout="UnTip()" onmouseover="Tip(extsnd_addmark_tip)">add-mark</a> (caddr vals))
+ (<a class=quiet href="#addmark" onmouseout="UnTip()" onmouseover="Tip(extsnd_addmark_tip)">add-mark</a> (cadddr vals))
+ (sf2it (cdr lst))))))
+ (sf2it (<em class=red>soundfont-info</em>))))
+</pre></td></tr></table>
+</td><td>
+<img src="pix/bongo.png" alt="soundfont marks">
+</td></tr></table>
+
+See also explode-sf2 in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- sound->integer -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="soundtointeger">sound->integer</a> (sound)</code>
+</td></tr><tr><td></td><td>
+This is the counterpart to <a href="#integertosound">integer-&gt;sound</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-loop-info -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="soundloopinfo">sound-loop-info</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+This gives info about loop points from the sound's header. The loop info is a list of
+up to 4 points, the first two (start, end) refer to the sustain loop,
+the second two to the release. The 5th and 6th list entries are the base note and detune values.
+For historical reasons, the 7th and 8th entries are the sustain and release modes.
+This is similar to <a href="#mussoundloopinfo">mus-sound-loop-info</a> (but it's settable). See explode-sf2 in examp.scm.
+<pre>
+ :<em class=typing>(sound-loop-info)</em>
+ <em class=listener>(24981 144332 0 0 60 0 1 0)</em>
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- sound-properties -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="soundproperties">sound-properties</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+This is a property list associated with the given sound. It is set to '() at the time a sound is opened. The accessor
+<a href="sndscm.html#soundproperty">sound-property</a> is provided in extensions.scm. There are several
+examples of using it in snd-motif.scm and autosave.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- sounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sounds">sounds</a> ()</code>
+</td></tr><tr><td></td><td>
+sounds returns a list of currently active sounds.
+A common Snd trope is (map func (sounds)):
+<pre>
+ (map maxamp (sounds))
+</pre>
+Or, if
+the return value is not needed:
+<pre>
+ (for-each (lambda (snd) (display (<a class=quiet href="#shortfilename" onmouseout="UnTip()" onmouseover="Tip(extsnd_shortfilename_tip)">short-file-name</a> snd))) (sounds))
+</pre>
+This can be
+extended to provide a complete list of sounds and channels (since many Snd functions
+take the "snd chn" arguments):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (all-chans)
+ (let ((sndlist '())
+ (chnlist '()))
+ (for-each (lambda (snd)
+ (do ((i (- (<a class=quiet href="#channels" onmouseout="UnTip()" onmouseover="Tip(extsnd_channels_tip)">channels</a> snd) 1) (- i 1)))
+ ((&lt; i 0))
+ (set! sndlist (cons snd sndlist))
+ (set! chnlist (cons i chnlist))))
+ (<em class=red>sounds</em>))
+ (list sndlist chnlist)))
+
+(apply map <a class=quiet href="#maxamp" onmouseout="UnTip()" onmouseover="Tip(extsnd_maxamp_tip)">maxamp</a> (all-chans))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectrum-end -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectrumend">spectrum-end</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the amount of the frequency domain to include in the spectrum
+display (the default is 1.0 = all of it).
+spectrum-end the slider labelled '% of spectrum' in the View
+Orientation dialog. See zoom-fft in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectro-hop -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectrohop">spectro-hop</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the distance (in pixels) moved between successive spectrogram traces
+(default is 4). spectro-hop is the 'hop' slider in the Color/Orientation dialog.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectrum-start -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectrumstart">spectrum-start</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the start point of the frequency domain in the spectrum
+display (default is 0.0). See zoom-fft in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectro-x-angle -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectroxangle">spectro-x-angle</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the spectrogram x-axis viewing angle (the default is 90.0 except in GL where it is 300.0). See snd-gl.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectro-x-scale -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectroxscale">spectro-x-scale</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the scaler (stretch amount) along the spectrogram x axis (the is default 1.0, in GL: 1.5).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectro-y-angle -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectroyangle">spectro-y-angle</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the spectrogram y axis viewing angle (the default is 0.0, in GL: 320.0).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectro-y-scale -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectroyscale">spectro-y-scale</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the scaler (stretch amount) for the spectrogram y axis (the default is 1.0).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectro-z-angle -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectrozangle">spectro-z-angle</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the spectrogram viewing angle for the z axis (the default is 358.0, in GL: 0.0).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- spectro-z-scale -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="spectrozscale">spectro-z-scale</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the scaler (stretch amount) for the z axis (the default is 0.1, in GL: 1.0).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- squelch-update -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="squelchupdate">squelch-update</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is #t if graphic updates are currently squelched (turned off). If you're doing a sequence of edits where intermediate
+states aren't of great interest, you can save time by turning off redisplays.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (without-graphics thunk)
+ (set! (<em class=red>squelch-update</em>) #t)
+ (let ((val (catch #t thunk (lambda args (car args)))))
+ (set! (<em class=red>squelch-update</em>) #f)
+ val))
+</pre></td></tr></table>
+</td></tr>
+
+
+<!-- srate -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="srate">srate</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This is the sound's sampling rate. If you set this to a new value, update-sound is called to
+reflect the new srate, but any current edits are simply flushed. This is consistent
+with the other header fields (data-format, etc), but it can be annoying.
+<br><br>
+There are several srates floating around in Snd.
+<code>(srate snd)</code> returns the sampling rate of a particular (currently open) sound.
+<code>(<a class=quiet href="#mussoundsrate" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundsrate_tip)">mus-sound-srate</a> filename)</code> returns a sound file's sampling rate.
+<code>mus-srate</code> is associated with the CLM package (setting the implicit srate for oscil etc).
+<code>default-output-srate</code> is the default sampling rate used when opening new files.
+<code>enved-srate</code> is a constant that can be assigned to the envelope editor's <code>enved-target</code> (to apply an envelope to the sampling rate).
+<code>region-srate</code> is the sampling rate associated with a region.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- src-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="srcchannel">src-channel</a> (num-or-env :optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+src-channel preforms sampling rate conversion using 'warped sinc interpolation'. The
+argument 'num-or-env' can be a number, an envelope, or a CLM env generator.
+<code>(src-channel 2.0)</code> makes the sound go twice as fast.
+This is the <a class=quiet href="#regularizedargs" onmouseout="UnTip()" onmouseover="Tip(extsnd_regularizedargs_tip)">regularized</a> version of <a href="#srcsound">src-sound</a>.
+<pre>
+ <em class=listener>:</em><em class=typing>(frames)</em> ; current duration
+ <em class=listener>50828</em>
+ <em class=listener>:</em><em class=typing>(src-channel 2.0)</em> ; make it half as long
+ <em class=listener>2.0</em>
+ <em class=listener>:</em><em class=typing>(frames)</em>
+ <em class=listener>25415</em>
+ <em class=listener>:</em><em class=typing>(src-channel '(0 .5 1 1))</em> ; start slow and speed up
+ <em class=listener>(0 0.5 1 1)</em>
+ <em class=listener>:</em><em class=typing>(frames)</em>
+ <em class=listener>35235</em>
+ <em class=listener>:</em><em class=typing>(src-channel (make-env '(0 .5 1 1) :length 20000))</em> ; stick at 1 after sample 20000
+ <em class=listener>#&lt;env linear, pass: 35236 (dur: 20000), index: 1, scaler: 1.0000, offset: 0.0000, ...&gt;</em>
+ <em class=listener>:</em><em class=typing>(frames)</em>
+ <em class=listener>42964</em>
+</pre>
+
+
+<!-- INDEX resampleexamples:Resampling -->
+
+<A NAME="resampleexamples"></a>
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<small><blockquote>
+resample all chans: <a href="#srcsound">src-sound</a><br>
+resample selection: <a href="#srcsoundselection">src-selection</a><br>
+resample mix: speed control in <a href="snd.html#mixdialog">Mix dialog</a> (also <a href="#applycontrols">apply-controls</a>)<br>
+resample via drawn envelope: srate in <a href="snd.html#editenvelope">Envelope editor</a><br>
+resample via CLM gen: <a href="sndclm.html#src">src</a><br>
+resample with independent time control (ssb-am): <a href="sndscm.html#ssbbank">ssb-bank</a> in dsp.scm<br>
+resample with independent time control (granulate): expand in <a href="#customcontrols">control panel</a>, <a href="sndscm.html#expsrc">expsrc</a> and <a href="sndscm.html#expsnd">expsnd</a><br>
+resample with independent time control (vocoder): <a href="sndclm.html#phase-vocoder">phase-vocoder</a> (this never works)<br>
+another time stretcher (autocorrelation):<a href="sndscm.html#rubbersound">rubber-sound</a> (this takes forever and rarely works)<br>
+resampling-based sound effects: <a href="sndscm.html#hellodentist">hello-dentist</a>, <a href="sndscm.html#fp">fp</a> ("Forbidden Planet"), flange and chorus in dsp.scm and new-effects.scm<br>
+the digital zipper: <a href="sndscm.html#zipdoc">zipper</a><br>
+resample via FFT: <a href="sndscm.html#downoct">down-oct</a><br>
+resample through env: <a href="sndscm.html#soundinterp">sound-interp</a> and <a href="sndscm.html#envsoundinterp">env-sound-interp</a><br>
+resample through list: <a href="sndscm.html#scratch">scratch</a><br>
+resample step-size through a function: <a href="#setsamples">step-src</a><br>
+predict duration of resampled sound: <a href="sndscm.html#srcduration">src-duration</a><br>
+linear src: linear-src-channel in dsp.scm<br>
+<br>
+</blockquote></small>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- src-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="srcsound">src-sound</a> (num-or-env :optional base snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+src-sound performs sampling rate conversion using 'warped sinc interpolation'. The
+argument 'num-or-env', which sets the ratio between the old and the new srate, can be either a number or an envelope.
+In the latter case, 'base' sets the segment base (the default is 1.0 = linear).
+A value greater than 1.0 causes the sound to be transposed up.
+A value less than 0.0 causes the sound to be reversed.
+<code>(src-sound 2.0)</code> speeds the sound up by a factor
+of 2 (transposes it up an octave), whereas <code>(src-sound 0.5)</code>
+slows it down by the same factor (transposes it down an octave).
+<code>(src-sound '(0 1 1 2))</code> starts at the original speed, then
+gradually increases until, at the end of the sound, it is going
+twice as fast.
+<br><br>
+'num-or-env' can also be a CLM env generator (its duration should
+be the same as the original sound, and its segments should not pass through 0.0). The following function can be used to predict
+how long the resultant note will be given an src envelope:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+;;; find new duration of sound after using env as srate.
+;;; the envelope gives the per-sample increment, so the "tempo"
+;;; is the inverse of that. To get the total new duration,
+;;; we need to integrate the inverse envelope, but a straight
+;;; line in the increment envelope becomes a 1/x curve in the
+;;; tempo curve, so we use log(x) as integral of 1/x and
+;;; take into account the local notion of "x".
+
+(define (<a class=quiet NAME="exsrcduration">src-duration</a> e)
+ (let* ((len (length e))
+ (ex0 (car e))
+ (ex1 (list-ref e (- len 2)))
+ (all-x (- ex1 ex0))
+ (dur 0.0))
+ (do ((i 0 (+ i 2)))
+ ((&gt;= i (- len 2)) dur)
+ (let* ((x0 (list-ref e i))
+ (x1 (list-ref e (+ i 2)))
+ (y0 (list-ref e (+ i 1))) ; 1/x x points
+ (y1 (list-ref e (+ i 3)))
+ (area (if (&lt; (abs (- y0 y1)) .0001)
+ (/ (- x1 x0) (* y0 all-x))
+ (* (/ (- (log y1) (log y0))
+ (- y1 y0))
+ (/ (- x1 x0) all-x)))))
+ (set! dur (+ dur (abs area)))))))
+
+;;; (src-duration '(0 1 1 2)) -&gt; 0.693147180559945
+:;; (src-duration '(0 1 1 .5)) -&gt; 1.38629436111989
+;;; (src-duration '(0 .5 .5 3 .6 1 .7 .1 .8 1.5 1 1)) -&gt; 1.02474349685432
+
+;;; here we're using this in the Snd listener:
+<em class=listener>&gt;</em><em class=typing>(frames)</em>
+<em class=listener>220501</em>
+<em class=listener>&gt;</em><em class=typing>(src-duration '(0 1 1 2))</em>
+<em class=listener>0.693147180559945</em>
+<em class=listener>&gt;</em><em class=typing>(src-sound '(0 1 1 2))</em> ; should be about .693 * 220500 frames
+<em class=listener>(0 1 1 2)</em>
+<em class=listener>&gt;</em><em class=typing>(frames)</em>
+<em class=listener>152842</em>
+<em class=listener>&gt;</em><em class=typing>(/ 152842.0 220501)</em>
+<em class=listener>0.693157854159392</em><em class=typing></em> ; tada!
+</pre></td></tr></table>
+
+The inverse, so to speak, of this is <a href="sndscm.html#srcfitenvelope">src-fit-envelope</a>:
+<pre>
+(define (src-fit-envelope e target-dur)
+ (scale-envelope e (/ (src-duration e) target-dur)))
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- start-playing -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="startplaying">start-playing</a> (:optional chans srate background)</code>
+</td></tr><tr><td></td><td>
+If a <a href="#makeplayer">play-list</a> is waiting, this starts it. 'chans' defaults to 1,
+'srate' defaults to 44100, 'background' defaults to #t. See play.scm or marks.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- start-progress-report -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="startprogressreport">start-progress-report</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This starts a <a href="#progressreport">progress-report</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- stop-player -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="stopplayer">stop-player</a> (player)</code>
+</td></tr><tr><td></td><td>
+This removes 'player' from the current play-list (see <a href="#makeplayer">make-player</a>).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- stop-playing -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="stopplaying">stop-playing</a> (:optional snd)</code>
+</td></tr><tr><td></td><td>
+If 'snd' is playing, this stops it.
+If no argument is given, it stops all playback. See play.scm, popup.scm,
+<a href="#stopplayinghook">stop-playing-hook</a>, or <a href="#stopplayingselectionhook">stop-playing-selection-hook</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- swap-channels -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="swapchannels">swap-channels</a> (:optional snd1 chn1 snd2 chn2 beg dur edpos0 edpos1)</code>
+</td></tr><tr><td></td><td>
+This swaps the indicated channels, between 'beg' and 'beg' + 'dur'.
+In simple cases, this is a virtual operation. swap-channels can be used to change channel order arbitrarily.
+For example, the following function reverses the channel order:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<a name="reversechannels">reverse-channels</a> :optional snd)
+ (let* ((ind (or snd (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (car (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>))))
+ (chns (<a class=quiet href="#channels" onmouseout="UnTip()" onmouseover="Tip(extsnd_channels_tip)">channels</a> ind)))
+ (let ((swaps (inexact-&gt;exact (floor (/ chns 2)))))
+ (<a class=quiet href="#asoneedit" onmouseout="UnTip()" onmouseover="Tip(extsnd_asoneedit_tip)">as-one-edit</a>
+ (lambda ()
+ (do ((i 0 (+ 1 i))
+ (j (- chns 1) (- j 1)))
+ ((= i swaps))
+ (<em class=red>swap-channels</em> ind i ind j)))))))
+</pre></td></tr></table>
+
+Channel rotation is similar, though slightly more work; see scramble-channels in examp.scm.
+Since swap-channels is a virtual operation in many cases, it's worth using it even
+where just a channel copy is desired; <a href="sndscm.html#monotostereo">mono-&gt;stereo</a>
+in extensions.scm for an example.
+Another example is swap-selection-channels in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- sync -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sync">sync</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+sync returns the sound's 'sync' value (an integer, 0 = not sync'd). Several functions (<a href="#scaleby">scale-by</a>, for example), apply to the
+currently selected sound and also to any other sounds that share its sync value. (I later decided that
+this was a bad idea, hence the regularized replacements). Sounds that share a given sync value
+move together when you drag an x-axis slider and so on.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- sync-max -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="syncmax">sync-max</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the maximum <a href="#sync">sync</a> setting seen so far &mdash; it provides a painless way to get a sync value that
+is guaranteed to be unique. To sync all currently open sounds:
+<pre>
+ (let ((new-sync (+ 1 (<em class=red>sync-max</em>))))
+ (for-each (lambda (snd) (set! (<a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> snd) new-sync)) (<a class=quiet href="#sounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_sounds_tip)">sounds</a>)))
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- time-graph? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="timegraphp">time-graph?</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is #t if the time domain graph is being displayed (the 'w' button).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- time-graph-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="timegraphstyle">time-graph-style</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This determines how time-domain data is displayed.
+The choices are:
+<pre>
+ graph-lines graph-dots graph-filled graph-lollipops graph-dots-and-lines
+
+ (set! (time-graph-style 0 4) graph-lollipops)
+</pre>
+<img src="pix/graphstyle.png" alt="graph styles">
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!--
+(with-sound (:channels 5) (do ((i 0 (+ 1 i))) ((= i 5)) (fm-violin 0 .4 (* (+ 1 i) 100) .1 :degree (* i 72))))
+(do ((i 0 (+ 1 i))) ((= i 5)) (set! (time-graph-style 0 i) i))
+(set! (dot-size) 4)
+(set! (selected-graph-color) (make-color 1 1 1))
+(set! (selected-data-color) (make-color 0 0 0))
+(set! (x-axis-label 0 0 0) "graph-lines")
+(set! (x-axis-label 0 1 0) "graph-dots")
+(set! (x-axis-label 0 2 0) "graph-filled")
+(set! (x-axis-label 0 3 0) "graph-dots-and-lines")
+(set! (x-axis-label 0 4 0) "graph-lollipops")
+-->
+
+
+<!-- time-graph-type -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="timegraphtype">time-graph-type</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If time-graph-type is <code>graph-as-wavogram</code>, the time domain waveform is displayed as a
+'<a href="snd.html#wavogram" onmouseout="UnTip()" onmouseover="Tip('<img src=\'pix/wavo.png\' width=\'640\' height=\'250\'>', TITLE, 'graph-as-wavogram', ABOVE, true)">wavogram</a>'.
+The default is <code>graph-once</code>. See also <a href="#wavohop">wavo-hop</a> and <a href="#wavotrace">wavo-trace</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- tracking-cursor-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="trackingcursorstyle">tracking-cursor-style</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the <a href="#cursorstyle">cursor-style</a> in effect when the cursor is tracking playback (<a href="#withtrackingcursor">with-tracking-cursor</a>).
+tracking-cursor-style can be <code>cursor-cross</code> or <code>cursor-line</code>. If you want some other shape,
+use the function choice for cursor-style (that function's third argument can tell you when you're tracking).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- transform-frames -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformframes">transform-frames</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This returns either 0 if there is no transform, <a href="#transformsize">transform-size</a> if
+<a href="#transformgraphtype">transform-graph-type</a> is <code>graph-once</code>,
+or (list spectrum-end time-slices fft-bins) if either a sonogram or a spectrogram is being displayed.
+
+<pre>
+ <em class=listener>:</em><em class=typing>(set! (transform-graph?) #t)</em> ; turn on fft display
+ <em class=listener>#t</em>
+ <em class=listener>:</em><em class=typing>(transform-frames)</em>
+ <em class=listener>512</em>
+ <em class=listener>:</em><em class=typing>(set! (transform-graph-type) graph-as-sonogram)</em>
+ <em class=listener>1</em> ; 1 = graph-as-sonogram
+ <em class=listener>:</em><em class=typing>(transform-frames)</em>
+ <em class=listener>(1.0 375 256)</em> ; 1.0 -&gt; full spectrum displayed
+ <em class=listener>:</em><em class=typing>(set! (transform-graph?) #f)</em> ; turn off fft display
+ <em class=listener>#f</em>
+ <em class=listener>:</em><em class=typing>(transform-frames)</em>
+ <em class=listener>0</em>
+</pre>
+
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- transform-graph? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformgraphp">transform-graph?</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is #t if the given channel is displaying a spectrum (the 'f' button).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- transform-graph-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformgraphstyle">transform-graph-style</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This determines how frequency-domain data is displayed.
+The choices are:
+<pre>
+ graph-lines graph-dots graph-filled graph-lollipops graph-dots-and-lines
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- transform-graph-type -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformgraphtype">transform-graph-type</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This determines the choice of spectral display. The choices are (default) <code>graph-once</code> (a single FFT),
+<code>graph-as-sonogram</code>, and <code>graph-as-spectrogram</code>.
+The sonogram is a set of FFTS taken at regular time intervals displayed as time vs frequency, using the
+width or color of the spectral portion to indicate its amplitude. The spectrogram is similar, but uses
+a 3D effect where the height of the line corresponds to its amplitude.
+Currently, the <a href="#fftlogfrequency">fft-log-frequency</a> and <a href="#normalizefft">transform-normalization</a>
+choices are ignored by the spectrogram display.
+If you've included openGL in Snd, the spectrogram will use openGL if <a href="#withgl">with-gl</a> is #t (the
+default).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- transform-normalization -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="normalizefft">transform-normalization</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the transform normalization choice (default: <code>normalize-by-channel</code>).
+If it is <code>normalize-by-channel</code> or <code>normalize-by-sound</code>, spectral data is
+normalized to 1.0 before display. If <code>dont-normalize</code>, you get the
+raw data values, which can reflect amplitude changes &mdash; Snd tries to
+choose a y axis limit that makes successive displays move smoothly.
+The other choice is <code>normalize-globally</code> (i.e. across all sounds).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- transform-sample -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformsample">transform-sample</a> (:optional bin slice snd chn)</code>
+</td></tr><tr><td></td><td>
+This is the current value of the transform (if any) in 'bin' and (if a
+sonogram or spectrogram) 'slice' in the given channel.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- transform-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformsize">transform-size</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the fft size (the default size is 512). It should be a power of 2.
+If your version of Snd was built with FFTW, and you set transform-size
+too large (on my machine, with 2 GBytes of memory,
+<code>(expt 2 26)</code> is apparently too large), FFTW simply exits Snd! There is currently
+no way to trap the error. Also, FFTW assumes the fft size is a (signed) int &mdash; 2^30 is probably
+the transform-size limit.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- transform-type -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformtype">transform-type</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the spectrum transform type (the default is <code>fourier-transform</code>).
+<pre>
+ fourier-transform wavelet-transform haar-transform
+ autocorrelation walsh-transform cepstrum
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+<!-- transform->vct -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformtovct">transform-&gt;vct</a> (:optional snd chn v)</code>
+</td></tr><tr><td></td><td>
+This returns a vct with the transform data from the given channel.
+If 'v' (a vct) is provided, it is filled, rather than creating a new vct.
+See <a href="#fftpeak">fft-peak</a> for an example.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="undo">undo</a> (:optional edits snd chn)</code>
+</td></tr><tr><td></td><td>
+This undoes 'edits' edits (the default is 1) in the given channel.
+Undo follows the <a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> field if it
+is not 0. The following might be a more reasonable undo function:
+<br>
+<pre>
+(define* (<a name="undochannel">undo-channel</a> :optional (<a class=quiet href="#edits" onmouseout="UnTip()" onmouseover="Tip(extsnd_edits_tip)">edits</a> 1) snd chn)
+ (if (and snd (not (= (<a class=quiet href="#sync" onmouseout="UnTip()" onmouseover="Tip(extsnd_sync_tip)">sync</a> snd) 0)) chn)
+ (set! (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> snd chn)
+ (max 0 (- (<a class=quiet href="#editposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_editposition_tip)">edit-position</a> snd chn) edits)))
+ (<em class=red>undo</em> edits snd)))
+</pre>
+
+See also <a href="#undohook">undo-hook</a>.
+Since redo collides with Ruby, forcing me to change its name to redo_edit,
+undo can also be accessed under the name undo_edit (in Scheme, <a name="undoedit">undo-edit</a>).
+
+<!-- INDEX undoexamples:Undo and Redo -->
+
+<A NAME="undoexamples"></a>
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<small><blockquote>
+undo all edits: <a href="#revertsound">revert-sound</a><br>
+specialize undo: <a href="#undohook">undo-hook</a><br>
+protect against undo: <a href="#edithook">edit-hook</a><br>
+redo edit: <a href="#redo">redo</a> and <a href="#redochannel">redo-channel</a><br>
+move around in edit list: <a href="#editposition">edit-position</a> and <a href="#currenteditposition">current-edit-position</a><br>
+About edit lists: <a href="#editlists">Edit lists</a><br><br>
+</blockquote></small>
+
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- update-lisp-graph -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="updatelispgraph">update-lisp-graph</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This forces Snd to redisplay 'chn's' lisp graph. See <a href="sndscm.html#enveddoc">enved.scm</a> which uses the lisp graph as a local envelope editor.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- update-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="updatesound">update-sound</a> (snd)</code>
+</td></tr><tr><td></td><td>
+This causes Snd to update 'snd' (it re-reads the data from disk, flushing any pending edits). In some cases (primarily involving
+a change in the number of channels), update-sound can change the index of the sound referred to by 'snd'.
+See <a href="#updatehook">update-hook</a> for a way to deal with the index confusion.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- update-time-graph -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="updatetimegraph">update-time-graph</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This forces Snd to redisplay 'chn's' time domain graph. See color-samples in draw.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- update-transform-graph -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="updatetransformgraph">update-transform-graph</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This forces Snd to redisplay 'chn's' fft graph. For historical reasons, it also forces the current transform to completion.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+
+<!-- variable-graph? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="variablegraphp">variable-graph?</a> (index)</code>
+</td></tr><tr><td></td><td>
+This returns #t if 'index' refers to a variable graph (see <a href="#makevariablegraph" onmouseout="UnTip()" onmouseover="Tip('<img src=\'pix/vardpy.png\' width=\'250\' height=\'250\'>', TITLE, 'make-variable-display in snd-motif', ABOVE, true)">make-variable-graph</a>).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+
+<!-- view-sound -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="viewsound">view-sound</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This opens 'filename' read-only (you can edit the sound within Snd, but you can't overwrite the original sound).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- verbose-cursor -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="verbosecursor">verbose-cursor</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If verbose-cursor #t (the default is #f), the cursor's position and other information is constantly
+displayed in the minibuffer. This is the View:Verbose cursor option . The new name of this variable
+is <a href="#withverbosecursor">with-verbose-cursor</a>;
+eventually "verbose-cursor" will be retired.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- wavelet-type -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="wavelettype">wavelet-type</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If <a href="#transformtype">transform-type</a> is <code>wavelet-transform</code>, wavelet-type selects which
+wavelet is used. The list of available wavelets is in the Transform
+Dialog. There are around 48 choices, so this variable goes from
+0 to 47 (the default is 0).
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- wavo-hop -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="wavohop">wavo-hop</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This sets the distance upward (in pixels) between wavogram traces; that is,
+the smaller this number, the more traces can be displayed (the default is 3). See <a href="#timegraphtype">time-graph-type</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- wavo-trace -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="wavotrace">wavo-trace</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This sets the length (in samples) of each wavogram trace (the default is 64). See <a href="#timegraphtype">time-graph-type</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- with-tracking-cursor -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="withtrackingcursor">with-tracking-cursor</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This is #t if the cursor is following along in the sound during playback. To make this the default:
+<pre>
+ (set! (with-tracking-cursor) #t)
+</pre>
+The interval (in seconds) between cursor updates is set by <a href="#cursorupdateinterval">cursor-update-interval</a>
+which defaults to 0.05. The accuracy of the cursor in reflecting the sound coming out the speakers
+depends on the amount of buffering in your audio system. If Snd's displayed location is off,
+set <a href="#cursorlocationoffset">cursor-location-offset</a> to reflect the number of samples
+of buffering you think you probably have. A positive cursor-location-offset delays the cursor's
+apparent progress (if playing forwards). In OSS, you can make a pretty good guess by setting
+it to the number of fragments times half the size of the fragments (since these are bytes, and
+cursor-location-offset is in terms of samples). If you have <code>(mus-oss-set-buffers 4 12)</code>,
+try <code>(set! (cursor-location-offset) (* 4 (expt 2 11)))</code>.
+
+<!-- INDEX trackingcursors:Tracking cursors -->
+<A NAME="trackingcursors"></a>
+
+<TABLE border=3 bordercolor="tan" hspace=20 vspace=10><tr><td>
+<blockquote><small>
+<br>
+play from the current cursor position with a tracking cursor: <a href="#pfc">pfc</a><br>
+display tracking cursor as a full height vertical line: <a href="#trackingcursorstyle">tracking-cursor-style</a><br>
+track play once: control-click 'play'. (You can add a mark at the current tracking cursor location during the play with C-m)<br>
+leave the cursor at the final position after tracking play: if-cursor-follows-play-it-stays-where-play-stopped in examp.scm<br>
+tracking cursor accuracy: <a href="#cursorlocationoffset">cursor-location-offset</a><br>
+tracking cursor updating: <a href="#cursorupdateinterval">cursor-update-interval</a><br>
+<br>
+</small></blockquote>
+</td></tr></TABLE>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- with-verbose-cursor -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="withverbosecursor">with-verbose-cursor</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+If with-verbose-cursor is #t, the cursor's position and other information is constantly
+displayed in the minibuffer. This is the View:Verbose cursor option
+(default: #f). The old name of this variable was <a href="#verbosecursor">verbose-cursor</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- write-peak-env-info-file -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="writepeakenvinfofile">write-peak-env-info-file</a> (snd chn filename)</code>
+</td></tr><tr><td></td><td>
+This function writes the current peak-env amp info of the given channel to 'filename'. See peak-env.scm which uses
+this function and its friends to write the peak env data to a file when a sound is closed; a subsequent
+open of that sound can use the saved peak-env data to speed up the sound's redisplay; without the peak env data,
+a background process is launched to read the entire sound to get the needed data.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- x-axis-label -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="xaxislabel">x-axis-label</a> (snd chn context)</code>
+</td></tr><tr><td></td><td>
+This is the current x axis label. 'context' is one of <code>time-graph</code> (the default), <code>lisp-graph</code>, or
+<code>transform-graph</code>.
+<pre>
+ :<em class=typing>(x-axis-label)</em>
+ <em class=listener>"time"</em>
+ :<em class=typing>(set! (x-axis-label) "tempus")</em>
+ <em class=listener>"tempus"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- x-axis-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="xaxisstyle">x-axis-style</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+x-axis-style is the View menu 'X-axis units' option (the default value is <code>x-axis-in-seconds</code>).
+The x axis labelling of the time domain waveform can be in seconds
+(<code>x-axis-in-seconds</code>), in samples (<code>x-axis-in-samples</code>), expressed
+as a percentage of the overall duration (<code>x-axis-as-percentage</code>, useful in envelope definitions), as a beat number (<code>x-axis-in-beats</code>),
+as a measure number (<code>x-axis-in-measures</code>), or in digital clock format (DD:HH:MM:SS.ddd) (<code>x-axis-as-clock</code>, useful in
+very large files).
+When the x axis labelling is in measures, the label has the form M(B)F or M(B) where M is the one-based
+measure number (that is, the first measure, at time 0.0, is measure 1), B is the one-based beat number
+within that measure, and F (if present) is the location within that beat on a scale of 0.0 to 1.0.
+If a major tick marks a measure beginning, and there are non-measure minor ticks, then the measure
+is distinguished from the beat by having a longer tick mark.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- x-bounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="xbounds">x-bounds</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This returns <code>(list x0 x1)</code>, the current x axis time domain bounds in seconds. To display the entire sound:
+<pre>
+ (set! (x-bounds) (list 0.0 (/ (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>))))
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- x->position -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="xtoposition">x-&gt;position</a> (x snd chn axis)</code>
+</td></tr><tr><td></td><td>
+This returns the graph (screen pixel) position that corresponds to the x axis value 'x'.
+'axis' is one of <code>time-graph</code> (the default), <code>lisp-graph</code>, or <code>transform-graph</code>.
+See draw.scm or gtk-popup.scm for examples.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- x-position-slider -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="xpositionslider">x-position-slider</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr>
+<tr><td></td><td>
+This is the value of x axis position slider. See zoom-fft in examp.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- x-zoom-slider -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="xzoomslider">x-zoom-slider</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the value of x axis zoom slider. See <a href="#zoomonepixel">zoom-one-pixel</a>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- xramp-channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="xrampchannel">xramp-channel</a> (rmp0 rmp1 base :optional beg dur snd chn edpos)</code>
+</td></tr><tr><td></td><td>
+xramp-channel is a slight extension of <a href="#rampchannel">ramp-channel</a>. It scales samples in the given sound/channel
+between 'beg' and 'beg' + 'dur' by an exponential ramp going from 'rmp0' to 'rmp1' with the connecting segment curvature
+set by 'base'.
+<pre>
+ (xramp-channel 0.0 1.0 32.0)
+</pre>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- y-axis-label -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="yaxislabel">y-axis-label</a> (snd chn context)</code>
+</td></tr><tr><td></td><td>
+This is the current y axis label. 'context' is one of <code>time-graph</code> (the default), <code>lisp-graph</code>, or <code>transform-graph</code>.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- y-bounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="ybounds">y-bounds</a> (:optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This returns <code>(list y0 y1)</code>, the current y axis bounds.
+To set the bounds to reflect the channel's maxamp, use <code>(set! (y-bounds) '())</code>.
+To set all channels at once using the selected sound's maxamp:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(let ((maxval (apply max (<a class=quiet href="#maxamp" onmouseout="UnTip()" onmouseover="Tip(extsnd_maxamp_tip)">maxamp</a> #f #t))))
+ (do ((i 0 (+ 1 i)))
+ ((= i (<a class=quiet href="#chans" onmouseout="UnTip()" onmouseover="Tip(extsnd_chans_tip)">channels</a>)))
+ (set! (<em class=red>y-bounds</em> #f i) (list (- maxval) maxval))))
+</pre></td></tr></table>
+
+Or to set each channel to its own maxamp:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(do ((i 0 (+ 1 i)))
+ ((= i (<a class=quiet href="#chans" onmouseout="UnTip()" onmouseover="Tip(extsnd_chans_tip)">channels</a>)))
+ (let ((maxval (<a class=quiet href="#maxamp" onmouseout="UnTip()" onmouseover="Tip(extsnd_maxamp_tip)">maxamp</a> #f i)))
+ (set! (<em class=red>y-bounds</em> #f i) (list (- maxval) maxval))))
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- y->position -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="ytoposition">y-&gt;position</a> (y snd chn axis)</code>
+</td></tr><tr><td></td><td>
+This returns the graph (screen pixel) position that corresponds to the y axis value 'y'.
+'axis' is one of <code>time-graph</code> (the default), <code>lisp-graph</code>, or <code>transform-graph</code>.
+This is used in samples-via-colormap in draw.scm to draw the time domain samples in many colors.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- y-position-slider -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="ypositionslider">y-position-slider</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the value of y axis position slider. See zync in snd-motif.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- y-zoom-slider -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="yzoomslider">y-zoom-slider</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+This is the value of y axis zoom slider. See <a href="#xdisplayenergy">display-energy</a>, or zync in snd-motif.scm.
+</td></tr><tr><td colspan=2 height=18></td></tr>
+
+
+<!-- zero-pad -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="zeropad">zero-pad</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+zero-pad is the fft zero pad size as a multiple of the fft size; <code>(set! (zero-pad) 1)</code>
+gives you half data, half zeros (the default value is 0). The data length is
+determined by the nominal transform-size. Zero padding causes interpolation
+of the fft points, making the display look smoother.
+
+<table cellpadding=5><tr><td>
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> (char-&gt;integer #\p) 0
+ (lambda ()
+ "increase zero-pad"
+ (set! (zero-pad) (+ (<em class=red>zero-pad</em>) 1))
+ (<a class=quiet href="#updatetransformgraph" onmouseout="UnTip()" onmouseover="Tip(extsnd_updatetransformgraph_tip)">update-transform-graph</a>)))
+
+(<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> (char-&gt;integer #\m) 0
+ (lambda ()
+ "decrease zero-pad"
+ (set! (zero-pad) (- (<em class=red>zero-pad</em>) 1))
+ (<a class=quiet href="#updatetransformgraph" onmouseout="UnTip()" onmouseover="Tip(extsnd_updatetransformgraph_tip)">update-transform-graph</a>)))
+</pre></td></tr></table>
+</td><td>
+<img src="pix/pad1.png" alt="more pads"></td>
+</tr></table>
+
+</td></tr>
+
+</table><!-- end of main sound/channel table -->
+<br><br>
+
+<table width="35%" border=0><tr><td bgcolor="#EEFDEE" valign="middle"><h4><A NAME="customcontrols">the control panel</a></h4></td></tr></table>
+
+
+<p>The control panel makes it easy to try out various sound effects without
+editing anything. You can change volume ('amp'), pitch ('speed'), tempo
+('expand'), reverb amount ('reverb'), simulated room size ('reverb len'),
+brightness ('contrast'), and dullness ('filter'). To treat a current
+setting as an edit operation, call <a href="#applycontrols">apply-controls</a>. For more on
+the effects themselves (and a pretty picture!), see the discussion in <a href="snd.html#controls">snd.html</a>.
+</p>
+<p>
+The control panel normally processes samples as follows: if the sampling
+rate conversion is on (the 'Speed' control is not 1.0), it applies srate
+conversion to the incoming sample; the next stage is the expansion function,
+if the 'Expand' toggle button is set; this value is passed
+next to the Contrast function, if it is running, and then the result
+is scaled by the Amp slider's value. The filter is run next, if
+it's on, and finally the sample is scaled by the reverb slider and
+passed to the reverb, if any, which adds its result to the sample;
+the final result is sent to the speakers.
+The control panel procedures are:
+</p>
+<!-- -------------------------------- CONTROL PANEL -------------------------------- -->
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- amp-control -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="ampcontrol">amp-control</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td width=30><br></td><td>
+The current amp value.
+It is possible to use these controls (in "real-time") in your own functions.
+See amprt in <a href="sndscm.html#exampdoc">examp.scm</a> for an example,
+or add-amp-control in snd-motif.scm.
+As an experiment, I added the optional 'chn' argument; if it is specified, the
+channel's local amp-control value is set instead of the sound's. This affects
+<a class=quiet href="#applycontrols" onmouseout="UnTip()" onmouseover="Tip(extsnd_applycontrols_tip)">apply-controls</a> and playback.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- amp-control-bounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="ampcontrolbounds">amp-control-bounds</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The amp-control min and max amounts as a list. The default is
+(list 0.0 8.0). The value 1.0 should be in the given range, since it is placed in the middle of the slider's range.
+If no 'snd' argument is given, this also affects the Mix, View:Files, and Record dialogs.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- apply-controls -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="applycontrols">apply-controls</a> (:optional snd target beg dur)</code>
+</td></tr><tr><td></td><td>
+Apply the current control panel state as an edit.
+'target' can be 0=sound, 1=channel, 2=selection.
+'beg' sets where in samples the apply starts: <code>(apply-controls 0 0 (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> m))</code> starts from the given mark.
+'dur', if given, sets how many samples to run through the apply process (the input duration).
+apply-controls can be used in conjunction with the various control panel variables:
+
+<table border=0 vspace=10><tr><td>
+<table border=0 cellpadding=5><tr><td><pre>
+(define expnd
+ (lambda (amt)
+ (set! (<a class=quiet href="#expandcontrolp" onmouseout="UnTip()" onmouseover="Tip(extsnd_expandcontrolp_tip)">expand-control?</a>) #t)
+ (set! (<a class=quiet href="#expandcontrol" onmouseout="UnTip()" onmouseover="Tip(extsnd_expandcontrol_tip)">expand-control</a>) amt)
+ (<em class=red>apply-controls</em>)))
+</pre></td></tr></table>
+
+</td><td width=20>
+</td><td>
+<table border=0 cellpadding=5><tr><td bgcolor="Beige"><pre>
+def expnd(amt)
+ set_expand_control? true
+ set_expand_control amt
+ apply_controls
+end
+</pre></td></tr></table>
+
+</td><td width=20>
+</td><td>
+<table border=0 cellpadding=5><tr><td bgcolor="LightGreen"><pre>
+: expnd ( amt -- ) { amt }
+ #t set-expand-control? drop
+ amt set-expand-control drop
+ apply-controls
+;
+</pre></td></tr></table>
+</td></tr></table>
+
+For many examples see new-effects.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- controls->channel -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="controlstochannel">controls-&gt;channel</a> (:optional settings beg dur snd chn origin)</code>
+</td></tr><tr><td></td><td>
+This sets up the sound's controls to reflect 'settings' (unspecified settings are not changed), then applies the controls as
+an edit of channel 'chn'. The 'settings' argument is a list where each entry can also be #f or an empty list:
+<pre>
+ (list amp speed
+ (list contrast contrast_amp)
+ (list expand expand_length expand_ramp expand_hop expand_jitter)
+ (list reverb_scale reverb_length reverb_feedback reverb_low_pass reverb_decay)
+ (list filter_order filter_env))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- contrast-control -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="contrastcontrol">contrast-control</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#contrast">contrast</a> amount.
+The <a href="sndclm.html#contrast-enhancement">contrast-enhancement</a> algorithm treats this variable as a kind of modulation index (the higher, the brighter),
+whereas contrast-control-amp below prescales the in-coming signal to be closer to -1.0 to 1.0
+(the brightening effect works best if it has a full amplitude signal to work with).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- contrast-control-amp -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="contrastcontrolamp">contrast-control-amp</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#contrast">contrast-control-amp</a> (a prescaler on the contrast-enhancement to get the
+full effect of the compander).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- contrast-control-bounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="contrastcontrolbounds">contrast-control-bounds</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The contrast-control min and max amounts as a list. The default is
+(list 0.0 10.0).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- contrast-control? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="contrastcontrolp">contrast-control?</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+#t if the <a class=quiet href="snd.html#contrast">contrast</a> button is set (i.e. the contrast compander is active).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- expand-control -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="expandcontrol">expand-control</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#expand">expansion</a> amount. This sets the ratio between the
+output and input grain spacing. If it is greater than 1.0, the result is longer.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- expand-control-bounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="expandcontrolbounds">expand-control-bounds</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The expand-control min and max amounts as a list. The default is
+(list 0.001 20.0).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- expand-control-hop -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="expandcontrolhop">expand-control-hop</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#expand">expansion</a> hop amount in seconds (the distance between successive grains).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- expand-control-jitter -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="expandcontroljitter">expand-control-jitter</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#expand">expansion</a> grain timing jitter. This defaults to .1; if you set it
+to too small a number (0.0 for example), you'll probably notice (presumably unwanted) notch-filter effects.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- expand-control-length -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="expandcontrollength">expand-control-length</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#expand">expansion</a> segment (grain) length in seconds. The longer the grain,
+the more reverberated or slurred the effect.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- expand-control-ramp -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="expandcontrolramp">expand-control-ramp</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#expand">expansion</a> ramp amount (between 0 and .5).
+This affects the smoothness of the grain overlaps &mdash; .001 gives a
+rattling effect.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- expand-control? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="expandcontrolp">expand-control?</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+#t if the expand button is set (i.e. the expansion effect is active).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- filter-control-coeffs -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filtercontrolcoeffs">filter-control-coeffs</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#filtercontrol">filter</a> coefficients (read-only currently). It is
+a vct suitable for use with the <a href="sndclm.html#filter">filter generator</a> or with
+<a href="#filtersound">filter-sound</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- filter-control-envelope -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filtercontrolenvelope">filter-control-envelope</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#filtercontrol">filter</a> (frequency reponse) envelope (a list of breakpoints).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- filter-control-in-dB -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filtercontrolindB">filter-control-in-dB</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#filtercontrol">filter</a> dB button. If #t, the filter (frequency) envelope
+graph is displayed in dB.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- filter-control-in-hz -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filtercontrolinhz">filter-control-in-hz</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+If #t, the filter frequency response envelope x axis is in Hz, otherwise 0 to 1.0 (where 1.0 corresponds to srate/2).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- filter-control-order -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filtercontrolorder">filter-control-order</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#filtercontrol">filter</a> order. This affects how much computing
+is needed to run the filter, and how close the filter can get to the desired frequency response envelope.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- filter-control-waveform-color -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filterwaveformcolor">filter-control-waveform-color</a></code>
+</td></tr><tr><td></td><td>
+The filter frequency response waveform color.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- filter-control? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="filtercontrolp">filter-control?</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+#t if the filter button is set (i.e. the filter is active).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reset-controls -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="resetcontrols">reset-controls</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+Set all the controls to their default state.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- restore-controls -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="restorecontrols">restore-controls</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+Set all the
+controls to the last saved state.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+<!-- reverb-control-decay -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reverbdecay">reverb-control-decay</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The length (in seconds) of the reverberation after the sound has
+finished (default: 1.0).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reverb-control-feedback -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reverbcontrolfeedback">reverb-control-feedback</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The reverb feedback coefficient. The more feedback, the happier Elvis.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reverb-control-length -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reverbcontrollength">reverb-control-length</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#reverb">reverb</a> delay line length scaler. Longer reverb simulates, to some
+extent, a bigger hall.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reverb-control-length-bounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reverbcontrollengthbounds">reverb-control-length-bounds</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The reverb-control-length min and max amounts as a list. The default is
+(list 0.0 5.0).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reverb-control-lowpass -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reverbcontrollowpass">reverb-control-lowpass</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The reverb low pass filter coefficient. (This filter is in the feedback loop).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reverb-control-scale -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reverbcontrolscale">reverb-control-scale</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The <a class=quiet href="snd.html#reverb">reverb</a> amount (the amount of the direct signal sent to the reverb).
+You can never have enough reverb.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reverb-control-scale-bounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reverbcontrolscalebounds">reverb-control-scale-bounds</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The reverb-control-scale min and max amounts as a list. The default is
+(list 0.0 4.0).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reverb-control? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="reverbcontrolp">reverb-control?</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+#t if the reverb button is set (i.e. the reverberator is active).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-controls -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="savecontrols">save-controls</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+This remembers the current control
+settings for a later <a class=quiet href="#restorecontrols" onmouseout="UnTip()" onmouseover="Tip(extsnd_restorecontrols_tip)">restore-controls</a>. In new-effects.scm, the effects that use the control panel
+internally (post-expsrc-dialog, for example) save and restore the current state via:
+<pre>
+ (<em class=red>save-controls</em>)
+ (reset-controls)
+ ;;; now set the ones that are of interest for the current effect
+ (apply-controls)
+ (restore-controls)
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- show-controls -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="showcontrols">show-controls</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+#t if the sound's control panel is currently open.
+If set to #t, the sound's control panel is opened, else it is closed.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- speed-control -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="speedcontrol">speed-control</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+current <a class=quiet href="snd.html#speed">speed</a> (sampling rate conversion factor). A speed of 2 plays the sound twice as fast.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- speed-control-bounds -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="speedcontrolbounds">speed-control-bounds</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The speed-control min and max amounts as a list. The default is
+(list 0.05 20.0).
+If no 'snd' argument is given, this also affects the Mix, and View:Files dialogs.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- speed-control-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="speedstyle">speed-control-style</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The speed control can be interpreted as a
+float, (<code>speed-control-as-float</code>, the default), as a ratio
+of relatively small integers (<code>speed-control-as-ratio</code>), or as a step in a
+microtonal scale (<code>speed-control-as-semitone</code>).
+In the various speed controls, you can click the number to cycle through the speed style choices.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- speed-control-tones -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="speedtones">speed-control-tones</a> (:optional <em class=narg>snd</em>)</code>
+</td></tr><tr><td></td><td>
+The number of tones per octave in the <code>speed-control-as-semitone</code> speed
+style (default: 12).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+</table>
+
+
+<p>
+<a href="sndscm.html#makehiddencontrolsdialog">make-hidden-controls-dialog</a> in
+snd-motif.scm sets up a dialog to handle the controls that aren't handled by
+the control panel (expand-control-hop, expand-control-length, expand-control-ramp,
+contrast-control-amp, reverb-control-lowpass, and reverb-control-feedback).
+The control panel itself is accessible as <code>(list-ref (<a href="#soundwidgets">sound-widgets</a>) 2)</code>.
+You can add or remove controls; <a href="sndscm.html#addampcontrols">add-amp-controls</a>
+in snd-motif.scm sets up a separate amp slider for each channel in the current sound.
+<a href="sndscm.html#disablecontrolpanel">disable-control-panel</a> disables (hides) the
+entire panel.
+</p>
+
+<br>
+
+<!-- INDEX editlists:Edit lists -->
+<!-- Edit Lists -->
+<br>
+<table width="35%" border=0><tr><td bgcolor="#EEFDEE" valign="middle"><h4><A NAME="editlists">Edit Lists</a></h4></td></tr></table>
+
+<p>An edit list (in other editors this is called an "edit decision list", I guess because it sounds decisive)
+describes the edit history of a channel. When, for example, you type C-d, nothing actually
+happens to any data, despite the fact that the graph no longer shows that sample, it's omitted when you play the
+channel, and so on. Instead, a descriptor is appended to the edit history of that
+channel saying "sample n was deleted". Undo and redo move around in this list (they simply move the
+pointer to the current edit history position); all the positions are accessible just like the current
+one, and are exposed in many functions described above via the 'pos' or 'edpos' arguments.
+The edit list functions are:
+</p>
+
+
+<!-- -------------------------------- EDIT-LIST TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- as-one-edit -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="asoneedit">as-one-edit</a> (func :optional origin)</code>
+</td></tr><tr><td width=30></td><td>
+call 'func', a function of no arguments, treating it as
+one edit (in all channels) in the edit history mechanism. Graphics redisplays are squelched during as-one-edit.
+as-one-edit returns the result of 'func'.
+
+<table border=0 vspace=10><tr><td>
+<table border=0 cellpadding=5><tr><td>
+<pre>
+(<em class=red>as-one-edit</em>
+ (lambda ()
+ (set! (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> 100) .1)
+ (set! (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> 200) .2)))
+</pre>
+</td></tr></table>
+
+</td><td width=20>
+</td><td>
+<table border=0 cellpadding=5><tr><td bgcolor="beige">
+<pre>
+<em class=red>as_one_edit</em>(lambda do ||
+ set_sample(100, 0.1)
+ set_sample(200, 0.2)
+ end)
+</pre>
+</td></tr></table>
+
+</td><td width=20>
+</td><td>
+<table border=0 cellpadding=5><tr><td bgcolor="lightgreen">
+<pre>
+lambda:
+ 100 .1 set-sample drop
+ 200 .2 set-sample drop
+; 0 make-proc <em class=red>as-one-edit</em>
+</pre>
+</td></tr></table>
+</td></tr></table>
+
+</td></tr>
+<tr><td></td><td>
+
+See mix.scm for many examples. If you want to save and restore Snd's state after using as-one-edit, you need to
+set 'origin' to some string that can restore the effect of the as-one-edit; the default is
+to copy the last edit history string and use its associated bounds &mdash; unlikely to be what you want.
+</td></tr><tr><td></td><td></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- display-edits -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="displayedits">display-edits</a> (:optional snd chn edpos with-source)</code>
+</td></tr><tr><td></td><td>
+This returns the current edit list contents as a string. If 'edpos' is specified, only that position is described.
+'with-source' (default: #t) determines whether ptree source code is included in the output.
+<pre>
+ :<em class=typing>(open-sound "oboe.snd")</em>
+ <em class=listener>#&lt;sound 0&gt;</em>
+ :<em class=typing>(scale-channel 2.0)</em>
+ <em class=listener>2.0</em>
+ :<em class=typing>(pad-channel 100 200)</em>
+ <em class=listener>100</em>
+ :<em class=typing>(display-edits 0 0 1)</em> ; show just edit 1 (the scale-channel call)
+ <em class=listener>"
+ (scale 0 50828) ; scale-channel 2.000 0 #f [1:2]:
+ (at 0, cp-&gt;sounds[0][0:50827, 2.000]) [file: /home/bil/cl/oboe.snd[0]]
+ (at 50828, end_mark)
+ "</em>
+</pre>
+</td></tr><tr><td></td><td></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- edit-fragment -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="editfragment">edit-fragment</a> (:optional edpos snd chn)</code>
+</td></tr><tr><td></td><td>
+This returns a list similar to that displayed in the edit history window giving
+the origin of the specified edit, its type (delete, insert, etc), its
+begin sample, and the number of samples
+affected. If 'edpos' is omitted, edit-fragment returns the currently active
+edit.
+<pre>
+ :<em class=typing>(edit-fragment 2 0 0)</em> ; continuing example above
+ <em class=listener>("pad-channel" "zero" 100 200)</em>
+</pre>
+</td></tr><tr><td></td><td></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- edit-list->function -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="editlisttofunction">edit-list-&gt;function</a> (:optional snd chn start end)</code>
+</td></tr><tr><td></td><td>
+This returns a function encapsulating the current edit history list, providing a way to save an edit
+sequence and re-apply it in some other context. For example, you can back up to some earlier point,
+save the edit list, make a change, then re-run the saved edit sequence.
+The function returned takes 2 arguments, a sound and a channel number.
+<pre>
+ :<em class=typing>(define our-edits (</em><em class=red>edit-list-&gt;function</em><em class=typing>))</em> ; same example as above
+ <em class=listener>#&lt;unspecified&gt;</em>
+ :<em class=typing>our-edits</em>
+ <em class=listener>#&lt;procedure our-edits ((snd chn) (scale-channel 2.0 0 #f snd chn) (pad-channel 100 200 snd chn))&gt;</em>
+ :<em class=typing>(undo 2)</em>
+ <em class=listener>2</em>
+ :<em class=typing>(our-edits 0 0)</em>
+ <em class=listener>100</em>
+</pre>
+
+In Ruby:
+<pre>
+ :<em class=typing>open_sound "oboe.snd"</em>
+ <em class=listener>0</em>
+ :<em class=typing>scale_channel 2.0</em>
+ <em class=listener>2.0</em>
+ :<em class=typing>pad_channel 100, 200</em>
+ <em class=listener>100</em>
+ :<em class=typing>our_edits = edit_list2function</em>
+ <em class=listener>#&lt;Proc:0x40c713ec@(eval):2&gt;</em>
+ :<em class=typing>our_edits.source</em>
+ <em class=listener>Proc.new {|snd, chn| scale_channel(2.000, 0, false, snd, chn); pad_channel(100, 200, snd, chn) }</em>
+ :<em class=typing>undo 2</em>
+ <em class=listener>2</em>
+ :<em class=typing>our_edits.call(0, 0)</em>
+ <em class=listener>100</em>
+</pre>
+
+In Forth:
+<pre>
+ snd&gt; <em class=typing>"oboe.snd" open-sound</em>
+ <em class=listener>0</em>
+ snd&gt; <em class=typing>2.0 scale-channel</em>
+ <em class=listener>2.0</em>
+ snd&gt; <em class=typing>100 200 pad-channel</em>
+ <em class=listener>100</em>
+ snd&gt; <em class=typing>0 0 edit-list-&gt;function value our-edits</em>
+ <em class=listener>nil</em>
+ snd&gt; <em class=typing>our-edits proc-source-ref</em>
+ <em class=listener>lambda: { snd chn } 2.000 0 #f snd chn scale-channel drop 100 200 snd chn pad-channel drop ; 2 make-proc</em>
+ snd&gt; <em class=typing>2 undo</em>
+ <em class=listener>2</em>
+ snd&gt; <em class=typing>our-edits '( 0 0 ) run-proc</em>
+ <em class=listener>#f</em>
+</pre>
+</td></tr><tr><td></td><td></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- edit-position -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="editposition">edit-position</a> (:optional <em class=narg>snd chn</em>)</code>
+</td></tr><tr><td></td><td>
+The current position in the edit history list; it can be set: <code>(set! (edit-position) 0)</code> is equivalent
+to <code>(<a class=quiet href="#revertsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_revertsound_tip)">revert-sound</a>)</code> in a mono sound.
+See <a href="#makesampler">make-sampler</a>.
+</td></tr><tr><td></td><td></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- edit-properties -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="editproperties">edit-properties</a> (:optional <em class=narg>snd chn edpos</em>)</code>
+</td></tr><tr><td></td><td>
+Each entry in a channel's edit history list has a property list (similar to the
+<a href="#channelproperties">channel-properties</a> list). If you have information that changes with the
+edit lists, these property lists might simplify the access code.
+</td></tr><tr><td></td><td></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- edits -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="edits">edits</a> (snd chn)</code>
+</td></tr><tr><td></td><td>
+This returns a list with the number of undo-able edits and redo-able edits. That is, if we have 2 undo-able edits and
+no redo-able edits, <code>(edits)</code> returns <code>(list 2 0)</code>.
+</td></tr><tr><td></td><td></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- edit-tree -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="edittree">edit-tree</a> (:optional snd chn pos)</code>
+</td></tr><tr><td></td><td>
+This returns a list of lists completely describing current edit list.
+Each inner list has the form
+<pre>
+ (list global-position data-number local-position local-end scaler ramp0 ramp1 type)
+</pre>
+If 'data-number' is -2, it marks the end of the list. In our example above (the scale-channel/pad-channel sequence):
+<pre>
+ :<em class=typing>(edit-tree)</em>
+ <em class=listener>((0 0 0 99 2.0 0.0 0.0 0) (100 -1 0 199 0.0 0.0 0.0 1)
+ (300 0 100 50827 2.0 0.0 0.0 0) (51028 -2 0 0 0.0 0.0 0.0 0))</em>
+</pre>
+
+The following function uses
+this information to highlight the changed portions of a given sound.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<A NAME="showoriginal">show-original</a> snd chn)
+ ;; draw a bar above unchanged portions of a sound
+ (define (check-fragment tree ls rs)
+ (let* ((fragment (car tree)) ; current edit list fragment
+ (pos (car fragment)) ; its position in sound
+ (dat (cadr fragment))
+ (scl (list-ref fragment 4)))
+ (if (and (= dat 0) ; original sound
+ (= scl 1.0)) ; unscaled
+ (let ((nxtpos (car (cadr tree))))
+ (if (and (&lt;= pos rs)
+ (&gt;= nxtpos ls)) ; fragment is at least partially visible
+ (let ((x0pos (<a class=quiet href="#xtoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_xtoposition_tip)">x-&gt;position</a> (/ (max ls pos) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>))))
+ (x1pos (<a class=quiet href="#xtoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_xtoposition_tip)">x-&gt;position</a> (/ (min rs nxtpos) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>)))))
+ (<a class=quiet href="#fillrectangle" onmouseout="UnTip()" onmouseover="Tip(extsnd_fillrectangle_tip)">fill-rectangle</a> x0pos 2 (- x1pos x0pos) 5)))))
+ (if (and (cdr tree) ; go to next fragment
+ (not (= (cadr (car tree)) -2)))
+ (check-fragment (cdr tree) ls rs))))
+ (check-fragment (<em class=red>edit-tree</em> snd chn)
+ (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> snd chn)
+ (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a> snd chn)))
+
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#aftergraphhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_aftergraphhook_tip)">after-graph-hook</a> show-original)
+</pre>
+</td></tr></table></td></tr><tr><td></td><td></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-edit-history -->
+
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="saveedithistory">save-edit-history</a> (filename :optional snd chn)</code>
+</td></tr><tr><td></td><td>
+This function saves the current edit lists in 'filename'.
+If 'chn' is omitted, all of the sound's channels are saved; if 'snd' is omitted,
+all edit lists are saved. If the underlying files are not subsequently
+changed, you can load this file to restore the current edit list state.
+save-edit-history returns #t if all went well.
+The following function makes an
+exact copy of the state (edit lists and all) of the given sound,
+providing a way to fork an edit path (geez, what jargon!). The idea here
+is to copy the complete edit state into a new sound so that two or more
+edit sequences can be compared.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define sfile 0)
+
+(define* (<a name="clonesoundas">clone-sound-as</a> new-name :optional snd)
+ (let* ((tmpf (<a class=quiet href="#sndtempnam" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndtempnam_tip)">snd-tempnam</a>))
+ (scm (string-append (substring tmpf 0 (- (string-length tmpf) 3)) "scm"))
+ (oldsnd (or snd (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>))))
+ (if (not (string? (<a class=quiet href="#savedir" onmouseout="UnTip()" onmouseover="Tip(extsnd_savedir_tip)">save-dir</a>))) (set! (<a class=quiet href="#savedir" onmouseout="UnTip()" onmouseover="Tip(extsnd_savedir_tip)">save-dir</a>) "/tmp"))
+ (<em class=red>save-edit-history</em> scm oldsnd)
+ (copy-file (<a class=quiet href="#filename" onmouseout="UnTip()" onmouseover="Tip(extsnd_filename_tip)">file-name</a> oldsnd) new-name)
+ (set! sfile (<a class=quiet href="#opensound" onmouseout="UnTip()" onmouseover="Tip(extsnd_opensound_tip)">open-sound</a> new-name))
+ (load scm)
+ (delete-file scm)
+ sfile))
+</pre></td></tr></table>
+
+We can also use save-edit-history (with some trouble) to split a sound off
+into an independent Snd process:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (separate-sound :optional snd)
+ (let* ((tmpf (<a class=quiet href="#sndtempnam" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndtempnam_tip)">snd-tempnam</a>))
+ (scm (string-append (substring tmpf 0 (- (string-length tmpf) 3)) "scm"))
+ (scm1 (string-append (substring tmpf 0 (- (string-length tmpf) 4)) "-1.scm"))
+ (oldsnd (or snd (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>)))
+ (name (<a class=quiet href="#filename" onmouseout="UnTip()" onmouseover="Tip(extsnd_filename_tip)">file-name</a> oldsnd)))
+ (if (not (string? (<a class=quiet href="#savedir" onmouseout="UnTip()" onmouseover="Tip(extsnd_savedir_tip)">save-dir</a>))) (set! (<a class=quiet href="#savedir" onmouseout="UnTip()" onmouseover="Tip(extsnd_savedir_tip)">save-dir</a>) "/tmp"))
+ (<em class=red>save-edit-history</em> scm oldsnd)
+ (<a class=quiet href="#closesound" onmouseout="UnTip()" onmouseover="Tip(extsnd_closesound_tip)">close-sound</a> oldsnd)
+ (with-output-to-file
+ scm1
+ (lambda ()
+ (display (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "(define sfile (<a class=quiet href="#opensound" onmouseout="UnTip()" onmouseover="Tip(extsnd_opensound_tip)">open-sound</a> ~S))~%" name))
+ (display (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "(load ~S)~%" scm))))
+ (system (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "snd ~A &amp;" scm1))))
+</pre></td></tr></table>
+
+</td></tr><tr><td></td><td></td></tr>
+
+</table>
+
+<p>It is sometimes more convenient to edit the edit history lists
+directly, than to run Snd and invoke the <a href="snd.html#savedstate">"Save session"</a> menu option.
+These lists are simply Scheme, Ruby, or Forth programs, just like anything else
+discussed in this document. You could even write them from
+scratch. Say we want to make a stereo file that consists
+of four mono files mixed at various points; we know where they
+should go, and we have religious objections to using a
+graphical user interface. So we create myfile.scm, and
+put in it something like:</p>
+
+<table border=0 cellpadding=5 hspace=20><tr><td><pre>
+(let ((myfile (<a class=quiet href="#newsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_newsound_tip)">new-sound</a> "mysound.snd" mus-aifc-sound-file <a class=quiet href="#dataformat" onmouseout="UnTip()" onmouseover="Tip(extsnd_musbshort_tip)">mus-bshort</a> 44100 2 "this is my sound")))
+ ;; this is equivalent to the New file menu option
+ (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> "oboe.snd" 0 0 myfile 0)
+ ;; this mixes in the mono file oboe.snd at sample 0 in channel 0
+ ;; use (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> "oboe.snd" 0 0 myfile 0 #f) to forego the editable mix
+ (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> "pistol.snd" 0 0 myfile 1)
+ ;; now pistol.snd is at sample 0 in channel 1
+ (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> "fyow.snd" 10000 0 myfile 0)
+ ;; add in fyow.snd at sample 10000 in the first channel
+ (<a class=quiet href="#mix" onmouseout="UnTip()" onmouseover="Tip(extsnd_mix_tip)">mix</a> "cardinal.snd" 20000 0 myfile 1)
+ ;; etc
+ )
+</pre></td></tr></table>
+
+<p>Now start Snd: <code>snd -l myfile.scm</code> and voila!
+Files like this can contain any arbitrary code, calling
+anything in Snd or anywhere else for that matter; you
+have a CLM-like notelist reader to describe sound file edits.
+Similarly, when you save Snd's state (via the Save session menu
+option or by calling the function <a href="#savestate">save-state</a>),
+the result is a program that can be edited just like any
+other such text.
+</p>
+
+
+
+<!-- Transforms -->
+<br>
+<table width="80%" border=0><tr><td bgcolor="lightsteelblue" valign="middle"><h3><A NAME="sndtransforms">Transforms</a></h3></td></tr></table>
+
+<p>Most of the transform functions and variables have been treated above, so they are only mentioned here.
+</p>
+
+<!-- -------------------------------- TRANSFORM TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- add-transform -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addtransform">add-transform</a> (name xlabel lo hi transform)</code>
+</td></tr><tr><td width=30></td><td>
+add-transform adds a transform to the transform choices (alongside Fourier, Wavelet, etc). 'name' is the name
+to use in the transform dialog. 'xlabel' is the x axis label
+of the resultant graph. 'lo' and 'hi' set which portion of the returned data
+to graph (normally 0.0 to 1.0). 'proc' is a function of two
+arguments, the length of the desired transform, and a sampler that
+can be used to get the current data. Do not free the sampler!
+The function should return a vct containing the transform data.
+add-transform returns the new transform's transform-type.
+Here's an example that displays a histogram of the current values in 16 bins:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>add-transform</em> "histogram" "bins" 0.0 1.0
+ (lambda (len fd)
+ (let ((v (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> len))
+ (steps (/ len 16))
+ (step (/ 1.0 len)))
+ (do ((i 0 (+ 1 i)))
+ ((= i len) v)
+ (let* ((val (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> fd))
+ (bin (inexact-&gt;exact (* (abs val) 16.0))))
+ (do ((j 0 (+ 1 j)))
+ ((= j steps))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> v
+ (+ j bin)
+ (+ step (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> v (+ j bin))))))))))
+</pre></td></tr></table>
+
+This code ties the Hilbert transform in dsp.scm into the user-interface:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>add-transform</em> "Hilbert" "Hilbert" 0.0 1.0
+ (lambda (len fd)
+ (let ((flt (<a class=quiet href="sndscm.html#makehilberttransform" onmouseout="UnTip()" onmouseover="Tip(sndscm_makehilberttransform_tip)">make-hilbert-transform</a> 40)))
+ (do ((i 0 (+ 1 i))) ; preload first samples
+ ((= i 40))
+ (<a class=quiet href="sndclm.html#fir-filter" onmouseout="UnTip()" onmouseover="Tip(sndclm_fir_filter_tip)">fir-filter</a> flt (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> fd)))
+ (<a class=quiet href="#vctmap" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctmap_tip)">vct-map!</a>
+ (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> len)
+ (lambda ()
+ (<a class=quiet href="sndclm.html#fir-filter" onmouseout="UnTip()" onmouseover="Tip(sndclm_fir_filter_tip)">fir-filter</a> flt (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> fd)))))))
+</pre></td></tr></table>
+
+If GSL is included in Snd, the following code ties in the (slow) Hankel transform:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>add-transform</em> "Hankel" "Hankel" 0.0 1.0
+ (lambda (n rd)
+ (let ((v (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> n)))
+ (do ((i 0 (+ 1 i))) ((= i n)) (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> v i (rd)))
+ (gsl-dht n v 1.0 1.0)
+ v)))
+</pre></td></tr></table></td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- delete-transform -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="deletetransform">delete-transform</a> (type)</code>
+</td></tr><tr><td></td><td>
+This removes a transform that was added via <a class=quiet href="#addtransform" onmouseout="UnTip()" onmouseover="Tip(extsnd_addtransform_tip)">add-transform</a>. The deleted transform-type may be re-used by
+a subsequent add-transform.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- fft -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fft">fft</a> (rl im :optional sgn)</code>
+</td></tr><tr><td></td><td>
+<p>
+This performs an FFT on vcts 'rl' and 'im' (the real and imaginary parts of the
+input data). 'sgn' is 1 for an FFT, -1 for an inverse FFT; (the default is 1).
+The CLM <a href="sndclm.html#fft">fft</a> function is called <a name="musfft">mus-fft</a> in Snd.
+The only difference between the two is that Snd's fft determines the fft size from
+the size of the vcts passed to it, whereas CLM's takes the size as an argument.
+Here's an example that uses the fft to produce a sum of sinusoids each with arbitrary amplitude
+and initial-phase:
+</p>
+<pre>
+(define (fft-&gt;sines amps phases)
+ (let* ((len (length phases))
+ (fft-size (expt 2 (+ 10 (ceiling (log len 2)))))
+ (rl (make-vct fft-size))
+ (im (make-vct fft-size)))
+ (do ((i 0 (+ i 1)))
+ ((= i len))
+ (let ((amp (vct-ref amps i))
+ (phase (vct-ref phases i)))
+ (vct-set! rl (+ i 1) (* amp (sin phase)))
+ (vct-set! im (+ i 1) (* amp (cos phase)))))
+ (<em class=red>fft</em> rl im -1)
+ rl))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-spectrum -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndspectrum">snd-spectrum</a> (data window length :optional (linear #t) (beta 0.0) in-place (normalized #t))</code>
+</td></tr><tr><td></td><td>
+This returns the spectrum (as a vct) of 'data' (also a vct) using the fft window 'win'.
+'length' is the number of samples
+of data.
+<pre>
+ (let ((spectr (snd-spectrum data rectangular-window (<a class=quiet href="#transformsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_transformsize_tip)">transform-size</a>))))
+ ...)
+</pre>
+If 'linear' is #f (its default is #t), the spectrum is in dB.
+'beta' is the fft data window family parameter; it is scaled internally so here it should be between 0.0 and 1.0.
+If 'in-place' is #t, the spectrum is in 'data', otherwise snd-spectrum returns a new vct.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- transform? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="transformp">transform?</a> (type)</code>
+</td></tr><tr><td></td><td>
+This returns #t if 'type' refers to an active transform type.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+</table>
+
+<p>Other related variables and functions:</p>
+<table cellpadding=0 cellspacing=1 border=0 hspace=20>
+<tr><td width=200><a href="#transformgraphp"><small>transform-graph?</small></a></td><td width=200><a href="#showtransformpeaks"><small>show-transform-peaks</small></a></td><td><a href="#transformsample"><small>transform-sample</small></a></td></tr>
+<tr><td><a href="#fftbeta"><small>fft-window-beta</small></a></td><td><a href="#showselectiontransform"><small>show-selection-transform</small></a></td><td><a href="#transformtovct"><small>transform-&gt;vct</small></a></td></tr>
+<tr><td><a href="#aftertransformhook"><small>after-transform-hook</small></a></td><td><a href="#spectrumend"><small>spectrum-end</small></a></td><td><a href="#transformframes"><small>transform-frames</small></a></td></tr>
+<tr><td><a href="#fftlogfrequency"><small>fft-log-frequency</small></a></td><td><a href="#spectrohop"><small>spectro-hop</small></a></td><td><a href="#transformtype"><small>transform-type</small></a></td></tr>
+<tr><td><a href="#fftlogmagnitude"><small>fft-log-magnitude</small></a></td><td><a href="#spectrumstart"><small>spectrum-start</small></a></td><td><a href="#updatetransformgraph"><small>update-transform-graph</small></a></td></tr>
+<tr><td><a href="#transformsize"><small>transform-size</small></a></td><td><a href="#spectroxangle"><small>spectro-x-angle</small></a></td><td><a href="#normalizefft"><small>transform-normalization</small></a></td></tr>
+<tr><td><a href="#transformgraphtype"><small>transform-graph-type</small></a></td><td><a href="#spectroxscale"><small>spectro-x-scale</small></a></td><td><a href="#zeropad"><small>zero-pad</small></a></td></tr>
+<tr><td><a href="#fftwindow"><small>fft-window</small></a></td><td><a href="#spectroyangle"><small>spectro-y-angle</small></a></td><td><a href="#wavelettype"><small>wavelet-type</small></a></td></tr>
+<tr><td><a href="#maxfftpeaks"><small>max-transform-peaks</small></a></td><td><a href="#spectroyscale"><small>spectro-y-scale</small></a></td><td><a href="#spectrozscale"><small>spectro-z-scale</small></a></td></tr>
+<tr><td><a href="#mindb"><small>min-dB</small></a></td><td><a href="#spectrozangle"><small>spectro-z-angle</small></a></td><td></td></tr>
+</table>
+
+<p>Some FFT-based effects and editing functions:
+</p>
+<!-- INDEX fftexamples:FFTs -->
+<A NAME="fftexamples"></a>
+<TABLE border=3 bordercolor="tan" hspace=20><tr><td>
+<small><blockquote>
+CLM fft function: <a href="sndclm.html#fft">mus-fft</a><br>
+CLM spectrum: <a href="sndclm.html#spectrum">spectrum</a><br>
+Snd spectrum: <a href="#sndspectrum">snd-spectrum</a><br>
+autocorrelation: <a href="sndclm.html#autocorrelate">autocorrelate</a><br>
+cross correlation: <a href="sndclm.html#correlate">correlate</a>, <a href="sndscm.html#displaycorrelation">display-correlation</a><br>
+FFT window: <a href="sndclm.html#make-fft-window">make-fft-window</a><br>
+Dolph-Chebyshev window in Scheme: <a href="sndscm.html#dolph">dolph</a><br>
+Hartley transform in Scheme: <a href="sndscm.html#dht">dht</a><br>
+Spectral edit dialog: <a href="snd.html#editenvelope">Envelope Editor</a><br>
+<br>
+fft-based filter: <a href="sndscm.html#fftedit">fft-edit</a>, <a href="sndscm.html#fftenvedit">fft-env-edit</a>, <a href="sndscm.html#fftenvinterp">fft-env-interp</a>, <a href="sndscm.html#fftsquelch">fft-squelch</a>, <a href="sndscm.html#fftcancel">fft-cancel</a><br>
+phase-vocoder: <a href="sndclm.html#phase-vocoder">phase-vocoder</a>. <a href="sndscm.html#pvocdoc">pvoc</a><br>
+transposition via fft: <a href="sndscm.html#downoct">down-oct</a><br>
+phase rotation via fft: <a href="sndscm.html#zerophase">zero-phase, rotate-phase</a><br>
+duration change via autocorrelation: <a href="sndscm.html#rubberdoc">rubber-sound</a><br>
+smoothing via fft: <a href="sndscm.html#fftsmoother">fft-smoother</a><br>
+cross-synthesis: <a href="sndscm.html#crosssynthesis">cross-synthesis</a><br>
+voiced-&gt;unvoiced effect: <a href="sndscm.html#voicedtounvoiced">voiced-&gt;unvoiced</a><br>
+noise reduction: <a href="sndscm.html#cleanchannel">clean-channel</a>, <a href="sndscm.html#clminsdoc">anoi</a><br>
+power spectral density: green.scm<br>
+spectral modeling: <a href="sndscm.html#clminsdoc">pins</a><br>
+polynomial approach to spectral multiplies (convolution): <a href="sndscm.html#spectralpolynomial">spectral-polynomial</a><br>
+<br>
+Superimpose ffts: <a href="sndscm.html#superimposeffts">superimpose-ffts</a><br>
+Waterfall real-time spectrograph: <a href="sndscm.html#startwaterfall">start-waterfall</a><br>
+Simple rt spectrum: <a href="sndscm.html#showinputfft">show-input-fft</a>, <a href="sndscm.html#showdraggableinputfft">show-draggable-input-fft</a><br>
+More transforms: <a href="sndscm.html#fractionalfouriertransform">fractional-fourier-transform</a>, <a href="sndscm.html#ztransform">z-transform</a> in dsp.scm<br>
+3D (single) fft display: <a href="sndscm.html#complexify">complexify</a><br>
+bark, mel, erb scale display: <a href="sndscm.html#displaybarkfft">display-bark-fft</a><br>
+apply function to spectrum, inverse fft: <a href="sndscm.html#filterfft">filter-fft</a><br>
+</blockquote></small>
+</td></tr></TABLE>
+
+<br>
+<!-- Dialogs -->
+<br>
+<table width="80%" border=0><tr><td bgcolor="lightsteelblue" valign="middle"><h3><A NAME="snddialogs">Dialogs and Other Widgets</a></h3></td></tr></table>
+
+<p>The built-in dialogs, accessible from the main menu, provide the standard, but sometimes clumsy
+ways to open and save sounds, edit envelopes and headers, and set various global variables.
+In addition, many other dialogs are implemented in various Scheme/Ruby/Forth files.
+The following
+functions refer to the built-in dialogs. They were aimed originally at semi-internal needs like
+saving the current Snd state, but might be useful elsewhere.
+Functions such as color-orientation-dialog normally create and start the dialog in question; that is,
+<code>(color-orientation-dialog)</code> puts the color/orientation dialog on the screen. If you're trying instead to
+customize the dialog in some way (in your initialization file, for example), you want the
+dialog to be created (so that the various widget children exist), but don't want it to pop
+up on the screen ('managed' in X jargon). So, most of the dialog functions have a 'managed' argument
+that defaults to #t. If #f, the dialog is created, if need be, but not started.
+install-searcher in snd-motif.scm, which adds customized file filtering code
+to the File:Open dialog, first makes sure the dialog exists with <code>(open-file-dialog #f)</code>.
+</p>
+
+
+<!-- -------------------------------- DIALOG TABLE -------------------------------- -->
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- add-directory-to-view-files-list -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="adddirectorytoviewfileslist">add-directory-to-view-files-list</a> (dir :optional dialog)</code>
+</td></tr><tr><td></td><td>
+This adds the sound files in directory 'dir' to the list of files in the View:Files dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- add-file-to-view-files-list -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addfiletoviewfileslist">add-file-to-view-files-list</a> (file :optional dialog)</code>
+</td></tr><tr><td></td><td>
+This adds 'file' to the list of files in the View:Files dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- add-file-filter -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addfilefilter">add-file-filter</a> (name func)</code>
+</td></tr><tr><td></td><td>
+This adds 'func' to the file filter list under the name 'name'. The file filter list is a list
+of functions, accessed from drop-down menus in the various file-related dialogs. Each such function
+filters the list of files displayed by the dialog, so that only some interesting subset is posted.
+The built-in filter is <a href="#justsounds">just-sounds</a> which uses the sound file extension
+tables to decide which files are sounds, omitting all others from the file lists.
+You can add your own filters to this
+menu with add-file-filter. The 'name' appears as the menu item label corresponding to the function.
+The function should take one argument, a file name, and return #t to retain that file in the file list.
+add-file-filter returns an integer to identify 'func' in other contexts.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>add-file-filter</em>
+ "mono"
+ (lambda (a)
+ "filter out all but mono sound files"
+ (and (<a class=quiet href="#soundfilep" onmouseout="UnTip()" onmouseover="Tip(extsnd_soundfilep_tip)">sound-file?</a> a)
+ (= (channels a) 1))))
+</pre></td></tr></table></td></tr>
+<tr><td colspan=2 height=16></td></tr>
+
+
+<!-- add-file-sorter -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addfilesorter">add-file-sorter</a> (name func)</code>
+</td></tr><tr><td></td><td>
+This adds 'func' to the file-sorter list under the name 'name'. Some dialog file lists include
+a "sort" menu to reorder the files in the file list. You can add your own sort functions to this
+menu with add-file-sorter. The 'name' appears as the menu item label corresponding to the function.
+The new sorter's index is returned; it is an integer for use with functions such as <a href="#viewfilessort">view-files-sort</a>.
+The function should take two arguments, each a filename, and return a strcmp-like number describing
+how to sort the pair. The following adds a sorter named "duration" that sorts files from shorter
+to longer:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+ (<em class=red>add-file-sorter</em>
+ "duration"
+ (lambda (a b)
+ "sort by duration from short to long"
+ (let ((dur1 (<a class=quiet href="#mussoundduration" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundduration_tip)">mus-sound-duration</a> a))
+ (dur2 (<a class=quiet href="#mussoundduration" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundduration_tip)">mus-sound-duration</a> b)))
+ (if (&gt; dur1 dur2) 1
+ (if (&lt; dur1 dur2) -1 0)))))
+</pre></td></tr></table></td></tr>
+<tr><td colspan=2 height=16></td></tr>
+
+
+<!-- add-sound-file-extension -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addsoundfileextension">add-sound-file-extension</a> (ext)</code>
+</td></tr><tr><td></td><td>
+This adds 'ext' to the list of (case sensitive) sound file extensions used by <a href="#soundfilesindirectory">sound-files-in-directory</a>.
+The initial list is ("snd" "aiff" "aif" "wav" "au" "aifc" "voc" "wve" "WAV" "sf2" "rf64" "caf").
+To add "ogg" as a recognized extension:
+<pre>
+ (add-sound-file-extension "ogg")
+</pre>
+The list itself is <a href="#soundfileextensions">sound-file-extensions</a>.
+See also <a href="sndscm.html#matchsoundfiles">add-sound-file-extension-1</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- add-to-main-menu -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="addtomainmenu">add-to-main-menu</a> (menu-label :optional update-callback)</code>
+</td></tr><tr><td></td><td>
+This adds a new top-level menu named 'menu-label' and returns its menu index. The index
+identifies the menu for add-to-menu and others.
+'update-callback' is a procedure of no arguments that is
+called each time the menu is displayed.
+<pre>
+ Scheme:
+ (define new-menu (add-to-main-menu "New Menu"))
+ (<a class=quiet href="#addtomenu" onmouseout="UnTip()" onmouseover="Tip(extsnd_addtomenu_tip)">add-to-menu</a> new-menu "First Item" (lambda () (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> ";item 1")))
+ (<a class=quiet href="#addtomenu" onmouseout="UnTip()" onmouseover="Tip(extsnd_addtomenu_tip)">add-to-menu</a> new-menu "Second Item" (lambda () (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> ";item 2")))
+
+ Ruby:
+ new_menu = add_to_main_menu("New Menu")
+ add_to_menu(new_menu, "First Item", lambda do | | snd_print("item 1") end)
+ add_to_menu(new_menu, "Second Item", lambda do | | snd_print("item 2") end)
+
+ Forth:
+ "New Menu" add-to-main-menu constant new-menu drop
+ new-menu "First Item" lambda: &lt;{ }&gt; "item1" snd-print ; undef add-to-menu drop
+ new-menu "Second Item" lambda: &lt;{ }&gt; "item2" snd-print ; undef add-to-menu drop
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- add-to-menu -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="addtomenu">add-to-menu</a> (top-menu menu-label callback :optional position)</code>
+</td></tr><tr><td></td><td>
+This adds the menu 'menu-label' to the top-level menu whose index is
+'top-menu' with the callback function 'callback', then returns the new menu label widget.
+The built-in
+Snd menus are numbered from 0 ('File') to 5 ('Popup'); 'Help' is menu 4. If the label and callback are #f, a separator is added to the menu.
+'position' sets the position of the new menu option; it defaults to the end of the menu. See new-effects.scm for many examples.
+<pre>
+ (<em class=red>add-to-menu</em> 1 "Stop Playing"
+ (lambda () (<a class=quiet href="#stopplaying" onmouseout="UnTip()" onmouseover="Tip(extsnd_stopplaying_tip)">stop-playing</a>)))
+
+ (<em class=red>add-to-menu</em> 5 "Reduce height"
+ (lambda () (set! (<a class=quiet href="#windowheight" onmouseout="UnTip()" onmouseover="Tip(extsnd_windowheight_tip)">window-height</a>) (/ (<a class=quiet href="#windowheight" onmouseout="UnTip()" onmouseover="Tip(extsnd_windowheight_tip)">window-height</a>) 2))))
+</pre></td></tr>
+<tr><td></td><td>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- channel-widgets -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="channelwidgets">channel-widgets</a> ()</code>
+</td></tr><tr><td></td><td>
+channel-widgets returns a list of various widgets associated with a given channel:
+<pre>
+ 0: graph ;drawing area for all 3 graphs (time, fft, lisp)
+ 1: w-button
+ 2: f-button
+ 3: x-position slider
+ 4: y-position slider
+ 5: x-zoom slider
+ 6: y-zoom slider
+ 7: edit history list
+ 8: right(united-chans) y-position slider
+ 9: right y-zoom slider
+ 10: main pane for channel
+ ------ the rest only in Gtk+
+ 11..16: adjustment widgets associated with the zoom and position sliders
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- clear-listener -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="clearlistener">clear-listener</a> ()</code>
+</td></tr><tr><td width=30></td><td>
+This deletes all listener text from the beginning to the cursor position (C-M-g is bound to this function).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- color-orientation-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="colororientationdialog">color-orientation-dialog</a> (:optional managed)</code>
+</td></tr><tr><td width=30></td><td>
+This creates and (if 'managed' which defaults to #t) activates the Color/Orientation dialog; it returns the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- define-envelope -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="defineenvelope">define-envelope</a> (name data :optional (base 1.0))</code>
+</td></tr><tr><td></td><td>
+This adds an envelope to the envelope editor's list, under the name 'name', using the list of breakpoints
+'data', and the optional 'base'. If the 'base' is omitted, this is the same as <a href="#defvar">defvar</a>.
+<pre>
+ Scheme: (define-envelope ramp '(0 0 1 1))
+ Ruby: define_envelope("ramp", [0, 0, 1, 1])
+ Forth: $" ramp" '( 0.0 0.0 1.0 1.0 ) 1.0 define-envelope
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- defvar -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="defvar">defvar</a> (var val)</code>
+</td></tr><tr><td></td><td>
+This is the same as <code>(define var val)</code> except that the envelope editor keeps track
+of 'var' thereafter and treats lists as envelopes.
+defvar exists in this context so that Snd and CLM can share envelope files.
+<pre>
+ (defvar a-func '(0 0 1 1))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- delete-file-filter -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="deletefilefilter">delete-file-filter</a> (index)</code>
+</td></tr><tr><td></td><td>
+This removes the file filter function associated with 'index' from the file filter list.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- delete-file-sorter -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="deletefilesorter">delete-file-sorter</a> (index)</code>
+</td></tr><tr><td></td><td>
+This removes the file sorter function associated with 'index' from the file sorter list.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- dialog-widgets -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="dialogwidgets">dialog-widgets</a> ()</code>
+</td></tr><tr><td></td><td>
+dialog-widgets returns a list of dialog widgets (or lists thereof, or #f if none yet):
+<pre>
+ 0: View: Color/Orientation dialog
+ 2: Edit: EnvelopeEditor dialog
+ 3 and 4: unused
+ 5: Options: Transform dialog
+ 6: File: Open dialog
+ 7: File: Save as dialog
+ 8: View: Files dialog
+ 9: raw data dialog (activated when raw sound opened, sometimes)
+ 10: File: New sound dialog
+ 11: File: Mix dialog
+ 12: Edit: Edit header dialog
+ 13: Edit: Find dialog
+ 14: Help dialog
+ 16: View: Mixes dialog
+ 17: File: Print dialog
+ 18: File: Recorder dialog
+ 19: View: Regions dialog
+ 20: info dialog (activated by info-dialog function)
+ 22: Edit: Selection Save as dialog
+ 23: File: Insert file dialog
+ 24: region save as dialog (from regions dialog save button)
+ 25: Options: Preferences dialog
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- edit-header-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="editheaderdialog">edit-header-dialog</a> (snd) </code>
+</td></tr><tr><td></td><td>
+This starts the Edit Header dialog on 'snd', returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-base -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedbase">enved-base</a> () </code>
+</td></tr><tr><td></td><td>
+This is the envelope editor exponential base value.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-clip? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedclipping">enved-clip?</a> ()</code>
+</td></tr><tr><td></td><td>
+This reflects the state of the envelope editor 'clip' button.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="enveddialog">enved-dialog</a> ()</code>
+</td></tr><tr><td></td><td>
+This starts the envelope editor dialog, returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-envelope -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedenvelope">enved-envelope</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the envelope (a list of breakpoints) in the envelope editor's graph window.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-filter -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="filterenv">enved-filter</a> ()</code>
+</td></tr><tr><td></td><td>
+This reflects the type of the envelope editor's filter (the default #t means FIR; #f is FFT). To get the FFT display in the envelope editor
+as the default:
+<pre>
+ (set! (<em class=red>enved-filter)</em> #f)
+ (set! (<a class=quiet href="#envedwaving" onmouseout="UnTip()" onmouseover="Tip(extsnd_envedwaving_tip)">enved-wave?</a>) #t)
+ (set! (<a class=quiet href="#envedtarget" onmouseout="UnTip()" onmouseover="Tip(extsnd_envedtarget_tip)">enved-target</a>) <a class=quiet href="#envedtarget" onmouseout="UnTip()" onmouseover="Tip(extsnd_envedtarget_tip)">enved-spectrum</a>)
+</pre></td></tr>
+
+
+<!-- enved-filter-order -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="filterenvorder">enved-filter-order</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the order of the envelope editor's FIR filter (the default is 40).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-in-dB -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedin-dB">enved-in-dB</a> ()</code>
+</td></tr><tr><td></td><td>
+This reflects the state of the envelope editor 'dB' button (it defaults to #f).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-power -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedpower">enved-power</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the envelope editor's base scale range (it defaults to 3.0).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedstyle">enved-style</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the envelope editor choice for connecting breakpoints. It can be <code>envelope-linear</code> (the default), or
+<code>envelope-exponential</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-target -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedtarget">enved-target</a> ()</code>
+</td></tr><tr><td></td><td>
+This determines how the envelope editor's current envelope is applied to the selected data.
+The choices are <code>enved-amplitude</code>, <code>enved-srate</code> and <code>enved-spectrum</code>.
+The first treats the envelope as an amplitude envelope, the second as an srate curve (changing speed),
+and the last as a frequency response envelope for a filter.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-waveform-color -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedwaveformcolor">enved-waveform-color</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the color of the waveform displayed in envelope editor (the default is blue).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- enved-wave? -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="envedwaving">enved-wave?</a> ()</code>
+</td></tr><tr><td></td><td>
+This reflects the state of the envelope editor 'wave' button.
+The wave shown is the time domain display, even when filtering.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- find-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="finddialog">find-dialog</a> (:optional managed text) </code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t) starts the Edit:Find dialog, returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- focus-widget -->
+<tr><td bgcolor="#f2f4ff" colspan=2>
+<code><a class=def name="focuswidget">focus-widget</a> (widget)</code>
+</td></tr><tr><td></td><td>
+This gives 'widget' "focus" &mdash; it becomes the active widget, receiving keystrokes and so on.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- gl-graph->ps -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="glgraphtops">gl-graph-&gt;ps</a> (:optional file (type 0) snd chn)</code>
+</td></tr><tr><td></td><td>
+This creates a Postscript picture of the current openGL display in snd's channel chn (a spectrogram).
+'file' defaults to <a href="#epsfile">eps-file</a>.
+'type' can be 0: eps, 1: ps, 2: pdf, 3: tex, 4: svg, or 5: pgf.
+This function is available only if OpenGL and gl2ps have been loaded (via the --with-gl and
+--with-gl2ps configuration switches).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- goto-listener-end -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="gotolistenerend">goto-listener-end</a></code>
+</td></tr><tr><td></td><td>
+This moves the cursor to the end of the listener text, and scrolls the window so that it is visible.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- graph->ps -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="graphtops">graph-&gt;ps</a> (:optional file)</code>
+</td></tr><tr><td></td><td>
+This creates a Postscript picture of the current display.
+'file' defaults to <a href="#epsfile">eps-file</a>.
+See also <a href="#epsbottommargin">eps-bottom-margin</a>, <a href="#epsleftmargin">eps-left-margin</a>,
+and <a href="#epssize">eps-size</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- help-dialog -->
+<tr><td colspan=2 valign=top><code><a class=def name="helpdialog">help-dialog</a> (subject help-string :optional xrefs urls) </code>
+</td></tr><tr><td></td><td>
+This starts the help dialog with the title 'subject' and help area text 'help', returning the dialog widget.
+'xrefs' is an optional list of strings to post in the "related items" list. 'urls' is a corresponding
+list of urls.
+<pre>
+ (help-dialog "xyzzy" "are we having fUn?")
+</pre>
+There are many examples in new-effects.scm.
+
+<table border=0 cellpadding=5 vspace=10><tr><td>
+<pre>
+(defmacro with-snd-help (form)
+ ;; if an error occurs while evaluating form, try to start the help dialog with some relevant help
+ `(catch #t
+ (lambda ()
+ ,form)
+ (lambda args
+ (if (and args (cadr args) (string? (cadr args)))
+ (let* ((func (if (string=? "set!" (substring (cadr args) 0 4))
+ (substring (cadr args) 5)
+ (cadr args)))
+ (help (<a class=quiet href="#sndhelp" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndhelp_tip)">snd-help</a> func)))
+ (if help (<em class=red>help-dialog</em> func help))))
+ args)))
+</pre>
+</td></tr></table>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- hide-widget -->
+<tr><td bgcolor="#f2f4ff" colspan=2>
+<code><a class=def name="hidewidget">hide-widget</a> (widget)</code>
+</td></tr><tr><td></td><td>
+This hides (unmanages) 'widget'.
+To remove the y-position slider (which is only there
+for looks):
+<pre>
+ (<a class=quiet href="#hidewidget" onmouseout="UnTip()" onmouseover="Tip(extsnd_hidewidget_tip)">hide-widget</a> (list-ref (<a class=quiet href="#channelwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_channelwidgets_tip)">channel-widgets</a>) 4))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- info-dialog -->
+<tr><td colspan=2 valign=top><code><a class=def name="infodialog">info-dialog</a> (subject info) </code>
+</td></tr><tr><td></td><td>
+This starts the info dialog with the title 'subject' and body 'info' returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- insert-file-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="insertfiledialog">insert-file-dialog</a> (:optional managed)</code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t) activates the File:Insert dialog, returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- listener-color -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="listenercolor">listener-color</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the background color of listener.
+<pre>
+ (set! (listener-color) (<a class=quiet href="#makecolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_makecolor_tip)">make-color</a> 0 0 0))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- listener-font -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="listenerfont">listener-font</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the listener font.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- listener-prompt -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="listenerprompt">listener-prompt</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the listener prompt which defaults to "&gt;". I like ":" better (as you can see in many of the examples in this file),
+so in ~/.snd_s7 I have this line:
+<pre>
+ (set! (listener-prompt) ":")
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- listener-selection -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="listenerselection">listener-selection</a> ()</code>
+</td></tr><tr><td></td><td>
+
+listener-selection returns the currently selected text in the listener, or #f if there isn't any. The following code
+starts the help dialog with help related to the selection if "h" is typed in the graph:
+<pre>
+ (<a class=quiet href="#bindkey" onmouseout="UnTip()" onmouseover="Tip(extsnd_bindkey_tip)">bind-key</a> #\h 0
+ (lambda ()
+ "start help dialog based on listener selected text"
+ (let ((subject (<em class=red>listener-selection</em>)))
+ (if subject
+ (<a class=quiet href="#helpdialog" onmouseout="UnTip()" onmouseover="Tip(extsnd_helpdialog_tip)">help-dialog</a> subject (<a class=quiet href="#sndhelp" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndhelp_tip)">snd-help</a> subject))))))
+</pre>
+<p>But it's probably more convenient to use the <a href="#listenerclickhook">listener-click-hook</a>
+and click-for-listener-help (draw.scm).
+</p>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- listener-text-color -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="listenertextcolor">listener-text-color</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the text color in the listener. For red text on a black background:
+<pre>
+ (set! (listener-color) (make-color 0 0 0)) ; in Gtk, maybe a bad idea &mdash; the cursor remains black...
+ (set! (listener-text-color) (make-color 1 0 0))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- main-menu -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mainmenu">main-menu</a> (menu)</code>
+</td></tr><tr><td></td><td>
+main-menu returns the top-level menu
+associated with its integer argument:
+<pre>
+ 0: File menu
+ 1: Edit menu
+ 2: View menu
+ 3: Options menu
+ 4: Help menu
+ 5: built-in popup menu
+ and others as added by add-main-menu
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- main-widgets -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mainwidgets">main-widgets</a> ()</code>
+</td></tr><tr><td></td><td>
+main-widgets returns a list of the top-level widgets in Snd (#f if not created):
+<pre>
+ 0: top-level-application ; XtAppContext in Motif, top level window in Gtk+
+ 1: top-level-shell
+ 2: main-pane ; outer paned window top window (holds sounds)
+ 3: main-sound-pane
+ 4: listener-pane ; outer paned window bottom window
+ 5: notebook-outer-pane
+</pre>
+
+For example, to get at Snd's main shell widget:
+<pre>
+ Scheme: (cadr (main-widgets))
+ Ruby: main_widgets.cadr
+ Forth: main-widgets cadr
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- menu-widgets -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="menuwidgets">menu-widgets</a> ()</code>
+</td></tr><tr><td></td><td>
+menu-widgets returns the top-level menu widgets (cascade menus in Motif or menu bars in Gtk+)
+as a list:
+<pre>
+ 0: top-level-menu-bar
+ 1: file-menu
+ 2: edit-menu
+ 3: view-menu
+ 4: options-menu
+ 5: help-menu,
+ 6: default popup menu
+</pre>
+See snd-motif.scm, snd-gtk.scm, kmenu.scm, and new-effects.scm for various examples.
+Manipulating menus can be tricky in both Motif and Gtk; if I were to try to explain
+submenus and whatnot here, I'd only get tangled up in half-forgotten complications.
+When I have to deal with this stuff, I always go to a working example.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-dialog-mix -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixdialogmix">mix-dialog-mix</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the id (mix object) of the mix displayed by the mix dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mix-file-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="mixfiledialog">mix-file-dialog</a> (:optional managed)</code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t) activates the File:Mix dialog,
+returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- new-sound-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="newsounddialog">new-sound-dialog</a> (:optional managed) </code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t)
+starts the File:New sound dialog, returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- open-file-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="openfiledialog">open-file-dialog</a> (:optional managed)</code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t) activates the File:Open dialog,
+returning the dialog widget.
+If the xm module is loaded, we could add our own info via:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+ (let* ((dialog (<em class=red>open-file-dialog</em> #f))
+ (rc (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(sndscm_findchild_tip)">find-child</a> dialog "info-rc2")) ; holds the info labels if a sound file is selected
+ (label (XtCreateManagedWidget "file-preview-info" xmLabelWidgetClass rc
+ (list XmNbackground (<a class=quiet href="#highlightcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_highlightcolor_tip)">highlight-color</a>)))))
+ (XtAddCallback (XmFileSelectionBoxGetChild dialog XmDIALOG_LIST)
+ XmNbrowseSelectionCallback
+ (lambda (widget context info)
+ (let ((file (cadr (XmStringGetLtoR (.item info) XmFONTLIST_DEFAULT_TAG))))
+ (XtVaSetValues label
+ (list XmNlabelString
+ (XmStringCreateLtoR (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~A: no comment" file)
+ XmFONTLIST_DEFAULT_TAG)))))
+ #f))
+</pre></td></tr></table></td></tr>
+<tr><td colspan=2 height=16></td></tr>
+
+
+<!-- preferences-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="preferencesdialog">preferences-dialog</a> ()</code>
+</td></tr><tr><td></td><td>
+This activates the Options:Preferences dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- print-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="printdialog">print-dialog</a> (:optional managed direct-to-printer)</code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t) activates the File:Print dialog, returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- recorder-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="recorderdialog">recorder-dialog</a> ()</code>
+</td></tr><tr><td></td><td>
+This starts the <a href="snd.html#recordfile">recorder</a> window, returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- remove-from-menu -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="removefrommenu">remove-from-menu</a> (top-menu menu-label)</code>
+</td></tr><tr><td></td><td>
+This removes the menu 'menu-label' from the top top-level menu whose index is 'top-menu'. See examp.scm or snd-motif.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- reset-listener-cursor -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="resetlistenercursor">reset-listener-cursor</a> ()</code>
+</td></tr><tr><td></td><td>
+This resets the listener cursor to the default pointer shape.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-envelopes -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="saveenvelopes">save-envelopes</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This saves the envelope editor envelopes in 'filename'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-listener -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="savelistener">save-listener</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This saves the listener contents in 'filename'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-region-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="saveregiondialog">save-region-dialog</a> (:optional managed) </code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t)
+starts the Region Save-as dialog (to save the current Region browser region), returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-selection-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="saveselectiondialog">save-selection-dialog</a> (:optional managed) </code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t)
+starts the Edit:Save selection as dialog (to save the current selection), returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-sound-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="savesounddialog">save-sound-dialog</a> (:optional managed) </code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t)
+starts the File:Save as dialog (to save the currently selected sound), returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- show-listener -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="showlistener">show-listener</a> ()</code>
+</td></tr><tr><td></td><td>
+If show-listener is set to #t, it opens the listener pane; otherwise it closes the listener.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- show-widget -->
+<tr><td bgcolor="#f2f4ff" colspan=2>
+<code><a class=def name="showwidget">show-widget</a> (widget)</code>
+</td></tr><tr><td></td><td>
+This shows (manages) 'widget'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-file-extensions -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="soundfileextensions">sound-file-extensions</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the list of sound file extensions used by the "just-sounds" buttons and
+<a href="#soundfilesindirectory">sound-files-in-directory</a> to try to recognize
+sound files. It is settable: a list of extensions as strings:
+<pre>
+ (set! (sound-file-extensions)
+ (list "snd" "aiff" "aif" "wav" "au" "aifc" "voc" "wve" "WAV" "sf2" "rf64" "caf"))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-file? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="soundfilep">sound-file?</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This returns #t if 'filename' has an extension that matches one in the <a href="#soundfileextensions">sound-file-extensions</a> list.
+<pre>
+ :<em class=typing>(sound-file? "oboe.snd")</em>
+ <em class=listener>#t</em>
+ :<em class=typing>(sound-file? "extsnd.html")</em>
+ <em class=listener>#f</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-files-in-directory -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="soundfilesindirectory">sound-files-in-directory</a> (:optional dir)</code>
+</td></tr><tr><td></td><td>
+This returns a list of the sound files found in 'dir'. A file is considered a sound if it has data and
+its extension is on the sound file extension list (see <a href="#addsoundfileextension">add-sound-file-extension</a>).
+The directory name defaults to the current directory.
+This is useful for batch processing of sounds. The following
+prints the names of all the stereo AIFC files it finds:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(for-each
+ (lambda (filename)
+ (if (and (= (<a class=quiet href="#mussoundheadertype" onmouseout="UnTip()" onmouseover="Tip(extsnd_mussoundheadertype_tip)">mus-sound-header-type</a> filename) <a class=quiet href="#headertype" onmouseout="UnTip()" onmouseover="Tip(extsnd_headertype_tip)">mus-aifc</a>)
+ (= (channels filename) 2))
+ (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~%~A" filename))))
+ (<em class=red>sound-files-in-directory</em>))
+</pre></td></tr></table>
+
+See also <a href="sndscm.html#mapsoundfiles">map-sound-files</a> in extensions.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- sound-widgets -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="soundwidgets">sound-widgets</a> ()</code>
+</td></tr><tr><td></td><td>
+sound-widgets returns a list of various widgets specific to a given sound:
+<pre>
+ 0: main-pane
+ 1: name-label ; sound's file name
+ 2: control-panel
+ 3: minibuffer
+ 4: play button
+ 5: filter-graph ; control panel drawing area for filter envelope
+ 6: unite button ; invisible in mono sounds
+ 7: minibuffer-label ; prompt area for the minibuffer
+ 8: name-icon ; hour-glass or whatever
+ 9: sync button
+</pre>
+
+For example, we can read and write the minibuffer:
+<pre>
+ Scheme:
+ :<em class=typing>(report-in-minibuffer "this is a test")</em>
+ <em class=listener>"this is a test"</em>
+ :<em class=typing>(widget-text (list-ref (sound-widgets) 3))</em>
+ <em class=listener>"this is a test"</em>
+
+ Ruby:
+ :<em class=typing>report_in_minibuffer("this is a test")</em>
+ <em class=listener>this is a test</em>
+ :<em class=typing>widget_text(sound_widgets()[3])</em>
+ <em class=listener>this is a test</em>
+
+ Forth:
+ <em class=listener>snd&gt;</em> <em class=typing>"this is a test" report-in-minibuffer</em>
+ <em class=listener>this is a test</em>
+ <em class=listener>snd&gt;</em> <em class=typing>0 sound-widgets 3 list-ref widget-text</em>
+ <em class=listener>this is a test</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- transform-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="transformdialog">transform-dialog</a> (:optional managed)</code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t) activates the Options:Transform dialog, returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-files-amp -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewfilesamp">view-files-amp</a> (dialog)</code>
+</td></tr><tr><td></td><td>
+This is the value of the amplitude slider in the View:Files dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-files-amp-env -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewfilesampenv">view-files-amp-env</a> (dialog)</code>
+</td></tr><tr><td></td><td>
+This is the amplitude envelope displayed in the View:Files dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-files-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewfilesdialog">view-files-dialog</a> (:optional managed)</code>
+</td></tr><tr><td></td><td>
+This creates and (if 'managed' which defaults to #t) activates a
+View:Files <a href="snd.html#viewfiles">dialog</a> and returns the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-files-files -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewfilesfiles">view-files-files</a> (dialog)</code>
+</td></tr><tr><td></td><td>
+This is the file list (a list of strings) of a View:Files dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-files-selected-files -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewfilesselectedfiles">view-files-selected-files</a> (dialog)</code>
+</td></tr><tr><td></td><td>
+This is the list of selected files (a list of strings) in a View:Files dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-files-sort -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewfilessort">view-files-sort</a> (:optional dialog)</code>
+</td></tr><tr><td></td><td>
+This is the sort function choice in a View:Files dialog. Initially there are 6 sort choices: a..z, z..a (sort by file name),
+new..old, old..new (sort by file write date), and small..big, big..small (sort by file size). The default is 0 (a..z).
+If you set view-files-sort without giving the dialog argument, it just affects the startup state of subsequent new View:Files
+dialogs. To set the sort choice in the current dialog:
+<pre>
+ (set! (view-files-sort (list-ref (<a class=quiet href="#dialogwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_dialogwidgets_tip)">dialog-widgets</a>) 8)) 2) ; 2=new..old
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-files-speed -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewfilesspeed">view-files-speed</a> (dialog)</code>
+</td></tr><tr><td></td><td>
+This is the value of the speed slider in a View:Files dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-files-speed-style -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewfilesspeedstyle">view-files-speed-style</a> (dialog)</code>
+</td></tr><tr><td></td><td>
+This is the speed style choice in a View:Files dialog. It is one of <code>speed-control-as-float</code> (the default),
+<code>speed-control-as-ratio</code>, or <code>speed-control-as-semitone</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-mixes-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewmixesdialog">view-mixes-dialog</a> ()</code>
+</td></tr><tr><td></td><td>
+This creates and activates the View:Mixes Dialog, returning the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- view-regions-dialog -->
+<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="viewregionsdialog">view-regions-dialog</a> ()</code>
+</td></tr><tr><td></td><td>
+This starts the <a href="snd.html#regionbrowser">region browser</a> (a no-op if there are no regions), and returns the dialog widget.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- widget-position -->
+<tr><td bgcolor="#f2f4ff" colspan=2>
+<code><a class=def name="widgetposition">widget-position</a> (widget)</code>
+</td></tr><tr><td></td><td>
+This returns a list giving the widget's x and y coordinates (in pixels). It can be set to reposition the widget.
+See nb.scm where it uses the current window position to try to find a convenient place for the help dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- widget-size -->
+<tr><td bgcolor="#f2f4ff" colspan=2>
+<code><a class=def name="widgetsize">widget-size</a> (widget) </code>
+</td></tr><tr><td></td><td>
+This returns a list giving the widget's width and height (in pixels). It can be set to resize the widget. See nb.scm and examp.scm.
+<pre>
+ (set! (<a class=quiet href="#widgetposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_widgetposition_tip)">widget-position</a> (cadr (<a class=quiet href="#mainwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_mainwidgets_tip)">main-widgets</a>))) (list 300 100))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- widget-text -->
+<tr><td bgcolor="#f2f4ff" colspan=2>
+<code><a class=def name="widgettext">widget-text</a> (widget)</code>
+</td></tr><tr><td></td><td>
+This returns the text widget's text. It can be set.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+</table>
+<!-- end of dialog table -->
+
+
+<br>
+<table width="80%" border=0><tr><td bgcolor="lightsteelblue" valign="middle"><h3><A NAME="sndmisc">Miscellaneous functions</a></h3></td></tr></table>
+
+<p>These functions don't seem to fit anywhere else:</p>
+
+<!-- -------------------------------- MISCELLANEOUS TABLE -------------------------------- -->
+
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- abort -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="abort">abort</a> ()</code>
+</td></tr><tr><td width=30><br></td><td>
+This exits Snd via "abort", presumably to fall into the C debugger. To stop some on-going Snd operation,
+use <a href="#cgp">C-g</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- add-source-file-extension -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addsourcefileextension">add-source-file-extension</a> (ext)</code>
+</td></tr><tr><td><br></td><td>
+add-source-file-extension adds 'ext' to the list of source file extensions.
+<pre>
+ (add-source-file-extension "rbs")
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- add-watcher -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addwatcher">add-watcher</a> (func)</code>
+</td></tr><tr><td><br></td><td>
+add-watcher adds 'func' (a function of no arguments) to the watcher list, and
+returns its id (an integer, used by <a href="#deletewatcher">delete-watcher</a>). Each watcher function is called whenever the current selection
+changes, a sound is opened or closed or set read-only, a sound is selected, or a mark is changed.
+effects-utils.scm (and the gtk version in gtk-effects-utils.scm) use this to make sure the
+"DoIt" button is sensitive only when it can actually do something. In the simplest case, this
+is:
+<pre>
+ Motif: (add-watcher (lambda ()
+ (XtSetSensitive
+ (XmMessageBoxGetChild new-dialog XmDIALOG_OK_BUTTON)
+ (not (null? (<a class=quiet href="#soundp" onmouseout="UnTip()" onmouseover="Tip(extsnd_soundp_tip)">sounds</a>))))))
+ Gtk: (add-watcher (lambda ()
+ (gtk_widget_set_sensitive ok-button (not (null? (<a class=quiet href="#soundp" onmouseout="UnTip()" onmouseover="Tip(extsnd_soundp_tip)">sounds</a>))))))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- bes-* -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><A class=def NAME="besj0">bes-j0</A> (x)</code><br>
+<code><em class=emdef>bes-j1</em> (x)</code><br>
+<code><em class=emdef>bes-jn</em> (n x)</code><br>
+<code><em class=emdef>bes-y0</em> (x)</code><br>
+<code><em class=emdef>bes-y1</em> (x)</code><br>
+<code><em class=emdef>bes-yn</em> (n x)</code><br>
+<code><em class=emdef>bes-i0</em> (n x)</code><br>
+<code><em class=emdef>bes-i1</em> (n x)</code> ; from GSL<br>
+<code><em class=emdef>bes-in</em> (n x)</code><br>
+<code><em class=emdef>bes-k0</em> (x)</code><br>
+<code><em class=emdef>bes-k1</em> (x)</code><br>
+<code><em class=emdef>bes-kn</em> (n x)</code><br>
+</td></tr><tr><td></td><td>
+If the Bessel functions are available from the math library (or GSL), these are J0 and friends.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- bind-key -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="bindkey">bind-key</a> (key state func :optional extended origin) </code>
+</td></tr><tr><td></td><td>
+
+bind-key causes 'key' (an integer or a key name) with modifiers 'state' (and preceding C-x if 'extended') to evaluate 'func'
+when the graph is receiving keysrokes. If bind-key seems to be a no-op, try clicking in the graph to
+force it to take the focus.
+If 'origin' is included, it is the name reported if an error occurs. The default is a description of the key.
+If you include a documentation string in the function, it is included in the Help menu's Key Bindings output.
+<br><br>
+The function ('func' above) should take zero or one arguments and
+return one of the cursor choices telling Snd what
+action (if any) to take after evaluating 'code'.
+Possible return values are:
+<pre>
+ cursor-in-view cursor-on-left cursor-on-right cursor-in-middle keyboard-no-action
+</pre>
+If the function takes one argument,
+that argument is the count (the C-u number prefixed to the keyboard command)
+defaulting to 1 if no prefix is typed.
+<br><br>
+The modifier 'state' is a combination of control = 4 and meta = 8.
+If the key argument is a string (a key name) it has to match exactly one of the known key names.
+In X, these can be found in &lt;X11/xkeysymdef.h&gt;, and in Gtk in gdk/gdkkeysyms.h; in both
+cases, remove the XK_ or GDK_ prefix. So, for example, the key marked "Page Down" is named
+"Page_Down" in both tables. Similarly "+" is "plus".
+
+<pre>
+ Scheme: (bind-key "End" 0 (lambda () "view full sound" (set! (<a class=quiet href="#xbounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_xbounds_tip)">x-bounds</a>) (list 0.0 (/ (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>) (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>))))))
+
+ Ruby: bind_key("End", 0, lambda do || set_x_bounds([0.0, frames.to_f / srate.to_f]) end)
+
+ Forth: "End" 0 lambda: 0.0 #f #f #f frames #f srate f/ 2 >list set-x-bounds ; 0 make-proc bind-key
+</pre>
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>bind-key</em> "Home" 0
+ (lambda ()
+ "move cursor and window to current edit"
+ (let ((ed (<a class=quiet href="#editfragment" onmouseout="UnTip()" onmouseover="Tip(extsnd_editfragment_tip)">edit-fragment</a>)))
+ (<a class=quiet href="#reportinminibuffer" onmouseout="UnTip()" onmouseover="Tip(extsnd_reportinminibuffer_tip)">report-in-minibuffer</a> (<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_format_tip)">format</a> #f "~A" ed))
+ (set! (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) (caddr ed))
+ cursor-in-view)))
+
+(<em class=red>bind-key</em> #\p 0
+ (lambda ()
+ "move cursor to left edge of window"
+ cursor-on-left)
+ #f "#\\p-&gt;cursor-on-left")
+
+(<em class=red>bind-key</em> #\v 4
+ (lambda ()
+ "move ahead one window"
+ (if (&lt; (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a>) (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a>))
+ (set! (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a>) (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a>)))
+ keyboard-no-action))
+
+(<em class=red>bind-key</em> #\v 0
+ (lambda ()
+ "remove click"
+ (set! (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>)) (* 0.5 (+ (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> (- (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) 1)) (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> (+ 1 (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>))))))
+ cursor-in-view))
+</pre></td></tr></table>
+
+<A NAME="extendedpiano"></A>We can use bind-key to turn the keyboard into a sort of extended piano:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>bind-key</em> #\o 0
+ (lambda () "play oboe.snd"
+ (<a class=quiet href="#play" onmouseout="UnTip()" onmouseover="Tip(extsnd_play_tip)">play</a> "oboe.snd")
+ keyboard-no-action))
+
+(<em class=red>bind-key</em> #\p 0
+ (lambda () "play pistol.snd"
+ (<a class=quiet href="#play" onmouseout="UnTip()" onmouseover="Tip(extsnd_play_tip)">play</a> "pistol.snd")
+ keyboard-no-action))
+</pre></td></tr></table>
+
+Now each time we hit "o", "oboe.snd" plays, etc. Or say we want to move
+forward two samples in the graph each time we type "l":
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>bind-key</em> #\l 0
+ (lambda () "move window forward 2 samples"
+ (set! (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> 0 0) (+ 2 (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> 0 0)))
+ keyboard-no-action))
+</pre></td></tr></table>
+
+Or, more useful perhaps, have C-c set the cursor at a particular sample:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(<em class=red>bind-key</em> #\c 4
+ (lambda (arg) "move cursor to arg"
+ (set! (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) arg)
+ cursor-in-middle))
+</pre></td></tr></table>
+
+A similar set rebinds the arrow keys to give much more precise window position and size control:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<a NAME="moveonepixel">move-one-pixel</a> s c right)
+ (let* ((ax (<a class=quiet href="#axisinfo" onmouseout="UnTip()" onmouseover="Tip(extsnd_axisinfo_tip)">axis-info</a> s c <a class=quiet onmouseout="UnTip()" onmouseover="Tip(extsnd_time_graph_tip)">time-graph</a>))
+ (lo (list-ref ax 0))
+ (hi (list-ref ax 1))
+ (lo-pix (list-ref ax 10))
+ (hi-pix (list-ref ax 12))
+ (samps-per-pixel (max 1 (inexact-&gt;exact (round (/ (- hi lo) (- hi-pix lo-pix))))))
+ (change (if right
+ (- (min (+ hi samps-per-pixel) (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> s c)) hi)
+ (- (max 0 (- lo samps-per-pixel)) lo))))
+ (set! (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a>) (+ lo change))
+ keyboard-no-action))
+
+(<em class=red>bind-key</em> "Left" 0 ;left arrow
+ (lambda ()
+ "move back one pixel"
+ (move-one-pixel (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>) #f)))
+
+(<em class=red>bind-key</em> "Right" 0 ;right arrow
+ (lambda ()
+ "move forward one pixel"
+ (move-one-pixel (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>) #t)))
+
+
+(define (<a NAME="zoomonepixel">zoom-one-pixel</a> s c in)
+ (let* ((ax (<a class=quiet href="#axisinfo" onmouseout="UnTip()" onmouseover="Tip(extsnd_axisinfo_tip)">axis-info</a> s c <a class=quiet onmouseout="UnTip()" onmouseover="Tip(extsnd_time_graph_tip)">time-graph</a>))
+ (lo (list-ref ax 0))
+ (hi (list-ref ax 1))
+ (lo-pix (list-ref ax 10))
+ (hi-pix (list-ref ax 12))
+ (samps-per-pixel (max 1 (inexact-&gt;exact (round (/ (- hi lo) (- hi-pix lo-pix))))))
+ (len (<a class=quiet href="#frames" onmouseout="UnTip()" onmouseover="Tip(extsnd_frames_tip)">frames</a> s c)))
+ (if in
+ (if (&gt; (- hi-pix lo-pix) samps-per-pixel)
+ (begin
+ (set! (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a>) (+ lo samps-per-pixel))
+ (set! (<a class=quiet href="#xzoomslider" onmouseout="UnTip()" onmouseover="Tip(extsnd_xzoomslider_tip)">x-zoom-slider</a>)
+ (exact-&gt;inexact
+ (round (/ (max samps-per-pixel (- hi lo (* 2 samps-per-pixel))) len))))))
+ (begin
+ (set! (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a>) (max 0 (- lo samps-per-pixel)))
+ (set! (<a class=quiet href="#xzoomslider" onmouseout="UnTip()" onmouseover="Tip(extsnd_xzoomslider_tip)">x-zoom-slider</a>)
+ (exact-&gt;inexact (round (/ (min len (+ (- hi lo) (* 2 samps-per-pixel))) len))))))
+ keyboard-no-action))
+
+(<em class=red>bind-key</em> "Up" 0 ;up arrow
+ (lambda ()
+ "zoom out one pixel"
+ (zoom-one-pixel (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>) #f)))
+(<em class=red>bind-key</em> "Down" 0 ;down arrow
+ (lambda ()
+ "zoom in one pixel"
+ (zoom-one-pixel (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>) (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>) #t)))
+</pre></td></tr></table>
+
+The emacs-style line-oriented commands C-p, C-n, and C-k aren't very useful in Snd,
+since there's no reason for 128 samples to consititute the audio analog of a line of text.
+In the next example, we rebind them to treat same-sense zero-crossings as line markers:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<A NAME="newcp">find-zero</a> forwards)
+ (let* ((loc (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>))
+ (twice #f)
+ (dir (if forwards 1 -1))
+ (reader (<a class=quiet href="#makesampler" onmouseout="UnTip()" onmouseover="Tip(extsnd_makesampler_tip)">make-sampler</a> loc #f #f dir))
+ (val (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a>)))
+ (while (not (or (<a class=quiet href="#cgp" onmouseout="UnTip()" onmouseover="Tip(extsnd_cgp_tip)">c-g?</a>)
+ (and forwards (<a class=quiet href="#sampleratendQ" onmouseout="UnTip()" onmouseover="Tip(extsnd_sampleratendQ_tip)">sampler-at-end?</a> reader))
+ (and (not forwards) (= loc 0))))
+ (let ((newval (<a class=quiet href="#readsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_readsample_tip)">read-sample</a> reader)))
+ (set! loc (+ loc dir))
+ (if (or (and (&gt;= val 0.0) (&lt; newval 0.0))
+ (and (&lt; val 0.0) (&gt;= newval 0.0)))
+ (if twice
+ (break loc)
+ (begin
+ (set! val newval)
+ (set! twice #t))))))
+ loc))
+
+(define (<A NAME="deletetozero">delete-to-zero</a> forwards)
+ (let ((loc (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>))
+ (zero-loc (find-zero forwards)))
+ (if (not (= loc zero-loc))
+ (if forwards
+ (<a class=quiet href="#deletesamples" onmouseout="UnTip()" onmouseover="Tip(extsnd_deletesamples_tip)">delete-samples</a> (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) (- zero-loc loc))
+ (begin
+ (<a class=quiet href="#deletesamples" onmouseout="UnTip()" onmouseover="Tip(extsnd_deletesamples_tip)">delete-samples</a> zero-loc (- loc zero-loc))
+ (set! (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) zero-loc))))))
+
+(define (go-to-zero forwards)
+ (set! (<a class=quiet href="#cursor" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursor_tip)">cursor</a>) (find-zero forwards)))
+
+(<em class=red>bind-key</em> #\k 4 (lambda (arg)
+ "delete to next zero crossing"
+ (do ((i 0 (+ 1 i)))
+ ((= i (abs arg)))
+ (delete-to-zero (&gt; arg 0)))))
+(<em class=red>bind-key</em> #\n 4 (lambda (arg)
+ "go to next zero crossing"
+ (do ((i 0 (+ 1 i)))
+ ((= i (abs arg)))
+ (go-to-zero (&gt; arg 0)))))
+(<em class=red>bind-key</em> #\p 4 (lambda (arg)
+ "go to previous zero crossing"
+ (do ((i 0 (+ 1 i)))
+ ((= i (abs arg)))
+ (go-to-zero (&lt; arg 0)))))
+</pre></td></tr></table>
+
+Most of the predefined key definitions are given in <a href="snd.html#builtinkeys">Keyboard Commands</a>.
+The key bindings set by bind-key are active only when the active widget is a graph; when the listener is receiving
+key strokes, the underlying text widget interprets them itself (using Emacs as a vague guide). You can change the listener's interpretation
+in the following manner (this assumes you're using Motif and have the xm module loaded):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(XtAppAddActions (car (<a class=quiet href="#mainwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_mainwidgets_tip)">main-widgets</a>)) (list (list "hiho" (lambda args (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> "hiho")))))
+(XtOverrideTranslations (list-ref (<a class=quiet href="#mainwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_mainwidgets_tip)">main-widgets</a>) 4) (XtParseTranslationTable "Ctrl &lt;Key&gt;i: hiho()\n"))
+</pre></td></tr></table>
+
+Since neither Motif nor Gtk explicitly support an Emacs-like extended mode, we have to go to
+a bit of trouble to add an extended command to the listener. The following implements C-x C-f
+in either Motif or Gtk:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+
+;;; Motif version:
+
+(define extended #f) ; our extended mode flag
+
+(XtAddEventHandler (list-ref (<a class=quiet href="#mainwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_mainwidgets_tip)">main-widgets</a>) 4) KeyPressMask #f
+ (lambda (w context event go)
+ (let* ((bits (.state event))
+ (keysym (XKeycodeToKeysym (XtDisplay w)
+ (.keycode event)
+ (if (not (= (logand bits ShiftMask) 0)) 1 0))))
+ (if (= (logand bits ControlMask) 0)
+ (set! extended #f)
+ ;; got C-&lt;something&gt;
+ (if (= (cadr keysym) 120) ; C-x
+ (set! extended #t)
+ (begin
+ (if (and extended
+ (= (cadr keysym) 102)) ; C-x C-f
+ (<a class=quiet href="#openfiledialog" onmouseout="UnTip()" onmouseover="Tip(extsnd_openfiledialog_tip)">open-file-dialog</a>))
+ (set! extended #f)))))))
+
+
+;;; Gtk version:
+
+(define extended #f) ; our extended mode flag
+
+(let ((listener (list-ref (<a class=quiet href="#mainwidgets" onmouseout="UnTip()" onmouseover="Tip(extsnd_mainwidgets_tip)">main-widgets</a>) 4)))
+ (g_signal_connect_closure_by_id
+ (GPOINTER listener)
+ (g_signal_lookup "key_press_event" (G_OBJECT_TYPE (GTK_OBJECT listener)))
+ 0
+ (g_cclosure_new (lambda (w event data)
+ (let ((bits (.state (GDK_EVENT_KEY event)))
+ (key (.keyval (GDK_EVENT_KEY event))))
+ (if (= (logand bits GDK_CONTROL_MASK) 0)
+ (set! extended #f)
+ ;; got C-&lt;something&gt;
+ (if (= key 120) ; C-x
+ (set! extended #t)
+ (begin
+ (if (and extended
+ (= key 102))
+ (<a class=quiet href="#openfiledialog" onmouseout="UnTip()" onmouseover="Tip(extsnd_openfiledialog_tip)">open-file-dialog</a>))
+ (set! extended #f))))
+ #f))
+ #f #f)
+ #f))
+</pre></td></tr></table>
+See edit123.scm, snd_conffile.scm, and snd_frg.scm for many more examples of bind-key.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- break -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="break">break</a> ()</code>
+</td></tr><tr><td></td><td>
+<p>In s7, this places a breakpoint at the current code location.
+If you hit the breakpoint, the listener prompt reflects the current
+function name (if any), and any typing at that point is evaluated
+in the local environment (so you have access to function arguments and
+local variables). To continue from the breakpoint, (break-ok). To
+exit back to the top level, (break-exit):
+</p>
+<pre>
+ <em class=typing>(define (outer arg1)
+ (let ((y 123))
+ (define (hiho arg)
+ (let ((x 32)
+ (y "a string")
+ (z (vct .1 .2 .3)))
+ (break)
+ (display y)
+ (+ x (string-length y) (vct-ref z 1))))
+ (hiho 1)
+ (break)
+ (* y 2)))</em>
+
+ <em class=listener>&gt;</em> <em class=typing>(outer 456)</em>
+ <em class=listener>hiho&gt;</em>
+ <em class=listener>snd-top-level</em>
+ <em class=listener>hiho&gt;</em> <em class=typing>x</em>
+ <em class=listener>32</em>
+ <em class=listener>hiho&gt;</em> <em class=typing>arg</em>
+ <em class=listener>1</em>
+ <em class=listener>hiho&gt;</em> <em class=typing>y</em>
+ <em class=listener>"a string"</em>
+ <em class=listener>hiho&gt;</em> <em class=typing>(break-ok)</em>
+ <em class=listener>&gt;</em>
+ <em class=listener>outer&gt;</em>
+ <em class=listener>snd-top-level</em>
+ <em class=listener>outer&gt;</em> <em class=typing>y</em>
+ <em class=listener>123</em>
+ <em class=listener>outer&gt;</em> <em class=typing>(break-ok)</em>
+ <em class=listener>&gt;</em>
+ <em class=listener>246</em>
+</pre>
+<p>To get a stack trace at the point of the break, <code>(stacktrace break-ok)</code>.
+</p>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+
+<!-- c-g? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="cgp">c-g?</a> ()</code>
+</td></tr><tr><td></td><td>
+This checks for C-g to interrupt an on-going computation, and let other UI
+events through. c-g? is especially useful in loops; we can define our own safe 'while' loop as follows
+(this is a slight revision of Guile's while macro from ice-9/boot-9.scm):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(defmacro safe-while (cond . body)
+ `(letrec ((break (lambda val (apply throw 'break val)))
+ (continue (lambda () (if (<em class=red>c-g?</em>)
+ (break 'interrupted)
+ (or (not ,cond)
+ (begin (begin ,@ body)
+ (continue)))))))
+ (catch 'break
+ (lambda () (continue))
+ (lambda v (cadr v)))))
+</pre></td></tr></table>
+
+Here's a version of "do" that is interruptible and continuable. c-g? provides
+the interrupt, and call-with-current-continuation provides the continuation.
+To continue running an interrupted do?, <code>(do-go-on)</code>.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define do-go-on-continuation #f)
+(define (do-go-on)
+ (if (continuation? do-go-on-continuation) ; a Snd function &mdash; should be provided by Scheme!
+ (do-go-on-continuation #f)
+ ";sorry! can't continue"))
+
+(defmacro do? (inits ends . body)
+ `(do ,inits
+ ((or (and ,(car ends)
+ (begin
+ (set! do-go-on-continuation #f) ; clear obsolete continuation
+ #t))
+ (and (<em class=red>c-g?</em>) ; got C-g &mdash; set continuation
+ (call-with-current-continuation
+ (lambda (go-on)
+ (set! do-go-on-continuation go-on)))))
+ ,(and (not (null? (cdr ends)))
+ (cadr ends)))
+ ,@body))
+</pre></td></tr></table>
+
+See examp.scm and play.scm for other examples.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- c-g! -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="cgx">c-g!</a> ()</code>
+</td></tr><tr><td></td><td>
+This simulates typing C-g. It is intended for use with <a href="#bindkey">bind-key</a> to remap C-g.
+If you use it in some other situation (a hook for example), there are annoying problems with clearing
+the "I've been interrupted" flags. Probably the safest thing is to call (c-g?) after the interruption
+has taken effect.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- delete-watcher -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="deletewatcher">delete-watcher</a> (id)</code>
+</td></tr><tr><td width=30><br></td><td>
+delete-watcher removes from the watcher list the function associated with id.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- erf -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><em class=emdef>erf</em> (x)</code><br>
+<code><em class=emdef>erfc</em> (n x)</code><br>
+</td></tr><tr><td></td><td>
+These are the erf and erfc functions from the math library.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- exit -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="exit">exit</a> ('exit-value')</code>
+</td></tr><tr><td></td><td>
+This exits Snd. Scheme's exit function is renamed %exit. In Forth, this function is snd-exit.
+The hooks associated with this function are:
+<pre>
+ <a class=quiet href="#beforeexithook" onmouseout="UnTip()" onmouseover="Tip(extsnd_beforeexithook_tip)">before-exit-hook</a> &mdash; can cancel exit request
+ <a class=quiet href="#exithook" onmouseout="UnTip()" onmouseover="Tip(extsnd_exithook_tip)">exit-hook</a>
+ Snd cleans up and exits
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- fmod -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><em class=emdef>fmod</em> (x y)</code>
+</td></tr><tr><td></td><td>
+fmod is mod with float arguments:
+<pre>
+ &gt;<em class=typing>(fmod 2.5 1.4)</em>
+ <em class=listener>1.1</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- gc-off -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="gcoff">gc-off</a> ()</code>
+</td></tr><tr><td></td><td>
+gc-off turns garbage collection off, if possible.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- gc-on -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="gcon">gc-on</a> ()</code>
+</td></tr><tr><td></td><td>
+gc-on turns garbage collection on.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- in -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="gin">in</a> (ms thunk)</code>
+</td></tr><tr><td></td><td>
+'ms' milliseconds from now, evaluate 'thunk', a function of no arguments. In Ruby, this
+is named "<a name="callin">call_in</a>".
+<pre>
+ (<em class=red>in</em> 5000 (lambda () (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> "boo!")))
+</pre>
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (at hour minute func)
+ (let* ((cur-time (localtime (current-time)))
+ (cur-minute (vector-ref cur-time 1))
+ (cur-hour (vector-ref cur-time 2))
+ (now (+ (* cur-hour 60) cur-minute))
+ (then (+ (* hour 60) minute)))
+ (<em class=red>in</em> (* 1000 60 (- then now)) func)))
+
+(at 15 11 (lambda () (<a class=quiet href="#sndprint" onmouseout="UnTip()" onmouseover="Tip(extsnd_sndprint_tip)">snd-print</a> "it's 3:11 pm!")))
+</pre></td></tr></table></td></tr>
+<tr><td colspan=2 height=16></td></tr>
+
+
+<!-- key -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="key">key</a> (key state :optional snd chn) </code>
+</td></tr><tr><td></td><td>
+This executes the keyboard command 'key' with modifier keys 'state'.
+'state' is a combination of control = 4 and meta = 8.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- key-binding -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="keybinding">key-binding</a> (key :optional (state 0) extended)</code>
+</td></tr><tr><td></td><td>
+This returns the user-defined (not built-in) procedure, if any, currently bound to 'key' with 'state' and 'extended' flags.
+'state' is a combination of control = 4 and meta = 8. 'extended' is #t if the command
+is preceded by C-x.
+<pre>
+ :<em class=typing>(key-binding "Right" 0)</em>
+ <em class=listener>#&lt;procedure #f (() "move one pixel forward" (move-one-pixel (selected-sound) (selected-channel) #t))&gt;</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- lgamma -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><em class=emdef>lgamma</em> (x)</code><br>
+</td></tr><tr><td></td><td>
+This is the lgamma function from the math library.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- little-endian? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="littleendianp">little-endian?</a> () </code>
+</td></tr><tr><td></td><td>
+This returns #t if underlying machine is little endian.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-macros -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="savemacros">save-macros</a> (filename)</code>
+</td></tr><tr><td></td><td>
+This saves all currently defined <a href="snd.html#kbdmacros">keyboard macros</a> in 'filename'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- save-state -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="savestate">save-state</a> (:optional filename)</code>
+</td></tr><tr><td></td><td>
+This saves the current state of Snd in 'filename'. The saved-state file is a Scheme/Ruby/Forth program that when loaded
+into Snd, recreates the state of Snd (as far as possible) at the point of the save.
+<a href="#savestatehook">save-state-hook</a> is called during the saving process (once on each temp file),
+and <a href="#aftersavestatehook">after-save-state-hook</a> is called afterwards.
+'filename' defaults to <a href="#savestatefile">save-state-file</a> which itself defaults to "saved-snd.scm"
+or some variant thereof.
+<br><br>
+There are a variety of
+limitations to this process; the worst is that save-state does not try to save hook values or global variable values &mdash;
+see also <a href="#ptreechannel">ptree-channel</a> in this regard.
+If you call save-state with active regions, and have the region browser running all the time, and subsequently
+want to back up to the saved state, it's safer to delete all the regions first (via <a href="#forgetregion">forget-region</a>),
+then load the saved-state file.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- script-arg -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="scriptarg">script-arg</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the current startup argument number (normally 1). See <a href="grfsnd.html#sndwithnogui">Snd as a script engine</a> and snd-test.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- script-args -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="scriptargs">script-args</a> ()</code>
+</td></tr><tr><td></td><td>
+This returns the startup arguments as a list of strings. See <a href="grfsnd.html#sndwithnogui">Snd as a script engine</a> and snd-test.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- send-mozilla -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sendmozilla">send-mozilla</a> (url)</code>
+</td></tr><tr><td></td><td>
+This starts firefox (or whatever <a href="#htmlprogram">html-program</a> is), and tells it to go to the location 'url'.
+<pre>
+ (send-mozilla "/home/bil/cl/extsnd.html#sendmozilla")
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-error -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="snderror">snd-error</a> (str)</code>
+</td></tr><tr><td></td><td>
+This throws 'snd-error with the error message 'str'. It provides a way to dive directly into
+Snd's error handling mechanism.
+See also <a href="#muserrorhook">mus-error-hook</a> and <a href="#snderrorhook">snd-error-hook</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-help -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndhelp">snd-help</a> (obj :optional (formatted #t))</code>
+</td></tr><tr><td></td><td>
+This returns the help text associated with 'obj':
+<pre>
+ Scheme:
+ :<em class=typing>(snd-help 'open-sound)</em> ; or "open-sound"
+ <em class=listener>"(open-sound filename) opens filename (as if opened from File:Open menu option),
+ and returns the new sound's index"</em>
+
+ Ruby:
+ :<em class=typing>snd_help("close_sound")</em> ; or :open_sound
+ <em class=listener>close_sound((snd false)): close snd</em>
+
+ Forth:
+ snd> <em class=typing>"revert-sound" snd-help</em>
+ <em class=listener>(revert-sound (snd #f)): revert snd to its unedited state (undo all)</em>
+</pre>
+If no help string can be found, or if the name doesn't come close to any currently defined name,
+snd-help runs through the current load path searching *.scm (or *.rb) files for a definition
+of that name. So, if you haven't loaded dsp.scm:
+<pre>
+ :<em class=typing>(snd-help "volterra-filter")</em>
+ <em class=listener>"volterra-filter is not defined; it appears to be defined in:
+ /home/bil/cl/dsp.scm:1936:(define (volterra-filter flt x) <!-- ) -->
+ and documented at sndscm.html#volterrafilter"</em>
+</pre>
+snd-help tries to be smart about minor mispellings:
+<pre>
+ :<em class=typing>(snd-help "close-soud")</em>
+ <em class=listener>"(close-sound (snd #f)): close snd
+ Other possibilities:
+ close-sound is defined; it is documented at extsnd.html#closesound"</em>
+</pre>
+To go to the
+HTML documentation for a given object, load <a href="sndscm.html#indexdoc">index.scm</a> and use the html function.
+<br><br>
+Normally snd-help adds carriage-returns to fit the current size of the listener; to
+get the raw string instead, set the argument 'formatted' to #f. click-for-listener-help
+in draw.scm uses this to put off formatting the help string until the help dialog (rather than
+the listener) gets it.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- *snd-opened-sound* -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndopenedsound">*snd-opened-sound*</a></code>
+</td></tr><tr><td></td><td>
+When a sound file is opened, Snd looks for a file with the same
+name but with an appended ".scm" extension. If such a file is found,
+it is loaded automatically. The variable *snd-opened-sound* is set to
+the newly opened sound (the object). This supports the snd-memo feature
+in the CL version of CLM, but can be used independently of CLM to store marks, selections,
+or whatever that you want associated with a particular sound. Confusingly
+enough, this is a variable, unlike all the others &mdash; that is, you
+refer to it directly, not as a procedure call. Say we have a sound file "now.snd",
+and we want it to use the grid-graph whenever it is viewed. We make "now.snd.scm"
+and put in it: <code>(set! (show-grid *snd-opened-sound*) #t)</code>. When "now.snd" is
+opened, "now.snd.scm" is loaded automatically with *snd-opened-sound* holding the sound object of "now.snd".
+There are other fancier ways to do this (e.g. <a href="sndscm.html#remembersoundstate">remember-sound-state</a>).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-print -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndprint">snd-print</a> (str)</code>
+</td></tr><tr><td></td><td>
+This displays 'str' in the listener, then returns 'str'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-tempnam -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndtempnam">snd-tempnam</a> ()</code>
+</td></tr><tr><td></td><td>
+This returns a new temp file name using Snd's <a href="#tempdir">temp-dir</a>.
+<pre>
+ <em class=listener>:</em><em class=typing>(temp-dir)</em>
+ <em class=listener>"/home/bil/zap/tmp"</em>
+ <em class=listener>:</em><em class=typing>(snd-tempnam)</em>
+ <em class=listener>"/home/bil/zap/tmp/snd_7000_2.snd"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-url -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndurl">snd-url</a> (name)</code>
+</td></tr><tr><td></td><td>
+This is the url (in the Snd documentation) corresponding to 'name'; 'name' can be a string or a symbol.
+<pre>
+ <em class=listener>:</em><em class=typing>(snd-url 'open-sound)</em>
+ <em class=listener>"extsnd.html#opensound"</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-urls -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndurls">snd-urls</a> ()</code>
+</td></tr><tr><td></td><td>
+This returns a list of lists, each inner list containing a Snd function name (as a string) and its associated url in the Snd documentation.
+<pre>
+ :<em class=typing>(assoc "open-sound" (snd-urls))</em>
+ <em class=listener>: ("open-sound" . "extsnd.html#opensound")</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-warning -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndwarning">snd-warning</a> (str)</code>
+</td></tr><tr><td></td><td>
+This posts a 'str' in the minibuffer and returns 'str'.
+See also <a href="#sndwarninghook">snd-warning-hook</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- unbind-key -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="unbindkey">unbind-key</a> (key state extended)</code>
+</td></tr><tr><td></td><td>
+This causes 'key' with modifiers 'state' and 'extended' to revert to its built-in default.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- window-property -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="windowproperty">window-property</a> (known-atom property)</code>
+</td></tr><tr><td width=30></td><td>
+window-property returns or changes an X-window's property; <a href="sndscm.html#titlewithdate">title-with-date</a> in examp.scm uses this function
+to put the date and time in the Snd title bar.
+<pre>
+ :<em class=typing>(window-property "SND_VERSION" "SND_VERSION")</em>
+ <em class=listener>"1-Jun-06"</em>
+ :<em class=typing>(set! (<em class=red>window-property</em> "SND_VERSION" "WM_NAME") "a new name")</em>
+ <em class=listener>#f</em>
+</pre>
+</td></tr>
+
+</table>
+<br>
+
+
+<!-- ---------------------------------------- CONSTANTS ---------------------------------------- -->
+
+<table width="80%" border=0><tr><td bgcolor="lightsteelblue" valign="middle"><h3><A NAME="sndconstants">Constants</a></h3></td></tr></table>
+
+<p><b>Sndlib</b> (see <a href="sndlib.html#sndlibxen">sndlib.html</a> for a complete list):</p>
+<pre>
+ mus-next mus-aifc mus-riff mus-rf64 mus-nist mus-raw mus-ircam mus-aiff
+ mus-bicsf mus-soundfont mus-voc mus-svx mus-caff
+
+ mus-bshort mus-lshort mus-mulaw mus-alaw mus-byte mus-ubyte mus-bfloat
+ mus-lfloat mus-bint mus-lint mus-b24int mus-l24int mus-bdouble mus-ldouble
+ mus-ubshort mus-ulshort
+
+ <a name="musoutformat">mus-out-format</a>
+</pre>
+
+<p><b>Time domain graph type</b> (<a href="#timegraphtype">time-graph-type</a>):</p>
+<pre>
+ graph-once <a class=quiet href="snd.html#wavogram" onmouseout="UnTip()" onmouseover="Tip('<img src=\'pix/wavo.png\' width=\'640\' height=\'250\'>', TITLE, 'graph-as-wavogram', ABOVE, true)">graph-as-wavogram</a>
+</pre>
+
+<p><b>Transform graph type</b> (the Transform Options Display choice, <a href="#transformgraphtype">transform-graph-type</a>):</p>
+<pre>
+ graph-once graph-as-sonogram graph-as-spectrogram
+</pre>
+
+<p><b>Transform type</b> (<a href="#transformtype">transform-type</a>):</p>
+<pre>
+ <a name="fouriertransform">fourier-transform</a> wavelet-transform cepstrum haar-transform
+ autocorrelation walsh-transform
+</pre>
+
+<p><b>Transform normalization</b> (<a href="#normalizefft">transform-normalization</a>):</p>
+<pre>
+ dont-normalize normalize-by-channel normalize-by-sound normalize-globally
+</pre>
+
+<p><b>FFT Window</b> type (<a href="#fftwindow">fft-window</a>):</p>
+<pre>
+ rectangular-window hann(ing)-window welch-window parzen-window
+ bartlett-window hamming-window blackman2-window blackman3-window
+ blackman4-window exponential-window riemann-window kaiser-window
+ cauchy-window poisson-window gaussian-window tukey-window
+ dolph-chebyshev-window hann-poisson-window connes-window samaraki-window
+ ultraspherical-window bartlett-hann-window bohman-window flat-top-window
+ blackman5-window blackman6-window blackman7-window blackman8-window
+ blackman9-window blackman10-window rv2-window rv3-window
+ rv4-window mlt-sine-window papoulis-window dpss-window
+ sinc-window
+</pre>
+
+<p><b>Zoom Focus</b> style (<a href="#zoomfocusstyle">zoom-focus-style</a>):</p>
+<pre>
+ zoom-focus-left zoom-focus-right zoom-focus-active zoom-focus-middle
+</pre>
+
+<p><b>X-axis Label</b> (<a href="#xaxisstyle">x-axis-style</a>):</p>
+<pre>
+ x-axis-in-seconds x-axis-in-samples x-axis-as-percentage x-axis-in-beats x-axis-in-measures x-axis-as-clock
+</pre>
+
+<p><b>Speed Control</b> style (<a href="#speedstyle">speed-control-style</a>, <a href="#viewfilesspeedstyle">view-files-speed-style</a>):</p>
+<pre>
+ speed-control-as-float speed-control-as-ratio speed-control-as-semitone
+</pre>
+
+<p><b>Channel Combination</b> style (<a href="#channelstyle">channel-style</a>):</p>
+<pre>
+ <a name="channelstyleconstants">channels-separate</a> channels-combined channels-superimposed
+</pre>
+
+<p><b>Envelope Editor</b> target (<a href="#envedtarget">enved-target</a>):</p>
+<pre>
+ enved-amplitude enved-spectrum enved-srate
+</pre>
+
+<p><b>Envelope Editor</b> ramp choice (<a href="#envedstyle">enved-style</a>):</p>
+<pre>
+ envelope-linear envelope-exponential
+</pre>
+
+<p><b>Graph Line</b> style (<a href="#graphstyle">graph-style</a>):</p>
+<pre>
+ <a name="graphlines">graph-lines</a> graph-dots graph-filled graph-lollipops
+ graph-dots-and-lines
+</pre>
+
+<p><b>Key binding</b> cursor action (<a href="#bindkey">bind-key</a>):</p>
+<pre>
+ <a name="cursorchoices">cursor-in-view</a> cursor-on-left cursor-on-right cursor-in-middle keyboard-no-action
+</pre>
+
+<p><b>Cursor</b> style (<a href="#cursorstyle">cursor-style</a>):</p>
+<pre>
+ cursor-cross cursor-line
+</pre>
+
+<p><b>Axis placement</b> choice (<a href="#showaxes">show-axes</a>):</p>
+<pre>
+ show-all-axes show-no-axes show-x-axis show-all-axes-unlabelled show-x-axis-unlabelled show-bare-x-axis
+</pre>
+
+<p><b>Graph</b> id (for <a href="#ytoposition">y-&gt;position</a> etc):</p>
+<pre>
+ time-graph transform-graph lisp-graph
+</pre>
+
+<p><b>Colormap</b> choice (<a href="#colormap">colormap</a>, defined in rgb.scm):</p>
+<pre>
+ black-and-white-colormap gray-colormap hot-colormap cool-colormap
+ bone-colormap copper-colormap pink-colormap jet-colormap
+ prism-colormap autumn-colormap winter-colormap spring-colormap
+ summer-colormap rainbow-colormap flag-colormap phases-colormap
+</pre>
+
+<p><b>Graphics context</b> choice (<a href="#graphdata">graph-data</a>)</p>
+<pre>
+ copy-context cursor-context selection-context mark-context
+</pre>
+
+<br>
+
+
+<!-- ---------------------------------------- ERRORS ---------------------------------------- -->
+
+<table width="80%" border=0><tr><td bgcolor="lightsteelblue" valign="middle"><h3><A NAME="snderrors">Errors and Debugging</a></h3></td></tr></table>
+<!-- INDEX snderrors:Debugging (Scheme) -->
+
+<p>When something goes awry, the various functions can throw an error (a symbol)
+which is normally caught by the default error handler (this is a kind of goto
+but without the embarrassment). It prints out some message,
+and sometimes appends a stack trace. So, as an example, selection-position
+throws 'no-active-selection if there isn't a selection:
+</p>
+<pre>
+ &gt;<em class=typing>(selection-position)</em>
+ <em class=listener>selection-position: no-active-selection</em>
+ &gt;<em class=typing>asdf</em>
+ <em class=listener>Unbound variable: asdf</em>
+</pre>
+<p>But there are cases where you'd rather handle an error (or all errors) specially.
+In the case of 'no-active-selection, we set up our own handler for that as follows:</p>
+<pre>
+&gt;<em class=typing>(catch 'no-active-selection
+ (lambda ()
+ (+ 1 (<a class=quiet href="#selectionposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionposition_tip)">selection-position</a>)))
+ (lambda (tag val) 0))</em>
+<em class=listener>0</em>
+</pre>
+<p>Here we've caught 'no-active-selection (if it occurs within the
+first thunk's body), and return 0 if it occurs; otherwise we return
+<code>(+ 1 (<a class=quiet href="#selectionposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectionposition_tip)">selection-position</a>))</code>. Scheme has a number
+of errors such as 'out-of-range, 'wrong-type-arg, 'numerical-overflow,
+etc. The Snd-specific errors are:</p>
+<pre>
+'no-such-channel 'no-such-sound 'no-such-mark 'no-such-mix
+'no-such-menu 'no-such-file 'no-such-region 'no-such-sample
+'no-such-edit 'cannot-save 'no-such-envelope 'no-active-selection
+'no-such-widget 'mus-error 'bad-arity
+'cannot-print 'no-such-axis 'no-such-player 'no-such-graphics-context
+'no-such-color 'no-such-widget 'no-such-plugin 'no-data
+'gsl-error 'no-such-key 'no-such-direction 'cannot-parse
+'no-such-colormap
+</pre>
+<p><code>bad-arity</code> is jargon indicating that a procedure has been passed the
+wrong number of arguments. <code>gsl-error</code> indicates that the GSL
+library is the source of the error.
+The symbol #t stands for all errors in this case, so we can
+run rough-shod over any error with:</p>
+<pre>
+(defmacro without-errors (func)
+ `(catch #t
+ (lambda ()
+ ,func)
+ (lambda args
+ (car args))))
+</pre>
+<p>You can use these errors in your code, if you like, or add your own. The following
+throws the error 'no-such-file:</p>
+<pre>
+(define look-for-file
+ (lambda (file)
+ (or (file-exists? file)
+ (throw 'no-such-file (list "look-for-file" file)))))
+</pre>
+<p>There is one special catch: 'snd-top-level. This is used by the
+debuggers to exit the current context, returning up a level in the
+stack of listeners. Normally that means you jump out of a breakpoint
+or whatever and find yourself back at the top level. <code>(throw 'snd-top-level)</code>.
+This catch is also the target of the SIGUSR1 signal, so if you're caught in an infinite
+loop and Snd won't respond to C-g or anything else, go to a shell, get the Snd
+process number ("PID" in the 'ps au' printout), then: kill -10 6141. SIGUSR1 is
+signal 10, and we're using the kill program to send that signal to Snd (process 6141 in our example).
+</p>
+
+<br>
+<table width="50%" border=0><tr><td bgcolor="EEFDEE" valign="middle"><h4>s7 debugging</h4></td></tr></table>
+
+<p>When s7 hits an error, it prints out a stacktrace as well as the error message.
+The variable *error-info* has additional info. You can also trace functions, and
+place breakpoints. See <a href="s7.html">s7.html</a> for further details.
+</p>
+
+
+<br>
+<table width="50%" border=0><tr><td bgcolor="EEFDEE" valign="middle"><h4>Guile debugging</h4></td></tr></table>
+
+<p>There are a variety of debugging aids supplied by Guile, including
+a backtrace facility. To be sure all Guile's debugging support
+code is loaded,
+</p>
+<pre>
+ (use-modules (ice-9 debug))
+</pre>
+<p>
+To get backtraces,
+</p>
+<pre>
+ (read-enable 'positions)
+ (debug-enable 'debug 'backtrace)
+</pre>
+<p>If you're getting a stack overflow, and you're sure it's not a case
+of infinite recursion,
+</p>
+<pre>
+ (debug-set! stack 0)
+</pre>
+<p>turns off the (very conservative) stack overflow check. If for some reason the
+backtrace information doesn't include a file name or line number, you can watch the
+load process by setting <b>%load-verbosely</b> to #t.
+</p>
+
+<br>
+<table width="50%" border=0><tr><td bgcolor="EEFDEE" valign="middle"><h4>Forth debugging</h4></td></tr></table>
+<p>See the debugging section in the fth documentation.
+</p>
+
+<br>
+<table width="50%" border=0><tr><td bgcolor="EEFDEE" valign="middle"><h4>Ruby debugging</h4></td></tr></table>
+<p>
+<code>$DEBUG = true</code> turns on the Ruby debugger.
+</p>
+
+<br>
+<table width="50%" border=0><tr><td bgcolor="EEFDEE" valign="middle"><h4><A NAME="cdebugging">C debugging</a></h4></td></tr></table>
+
+<!-- INDEX cdebugging:Debugging (C) -->
+<p>If you hit a bug in Snd's C code, you'll need to use gdb
+to track it down, or mail me the gory details;
+if the error is a segfault, there is probably a file named "core" or "core.nnnn"
+on the current directory:
+</p>
+<pre>
+ gdb snd core
+ where
+</pre>
+<p>The "where" command displays the stack at the point of the error.
+"up", and "down" move around in the stack, and "info locals" prints out
+the current frame's variables. If it's not a segfault, you can
+</p>
+<pre>
+ gdb snd
+ run
+</pre>
+<p>Then get the error to happen, at which point you should fall into gdb
+where you can type "where" and so on. If the problem involves X, you
+may need to run -sync. If Gtk, run --g-fatal-errors. If Snd gets hung
+and you need to type C-C to get out,
+</p>
+<pre>
+ gdb snd
+ break exit
+ run
+</pre>
+
+<br>
+
+
+<table width="80%" border=0><tr><td bgcolor="lightsteelblue" valign="middle"><h3><A NAME="appearance">Customizing Snd's appearance</a></h3></td></tr></table>
+
+<p>Snd's overall appearance is controlled first by the startup <a href="grfsnd.html#sndswitches">switches</a> that
+choose the outermost widget; normally this is a paned window with a sound
+in each pane; -separate puts each
+sound in a separate window, and -notebook
+puts each sound on a separate page of a notebook widget. Similarly -horizontal
+and -vertical determine which way the outer panes are laid out.
+There are a variety of functions and variables related to widget colors and so forth.
+</p>
+
+
+<!-- ---------------------------------------- COLORS ---------------------------------------- -->
+
+<table width="60%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h4><A NAME="colors">Colors</a></h4></td></tr></table>
+
+<p>A color in Snd is an object with three fields representing the
+rgb (red green blue) settings as numbers between 0.0 and 1.0. A color
+object is created via make-color:</p>
+<pre>
+ &gt;<em class=typing>(define blue (<a class=quiet href="#makecolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_makecolor_tip)">make-color</a> 0 0 1))</em>
+</pre>
+<p>This declares the Scheme variable "blue" and gives it the value
+of the color whose rgb components include only blue in full force.
+The X11 color names are defined in <a href="sndscm.html#rgbdoc">rgb.scm</a>. The overall
+widget background color is basic-color.
+</p>
+<pre>
+ &gt;<em class=typing>(set! (<a class=quiet href="#basiccolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_basiccolor_tip)">basic-color</a>) blue)</em>
+</pre>
+
+<p>The color variables
+are:</p>
+
+<table border=2 bordercolor="#f2f4ff" cellpadding=6 hspace=10><tr><td>
+<table border=0 cellpadding=0 cellspacing=0 hspace=20>
+<tr><td><code><a class=def name="axiscolor">axis-color</a></code></td><td width=20></td>
+ <td><code>defaults to current data color</code></td><td width=20></td>
+ <td>color of axes</td></tr>
+<tr><td><code><a class=def name="basiccolor">basic-color</a></code></td><td width=20></td>
+ <td><code>ivory2</code></td><td width=20></td>
+ <td>main Snd color.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="cursorcolor">cursor-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>red</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">graph cursor color.</td></tr>
+<tr><td><code><a class=def name="datacolor">data-color</a></code></td><td></td>
+ <td><code>black</code></td><td></td>
+ <td>color of data in unselected graph.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="doitbuttoncolor">doit-button-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>palegreen2</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">color of Ok and Apply buttons.</td></tr>
+<tr><td><code><a class=def name="doitagainbuttoncolor">doit-again-button-color</a></code></td><td></td>
+ <td><code>darkolivegreen1</code></td><td></td>
+ <td>color of Undo&amp;Apply buttons.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><em class=emdef>enved-waveform-color</em></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>blue</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">color of waveform displayed in envelope editor.</td></tr>
+<tr><td><code><em class=emdef>filter-control-waveform-color</em></code></td><td></td>
+ <td><code>blue</code></td><td></td>
+ <td>color of control panel filter waveform.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="graphcolor">graph-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>white</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">background color of unselected graph.</td></tr>
+<tr><td><code><a class=def name="helpbuttoncolor">help-button-color</a></code></td><td></td>
+ <td><code>lightsteelblue2</code></td><td></td>
+ <td>color of Help buttons.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="highlightcolor">highlight-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>ivory1</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">highlighting color.</td></tr>
+<tr><td><code><em class=emdef>listener-color</em></code></td><td></td>
+ <td><code>aliceblue</code></td><td></td>
+ <td>background color of listener.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><em class=emdef>listener-text-color</em></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>black</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">text color in listener.</td></tr>
+<tr><td><code><a class=def name="markcolor">mark-color</a></code></td><td></td>
+ <td><code>red</code></td><td></td>
+ <td>color of mark indicator.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><em class=emdef>mix-color</em></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>darkgray</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">color of mix waveforms.</td></tr>
+<tr><td><code><a class=def name="positioncolor">position-color</a></code></td><td></td>
+ <td><code>ivory3</code></td><td></td>
+ <td>position slider color</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="pushedbuttoncolor">pushed-button-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>lightsteelblue1</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">color of pushed button.</td></tr>
+<tr><td><code><a class=def name="quitbuttoncolor">quit-button-color</a></code></td><td></td>
+ <td><code>indianred</code></td><td></td>
+ <td>color of Dismiss and Cancel buttons.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="resetbuttoncolor">reset-button-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>goldenrod1</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">color of Reset buttons.</td></tr>
+<tr><td><code><a class=def name="sashcolor">sash-color</a></code></td><td></td>
+ <td><code>lightgreen</code></td><td></td>
+ <td>color of paned window sashes.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="selecteddatacolor">selected-data-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>black</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">color of data in currently selected graph.</td></tr>
+<tr><td><code><a class=def name="selectedgraphcolor">selected-graph-color</a></code></td><td></td>
+ <td><code>white</code></td><td></td>
+ <td>background color of currently selected graph.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="selectioncolor">selection-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>lightsteelblue1</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">color of selected portion of graph.</td></tr>
+<tr><td><code><a class=def name="textfocuscolor">text-focus-color</a></code></td><td></td>
+ <td><code>white</code></td><td></td>
+ <td>color of text field when it has focus.</td></tr>
+<tr><td bgcolor="#f2f4ff"><code><a class=def name="zoomcolor">zoom-color</a></code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff"><code>ivory4</code></td><td bgcolor="#f2f4ff"></td>
+ <td bgcolor="#f2f4ff">zoom slider color.</td></tr>
+</table>
+</td></tr></table>
+
+<p>I have these lines in my ~/.snd_s7 file:
+</p>
+<pre>
+ (define beige (<a class=quiet href="#makecolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_makecolor_tip)">make-color</a> 0.96 0.96 0.86))
+ (define blue (<a class=quiet href="#makecolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_makecolor_tip)">make-color</a> 0 0 1))
+ (set! (<a class=quiet href="#selectedgraphcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedgraphcolor_tip)">selected-graph-color</a>) beige)
+ (set! (<a class=quiet href="#selecteddatacolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_selecteddatacolor_tip)">selected-data-color</a>) blue)
+</pre>
+<p>In Forth (~/.snd_forth) this is:
+</p>
+<pre>
+ 0.96 0.96 0.86 make-color ( beige ) set-selected-graph-color drop
+ 0.00 0.00 1.00 make-color ( blue ) set-selected-data-color drop
+</pre>
+<p>And in Ruby (~/.snd_ruby):
+</p>
+<pre>
+ beige = make_color 0.96, 0.96, 0.86
+ blue = make_color 0, 0, 1
+ set_selected_graph_color beige
+ set_selected_data_color blue
+</pre>
+
+<!-- INDEX colors:Colors -->
+<TABLE border=3 bordercolor="tan" hspace=40 vspace=10><tr><td>
+<blockquote><small><br>
+Other color-related stuff:<br>
+X/Motif color resources: <a href="grfsnd.html#sndresources">Snd Resources</a><br>
+Color names: <a href="sndscm.html#rgbdoc">rgb.scm, rgb.rb</a><br>
+colors in the file dialogs: install-searcher-with-colors in snd-motif.scm<br>
+color-orientation-dialog: <a href="#colororientationdialog">color-orientation-dialog</a><br>
+colored samples: <a href="sndscm.html#drawdoc">display-colored-samples</a> and others in draw.scm<br>
+colored edits: <a href="sndscm.html#drawdoc">display-previous-edits</a> in draw.scm<br>
+colored marks: mark-sync-color in snd-motif.scm<br>
+colors in rxvt: red-text et al in examp.scm<br>
+flashing colors: flash-selected-data in examp.scm<br>
+openGL: snd-gl.scm, <a href="grfsnd.html#sndandgl">Snd and OpenGL</a><br>
+fancy widget backgrounds: new-backgrounds.scm in the tutorial<br>
+root window color: set-root-window-color in snd-motif.scm<br>
+color hook: <a href="#colorhook">color-hook</a><br>
+Snd graphics contexts: <a href="#sndgcs">snd-gcs</a><br>
+<br></small></blockquote>
+</td></tr></TABLE>
+
+
+<br><br>
+
+<!-- ---------------------------------------- FONTS ---------------------------------------- -->
+
+<table width="60%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h4><A NAME="fonts">Fonts</a></h4></td></tr></table>
+
+<p>Fonts in Snd are strings containing a description of the
+desired font. These can be the abbreviated forms such as
+"8x14" or a full X font name such as "-misc-fixed-bold-r-normal--*-140-*-*-*-*-*-*".
+In Gtk, the font names resemble "Monospace 10", etc.
+The font variables are:
+</p>
+<table cellpadding=0 cellspacing=0 hspace=20>
+<tr><td width=200><code><a class=def name="axislabelfont">axis-label-font</a></code></td><td>used in axis labels</td></tr>
+<tr><td><code><a class=def name="axisnumbersfont">axis-numbers-font</a></code></td><td>used in axis tick numbers</td></tr>
+<tr><td><code><a class=def name="boldpeaksfont">bold-peaks-font</a></code></td><td>used by fft peaks display</td></tr>
+<tr><td><code><a class=def name="peaksfont">peaks-font</a></code></td><td>used by fft peaks display</td></tr>
+<tr><td><code><em class=emdef>listener-font</em></code></td><td>listener font</td></tr>
+<tr><td><code><a class=def name="tinyfont">tiny-font</a></code></td><td>smallest font used</td></tr>
+</table>
+<br>
+<table border=0 cellpadding=5 hspace=20>
+<tr><td><pre>
+(set! (<a class=quiet href="#listenerfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_listenerfont_tip)">listener-font</a>) "9x15")
+(set! (<a class=quiet href="#axislabelfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_axislabelfont_tip)">axis-label-font</a>) "-*-times-medium-r-normal-*-18-*-*-*-*-*-*-*")
+(set! (<a class=quiet href="#axisnumbersfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_axisnumbersfont_tip)">axis-numbers-font</a>) "9x15")
+</pre></td></tr></table>
+
+<p>See also <a href="#currentfont">current-font</a> below.
+If the requested font can't be loaded, the set! statement returns the old (unchanged) font name.
+</p>
+<pre>
+ &gt;<em class=typing>(set! (axis-label-font) "8x14")</em>
+ <em class=listener>"-*-times-medium-r-normal-*-18-*-*-*-*-*-*-*"</em>
+</pre>
+<br>
+<br>
+
+
+<table width="60%" border=0><tr><td bgcolor="lightgreen" valign="middle"><h4><A NAME="graphics">Graphics</a></h4></td></tr></table>
+
+<p>It is possible to draw directly on any of the channel graphs. Examples include the
+<a href="#showoriginal">show-original</a> after-graph-hook function, and the
+<a href="#xcursor">x-cursor</a> function that draws an "x" shaped cursor.
+</p>
+
+<!-- -------------------------------- GRAPHICS -------------------------------- -->
+<table border=0 cellspacing=4 cellpadding=6 hspace=10>
+
+<!-- add-colormap -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="addcolormap">add-colormap</a> (name func)</code>
+</td></tr><tr><td></td><td>
+add-colormap adds a new colormap to the colormap table, returning its index (for
+use with <a href="#colormap">colormap</a> or <a href="#colormapref">colormap-ref</a>).
+'name' is the name displayed in the Color/Orientation Dialog's list of colormaps.
+'func' is a function of one argument, the desired colormap size; it will be
+called whenever the new colormap's values are needed or the colormap size changes,
+so that the colormap needs to be recomputed. It should return a list of
+three vcts, each vct containing 'size' values representing respectively
+the red, green, and blue values (each a number between 0.0 and 1.0).
+In the following code, the fields are set from envelopes (this is a loose translation
+of FractInt's royal colormap):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(add-colormap "purple"
+ (lambda (size)
+ (let ((r (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> size))
+ (g (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> size))
+ (b (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> size))
+ (incr (exact-&gt;inexact (/ 256.0 size)))
+ (er (list 0 60 60 116 128 252 192 252 256 60))
+ (eg (list 0 0 64 0 128 252 192 252 256 0))
+ (eb (list 0 80 128 252 192 0 256 80)))
+ (do ((i 0 (+ 1 i))
+ (x 0.0 (+ x incr)))
+ ((= i size))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> r i (exact-&gt;inexact (/ (<a class=quiet href="sndscm.html#envelopeinterp" onmouseout="UnTip()" onmouseover="Tip(sndscm_envelopeinterp_tip)">envelope-interp</a> x er) 256.0))) ; from env.scm
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> g i (exact-&gt;inexact (/ (<a class=quiet href="sndscm.html#envelopeinterp" onmouseout="UnTip()" onmouseover="Tip(sndscm_envelopeinterp_tip)">envelope-interp</a> x eg) 256.0)))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> b i (exact-&gt;inexact (/ (<a class=quiet href="sndscm.html#envelopeinterp" onmouseout="UnTip()" onmouseover="Tip(sndscm_envelopeinterp_tip)">envelope-interp</a> x eb) 256.0))))
+ (list r g b))))
+
+;;; another amusing colormap from FractInt:
+(add-colormap "cos"
+ (lambda (size)
+ (let ((r (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> size))
+ (g (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> size))
+ (b (<a class=quiet href="#makevct" onmouseout="UnTip()" onmouseover="Tip(extsnd_makevct_tip)">make-vct</a> size))
+ (incr (exact-&gt;inexact (/ 3.14159 size))))
+ (do ((i 0 (+ 1 i))
+ (x 0.0 (+ x incr)))
+ ((= i size))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> r i (abs (sin (* 1.5 x))))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> g i (abs (sin (* 3.5 x))))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> b i (abs (sin (* 2.5 x)))))
+ (list r g b))))
+</pre></td></tr></table>
+
+<table><tr>
+<td><img src="pix/coscolor.png" alt="colormaps"></td>
+<td><img src="pix/jetcolor.png" alt="colormaps"></td>
+<td><img src="pix/hotcolor.png" alt="colormaps"></td>
+</tr></table>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- background-gradient -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="backgroundgradient">background-gradient</a> ()</code>
+</td></tr><tr><td></td><td>
+<p>In Gtk+Cairo versions of Snd, this is the amount of background color gradient in the channel graphs (0.0, the default, means
+no gradient).
+</p>
+<img src="pix/bggrad.png" alt="graph with background gradient" vspace=10>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- color? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colorp">color?</a> (obj)</code>
+</td></tr><tr><td></td><td>
+This returns #t if 'obj' is a color (a Pixel in xm jargon); see <a href="#makecolor">make-color</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- color->list -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colortolist">color-&gt;list</a> (obj)</code>
+</td></tr><tr><td></td><td>
+This returns the rgb color components of 'obj' in a list.
+<pre>
+ <em class=listener>:</em><em class=typing>(color-&gt;list (make-color 1 0 0))</em>
+ <em class=listener>(1.0 0.0 0.0)</em>
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- color-cutoff -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colorcutoff">color-cutoff</a> ()</code>
+</td></tr><tr><td></td><td>
+In spectra, this sets the lowest data value that will be colored (the default is 0.003). Anything less than that
+is rendered in the background color. This is the "data cutoff" slider in the View:Color/Orientation dialog.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- color-inverted -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colorinverted">color-inverted</a> ()</code>
+</td></tr><tr><td></td><td>
+This reflects the 'invert' button in the View:<a href="snd.html#colorbrowser">Color/Orientation</a> dialog.
+If the colormap is inverted, the order of colors is reversed.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- color-scale -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colorscale">color-scale</a> ()</code>
+</td></tr><tr><td></td><td>
+color-scale reflects the darkness setting in the View:<a href="snd.html#colorbrowser">Color/Orientation</a> dialog.
+The mapping between the slider in the dialog and the color-scale value is not linear, and is
+currently different in Gtk and Motif.
+The color chooser function in <a href="#timegraphhook">time-graph-hook</a> can use
+<a href="#colorinverted">color-inverted</a>
+and color-scale to drive colormap choices:
+
+<pre>
+ (add-hook! <a class=quiet href="#timegraphhook">time-graph-hook</a>
+ (lambda (snd chn)
+ (apply <a class=quiet href="#makecolor">make-color</a> (<a class=quiet href="#colormapref">colormap-ref</a>
+ (<a class=quiet href="#colormap">colormap</a>)
+ (let ((x (if (<em class=red>color-inverted</em>)
+ (/ chn n) ; n = total chans in this case
+ (/ (- n chn) n)))
+ (base (<em class=red>color-scale</em>)))
+ (if (= base 1.0)
+ x
+ (/ (- (expt base x) 1.0)
+ (- base 1.0))))))))
+</pre>
+
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- colormap -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colormap">colormap</a> ()</code>
+</td></tr><tr><td></td><td>
+This is the colormap choice for various displays, most prominently the transform sonogram and spectrogram,
+and the wavogram.
+The built-in maps (from 0 to 15) are:
+black-and-white, gray, hot, cool, bone, copper, pink, jet, prism, autumn, winter,
+spring, summer, rainbow, flag, and phases.
+These names are defined (with '-colormap' appended) in rgb.scm and rgb.rb.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- colormap-name -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colormapname">colormap-name</a> (index)</code>
+</td></tr><tr><td></td><td>
+colormap-name returns the specified colormap's name.
+<pre>
+ <em class=listener>:</em><em class=typing>(colormap-name (colormap))</em>
+ <em class=listener>"hot"</em>
+</pre>
+rgb.scm defines the built-in colormap names.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- colormap-ref -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colormapref">colormap-ref</a> (map pos)</code>
+</td></tr><tr><td></td><td>
+colormap-ref returns the rgb values of the colormap 'map' at position 'pos',
+suitable for use with make-color. 'pos' should be a float between
+0.0 and 1.0.
+See the example above, or samples-via-colormap in draw.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- colormap-size -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colormapsize">colormap-size</a> ()</code>
+</td></tr><tr><td></td><td>
+colormap-size returns (or sets) the current number of colors in each colormap.
+The default is 512.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- colormap? -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="colormapp">colormap?</a> (index)</code>
+</td></tr><tr><td></td><td>
+colormap? returns #t if 'index' represents a usable colormap.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- copy-context -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><A class=def NAME="copycontext">copy-context</A></code>
+</td></tr><tr><td></td><td>
+This is the graphics mode (an integer in Snd, not a function) to use to draw over whatever is currently in a graph.
+The "contexts" refer to graphics contexts used throughout Snd; the <code>copy-context</code>
+copies into the current graph, whereas the <code>cursor-context</code> uses XOR.
+The error thrown for an unimplemented context is 'no-such-graphics-context.
+See draw.scm or <a href="#displaysampsinred">display-samps-in-red</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- current-font -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="currentfont">current-font</a> (snd chn context)</code>
+</td></tr><tr><td></td><td>
+This is the current font (a Font in Motif, a PangoFontDescription* in Gtk+).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- cursor-context -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><A class=def NAME="cursorcontext">cursor-context</A></code>
+</td></tr><tr><td></td><td>
+This is the graphics mode (an integer in Snd, not a function) for XOR drawing in the cursor color (for cursors, normally).
+See <a href="#xcursor">x-cursor</a> or
+<a href="#foregroundcolor">foreground-color</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- delete-colormap -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="deletecolormap">delete-colormap</a> (index)</code>
+</td></tr><tr><td></td><td>
+delete-colormap deletes the colormap represented by 'index'.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- draw-axes -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="drawaxes">draw-axes</a> (wid gc :optional label x0 x1 y0 y1 style axes)</code>
+</td></tr><tr><td width=30></td><td>
+This draws axes in the widget 'wid', using the graphics context 'gc', with the x-axis label 'label'
+going from 'x0' to 'x1' (floats) along the x axis, 'y0' to 'y1' along the y axis, with x-axis-style
+'style' (<code>x-axis-in-seconds</code> etc). Whether axes are actually displayed or just implied
+depends on 'axes', which defaults to <code>show-all-axes</code>.
+draw-axes returns a list of the actual (pixel) axis bounds.
+See the scanned-synthesis display code in snd-motif.scm,
+or the local envelope editor code in xm-enved.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- draw-dot -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="drawdot">draw-dot</a> (x0 y0 dot-size snd chn context)</code>
+</td></tr><tr><td width=30></td><td>
+This draws a dot at ('x0 y0') of diameter 'dot-size' pixels in the specified context. See musglyphs.scm.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- draw-dots -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="drawdots">draw-dots</a> (positions dot-size snd chn context)</code>
+</td></tr><tr><td></td><td>
+This draws dots of size 'dot-size' from the (x y) pairs in the vector 'positions' in the specified context.
+draw-dots, draw-lines, and fill-polygon take vectors, rather than vcts (which would be more consistent
+with the rest of Snd) because the values passed are supposed to be short ints.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- draw-line -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="drawline">draw-line</a> (x0 y0 x1 y1 snd chn context)</code>
+</td></tr><tr><td></td><td>
+This draws a line from ('x0 y0') to ('x1 y1') in the specified context.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- draw-lines -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="drawlines">draw-lines</a> (lines snd chn context)</code>
+</td></tr><tr><td></td><td>
+This draws lines following the (x y) pairs in the vector 'lines' in the specified context.
+See make-current-window-display in draw.scm.
+make-bezier-1 in <a href="sndscm.html#musglyphs">musglyphs.scm</a> can be used to draw Bezier curves.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- draw-string -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="drawstring">draw-string</a> (text x0 y0 snd chn context)</code>
+</td></tr><tr><td></td><td>
+This draws a string ('text') in the current font and foreground color starting at ('x0 y0') in the specified context.
+The next procedures use the channel-property list (extensions.scm) to maintain a list
+of sample-oriented comments, displaying a given comment if its associated sample is
+currently in the time-domain graph:
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define* (<a name="addcomment">add-comment</a> sample comment :optional snd1 chn1)
+ (let* ((snd (or snd1 (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-sound</a>)))
+ (chn (or chn1 (<a class=quiet href="#selectedchannel" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedchannel_tip)">selected-channel</a>)))
+ (old-comments (or (<a class=quiet href="sndscm.html#channelproperty" onmouseout="UnTip()" onmouseover="Tip(sndscm_channelproperty_tip)">channel-property</a> 'comments snd chn) '())))
+ (set! (<a class=quiet href="sndscm.html#channelproperty" onmouseout="UnTip()" onmouseover="Tip(sndscm_channelproperty_tip)">channel-property</a> 'comments snd chn)
+ (cons (list sample comment)
+ old-comments))))
+
+(define (show-comments snd chn)
+ (let ((comments (or (<a class=quiet href="sndscm.html#channelproperty" onmouseout="UnTip()" onmouseover="Tip(sndscm_channelproperty_tip)">channel-property</a> 'comments snd chn) '())))
+ (for-each
+ (lambda (<a class=quiet href="#comment" onmouseout="UnTip()" onmouseover="Tip(extsnd_comment_tip)">comment</a>)
+ (let* ((samp (car comment))
+ (text (cadr comment))
+ (text-width (* 6 (string-length text)))
+ (ls (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> snd chn))
+ (rs (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a> snd chn)))
+ (if (and (&lt; ls samp)
+ (&gt; rs samp))
+ (let ((xpos (<a class=quiet href="#xtoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_xtoposition_tip)">x-&gt;position</a> (/ samp (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a>))))
+ (ypos (<a class=quiet href="#ytoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_ytoposition_tip)">y-&gt;position</a> (<a class=quiet href="#sample" onmouseout="UnTip()" onmouseover="Tip(extsnd_sample_tip)">sample</a> samp))))
+ (<a class=quiet href="#drawline" onmouseout="UnTip()" onmouseover="Tip(extsnd_drawline_tip)">draw-line</a> xpos 20 xpos (- ypos 4))
+ (<em class=red>draw-string</em> text (- xpos (/ text-width 2)) 18)))))
+ comments)))
+
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#aftergraphhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_aftergraphhook_tip)">after-graph-hook</a> show-comments)
+</pre></td></tr></table>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- fill-rectangle -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fillrectangle">fill-rectangle</a> (x0 y0 width height snd chn context erase)</code>
+</td></tr><tr><td></td><td>
+This draws a filled rectangle in the current foreground color from ('x0 y0') of size ('width height').
+If 'erase' is #t, this function erases the rectangular area.
+See draw.scm, snd-motif.scm, or <a href="#showoriginal">show-original</a>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- fill-polygon -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="fillpolygon">fill-polygon</a> (points snd chn context)</code>
+</td></tr><tr><td></td><td>
+This draws a filled polygon whose vertices are in the vector 'points'.
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (-&gt; x0 y0 size snd chn)
+ "draw an arrow pointing (from the left) at the point (x0 y0)"
+ (let ((points (make-vector 8)))
+ (define (point i x y)
+ (vector-set! points (* i 2) x)
+ (vector-set! points (+ (* i 2) 1) y))
+ (define (arrow-head x y)
+ (point 0 x y)
+ (point 1 (- x (* 2 size)) (- y size))
+ (point 2 (- x (* 2 size)) (+ y size))
+ (point 3 x y)
+ (<em class=red>fill-polygon</em> points snd chn))
+ (arrow-head x0 y0)
+ (<a class=quiet href="#fillrectangle" onmouseout="UnTip()" onmouseover="Tip(extsnd_fillrectangle_tip)">fill-rectangle</a> (- x0 (* 4 size))
+ (inexact-&gt;exact (- y0 (* .4 size)))
+ (* 2 size)
+ (inexact-&gt;exact (* .8 size))
+ snd chn)))
+</pre></td></tr></table>
+
+musglyphs.scm has some elaborate examples that use fill-polygon to draw music notation symbols.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- foreground-color -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="foregroundcolor">foreground-color</a> (snd chn context)</code>
+</td></tr><tr><td></td><td>
+This is the current foreground color.
+The following gives us a green cursor:
+<pre>
+ (set! (foreground-color 0 0 <a class=quiet href="#cursorcontext" onmouseout="UnTip()" onmouseover="Tip(extsnd_cursorcontext_tip)">cursor-context</a>) (<a class=quiet href="#makecolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_makecolor_tip)">make-color</a> 1 0 1))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- glSpectrogram -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="glspectrogram">glSpectrogram</a> (data gl-list cutoff use-dB min-dB scale br bg bb)</code>
+</td></tr><tr><td></td><td>
+glSpectrogram takes spectrogram data and passes it to openGL.
+The <a href="sndscm.html#startwaterfall">waterfall</a> function in snd-gl.scm uses this function.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- graph-data -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="graphdata">graph-data</a> (data snd chn context low high graphics-style)</code>
+</td></tr><tr><td></td><td>
+graph-data displays 'data' in the time domain graph of the sound's channel
+'chn' using the graphics context 'context' (normally <code>copy-context</code>), placing the
+data in the recipient's graph between points 'low' and 'high'
+in the drawing mode 'graphics-style'.
+With this function and make-graph-data, we can overlay sounds,
+overlay different versions of the same sound, place a portion of a
+sound over another at an arbitrary point, and so on (see draw.scm):
+
+<table border=0 cellpadding=5 vspace=10><tr><td><pre>
+(define (<A NAME="displaysampsinred">display-samps-in-red</A> snd chn)
+ "display samples 1000 to 2000 in red whenever they're in the current view"
+ (let ((left (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> snd chn))
+ (right (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a> snd chn))
+ (old-color (<a class=quiet href="#foregroundcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_foregroundcolor_tip)">foreground-color</a> snd chn))
+ (red (<a class=quiet href="#makecolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_makecolor_tip)">make-color</a> 1 0 0)))
+ (if (and (&lt; left 2000)
+ (&gt; right 1000))
+ (let* ((data (<em class=red>make-graph-data</em> snd chn)))
+ (if (<a class=quiet href="#vctp" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctp_tip)">vct?</a> data) ;the simple, one-sided graph case
+ (let* ((samps (- (min right 2000)
+ (max left 1000)))
+ (offset (max 0 (- 1000 left)))
+ (new-data (<a class=quiet href="#vctsubseq" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctsubseq_tip)">vct-subseq</a> data offset (+ offset samps))))
+ (set! (<a class=quiet href="#foregroundcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_foregroundcolor_tip)">foreground-color</a> snd chn) red)
+ (<em class=red>graph-data</em> new-data snd chn <a class=quiet href="#copycontext" onmouseout="UnTip()" onmouseover="Tip(extsnd_copycontext_tip)">copy-context</a> (max 1000 left) (min 2000 right))
+ (set! (<a class=quiet href="#foregroundcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_foregroundcolor_tip)">foreground-color</a> snd chn) old-color))
+ (let* ((low-data (car data)) ;the two-sided envelope graph case
+ (high-data (cadr data))
+ ;; we need to place the red portion correctly in the current graph
+ ;; so the following is getting the "bin" numbers associated with
+ ;; samples 1000 and 2000
+ (size (length low-data))
+ (samps (- right left))
+ (left-offset (max 0 (- 1000 left)))
+ (left-bin (inexact-&gt;exact (round (/ (* size left-offset) samps))))
+ (right-offset (- (min 2000 right) left))
+ (right-bin (inexact-&gt;exact (round (/ (* size right-offset) samps))))
+ (new-low-data (<a class=quiet href="#vctsubseq" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctsubseq_tip)">vct-subseq</a> low-data left-bin right-bin))
+ (new-high-data (<a class=quiet href="#vctsubseq" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctsubseq_tip)">vct-subseq</a> high-data left-bin right-bin)))
+ (set! (<a class=quiet href="#foregroundcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_foregroundcolor_tip)">foreground-color</a> snd chn) red)
+ (<em class=red>graph-data</em>
+ (list new-low-data new-high-data) snd chn <a class=quiet href="#copycontext" onmouseout="UnTip()" onmouseover="Tip(extsnd_copycontext_tip)">copy-context</a> left-bin right-bin)
+ (set! (<a class=quiet href="#foregroundcolor" onmouseout="UnTip()" onmouseover="Tip(extsnd_foregroundcolor_tip)">foreground-color</a> snd chn) old-color)))))))
+
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#aftergraphhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_aftergraphhook_tip)">after-graph-hook</a> display-samps-in-red)
+</pre></td></tr></table></td></tr>
+<tr><td></td><td>
+
+<img src="pix/redsamps.png" alt="red samples" hspace=20>
+
+</td></tr><tr><td colspan=2 height=32></td></tr>
+
+
+<!-- make-color -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="makecolor">make-color</a> (red green blue)</code>
+</td></tr><tr><td></td><td>
+make-color returns a color object using the rgb values 'red', 'green', and 'blue'. Each argument
+is a float between 0.0 (none of that color) and 1.0 (full value for that color). So,
+<pre>
+ (make-color 1 0 0)
+</pre>
+returns a red color object.
+Two colors are equal (i.e. equal? returns #t) if their rgb values are the same.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- make-graph-data -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="makegraphdata">make-graph-data</a> (snd chn edit-position low-sample high-sample)</code>
+</td></tr><tr><td></td><td>
+Use make-graph-data to get the currently displayed data (i.e. the waveform displayed
+in the graph, which can be based on an overall peak envelope rather than the
+individual samples).
+It returns either a vct (if the graph has one trace), or a
+list of two vcts (the two sides of the peak envelope graph).
+'edit-position' defaults to the current edit history position,
+'low-sample' defaults to the current window left sample, and
+'high-sample' defaults to the current rightmost sample.
+The result can be used in the lisp graph:
+
+<table border=0 cellpadding=5 vspace=10><tr><td>
+<pre>
+(define <A NAME="displaydb">display-db</A>
+ (lambda (snd chn)
+ "(display-db snd chn) is a lisp-graph-hook function to display the time domain data in dB"
+ (let ((datal (<em class=red>make-graph-data</em> snd chn)))
+ (if datal
+ (let* ((data (if (<a class=quiet href="#vctp" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctp_tip)">vct?</a> datal) datal (cadr datal)))
+ (len (length data))
+ (sr (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> snd)))
+ (define (dB val)
+ (if (&lt; val .001)
+ -60.0
+ (* 20.0 (log10 val))))
+ (do ((i 0 (+ 1 i)))
+ ((= i len))
+ (<a class=quiet href="#vctset" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctset_tip)">vct-set!</a> data i (+ 60.0 (dB (abs (<a class=quiet href="#vctref" onmouseout="UnTip()" onmouseover="Tip(extsnd_vctref_tip)">vct-ref</a> data i))))))
+ (<a class=quiet href="#graph" onmouseout="UnTip()" onmouseover="Tip(extsnd_graph_tip)">graph</a> data "dB"
+ (/ (<a class=quiet href="#leftsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_leftsample_tip)">left-sample</a> snd chn) sr) (/ (<a class=quiet href="#rightsample" onmouseout="UnTip()" onmouseover="Tip(extsnd_rightsample_tip)">right-sample</a> snd chn) sr)
+ 0.0 60.0
+ snd chn))))))
+
+(<a class=quiet onmouseout="UnTip()" onmouseover="Tip(scheme_add_hook_tip)">add-hook!</a> <a class=quiet href="#lispgraphhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_lispgraphhook_tip)">lisp-graph-hook</a> display-db)
+</pre>
+</td></tr></table>
+
+Here we are taking whatever is displayed in the time domain, and
+presenting the same thing in dB in the lisp graph. <a href="sndscm.html#displayenergy">display-energy</a>
+in draw.scm is another example. But the real power of this function
+comes from its use with graph-data.
+The latter takes its argument (either a vct or a list of two
+vcts), and displays it in any channel's time domain graph using its current graph-style.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- mark-context -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><A class=def NAME="markcontext">mark-context</A></code>
+</td></tr><tr><td></td><td>
+This is the graphics context used to draw a mark (XOR mode). (It is an integer, not a function).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- selection-context -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><A class=def NAME="selectioncontext">selection-context</A></code>
+</td></tr><tr><td></td><td>
+This is the graphics context for XOR drawing in the selection color. (An integer, not a function).
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-color -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndcolor">snd-color</a> (choice)</code>
+</td></tr><tr><td></td><td>
+snd-color returns a Snd built-in color (as a Pixel/GdkPixel); it simplifies
+code that wants to follow whatever the current Snd color choices are. The choices are:
+<pre>
+ 0: white 12: listener-color 24: pushed-button-color
+ 1: black 13: listener-text-color 25: sash-color
+ 2: red 14: basic-color 26: help-button-color
+ 3: yellow 15: selection-color 27: doit-button-color
+ 4: green 16: zoom-color 28: doit-again-button-color
+ 5: light-blue 17: position-color 29: quit-button-color
+ 6: lighter-blue 18: highlight-color 30: reset-button-color
+ 7: data-color 19: enved-waveform-color 31: grid-color
+ 8: selected-data-color 20: cursor-color 32: selected-grid-color
+ 9: mark-color 21: text-focus-color 33: axis-color
+ 10: graph-color 22: filter-control-waveform-color
+ 11: selected-graph-color 23: mix-color
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-font -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndfont">snd-font</a> (choice)</code>
+</td></tr><tr><td></td><td>
+snd-font returns a Snd built-in font (as a raw pointer, suitable for <a href="#currentfont">current-font</a> but not much else); it simplifies
+code that wants to follow whatever the current Snd font choices are, but is really aimed at code that wants to use
+just built-in functions like <a href="#currentfont">current-font</a>, and not rely
+on the <a href="grfsnd.html#sndwithmotif">xm</a> or <a href="grfsnd.html#sndwithgtk">xg</a> modules.
+The choices are:
+<pre>
+ 0: <a class=quiet href="#peaksfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_peaksfont_tip)">peaks-font</a>
+ 1: <a class=quiet href="#boldpeaksfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_boldpeaksfont_tip)">bold-peaks-font</a>
+ 2: <a class=quiet href="#tinyfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_tinyfont_tip)">tiny-font</a>
+ 3: <a class=quiet href="#axislabelfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_axislabelfont_tip)">axis-label-font</a>
+ 4: <a class=quiet href="#axisnumbersfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_axisnumbersfont_tip)">axis-numbers-font</a>
+ 5: <a class=quiet href="#listenerfont" onmouseout="UnTip()" onmouseover="Tip(extsnd_listenerfont_tip)">listener-font</a>
+</pre>
+See <a href="sndscm.html#displaybarkfft">display-bark-fft</a> in dsp.scm for an example.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- snd-gcs -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="sndgcs">snd-gcs</a></code>
+</td></tr><tr><td></td><td>
+snd-gcs returns a list of Snd's graphics contexts:
+<pre>
+ 0: bg=graph-color, fg=data-color
+ 1: bg=selected-graph-color, fg=selected-data-color
+ 2: bg=graph-color, fg=data-color, fg changes for superimposed graphs
+
+ 3: bg=graph-color, fg=cursor-color, XOR (for cursor)
+ 4: bg=selected-graph-color, fg=cursor-color, XOR (for cursor in selection)
+
+ 5: bg=graph-color, fg=selection-color, XOR (for selection highlighting)
+ 6: bg=selected-graph-color, fg=selection-color, XOR (selection highlighting)
+
+ 7: bg=data-color, fg=graph-color (to erase data)
+ 8: bg=selected-data-color, fg=selected-graph-color (erase data in selected channel)
+
+ 9: bg=graph-color, fg=mark-color, XOR (for marks)
+ 10: bg=selected-graph-color, fg=mark-color, XOR (marks in selected channel)
+
+ 11: bg=graph-color, fg=mix-color
+ 12: bg=selected-graph-color, fg=mix-color
+
+ 13: bg=basic-color, fg=black
+ 14: bg=basic-color, fg=filter-waveform-color
+</pre>
+These graphics-contexts make it easier to fit in with whatever color scheme is currently in use. For example,
+in snd-motif.xm's SMPTE time display, we make sure the font color reflects whether we're in the selected channel:
+<pre>
+ (XSetFont dpy
+ (if (= chn (<a class=quiet href="#selectedsound" onmouseout="UnTip()" onmouseover="Tip(extsnd_selectedsound_tip)">selected-channel</a> snd))
+ (cadr (snd-gcs))
+ (car (snd-gcs)))
+ (.fid fs))
+</pre>
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+
+<!-- with-gl -->
+<tr><td colspan=2 bgcolor="#f2f4ff">
+<code><a class=def name="withgl">with-gl</a></code>
+</td></tr><tr><td></td><td>
+If with-gl is #t and GL is loaded, use GL where possible (the default is #t if HAVE_GL).
+You can find out at run-time whether GL is loaded via <code>(provided? 'gl)</code>.
+</td></tr><tr><td colspan=2 height=16></td></tr>
+
+</table>
+
+
+ <!-- I(open file):L(open-sound)(opensound) -->
+ <!-- I(close file):L(close-sound)(closesound) -->
+ <!-- I(save file):L(save-sound)(savesound) -->
+ <!-- I(save file as):L(save-sound-as)(savesoundas) -->
+ <!-- I(change format):L(save-sound-as)(savesoundas) -->
+ <!-- I(revert file):L(revert-sound)(revertsound) -->
+ <!-- I(open file read-only):L(view-sound)(viewsound) -->
+ <!-- I(create new file):L(new-sound)(newsound) -->
+ <!-- I(print file):L(graph-&gt;ps)(graphtops) -->
+ <!-- I(exit Snd):L(exit)(exit) -->
+ <!-- I(undo edit):L(undo)(undo) -->
+ <!-- I(redo edit):L(redo)(redo) -->
+ <!-- I(cut selection):L(delete-selection)(deleteselection) -->
+ <!-- I(insert selection):O(insert-region)(insertregion) -->
+ <!-- I(insert selection):L(insert-selection)(insertselection) -->
+ <!-- I(play file):L(play, stop)(play) -->
+ <!-- I(show marks):L(show-marks)(showmarks) --><!-- I(show marks):A(showmarks) -->
+ <!-- I(y=0 line):L(show-y-zero)(showyzero) -->
+ <!-- I(dots or lines):L(graph-style)(graphstyle) -->
+ <!-- I(combine channels):L(channel-style)(channelstyle) -->
+ <!-- I(control panel):L(show-controls)(showcontrols) -->
+ <!-- I(fft peaks):L(show-transform-peaks)(showtransformpeaks) -->
+ <!-- I(fft peaks):O(peaks)(peaks) -->
+ <!-- I(fft/sono/spectrogram):L(transform-graph-type)(transformgraphtype) -->
+ <!-- I(zoom focus):L(zoom-focus-style)(zoomfocusstyle) -->
+ <!-- I(fft in dB):L(fft-log-magnitude)(fftlogmagnitude) -->
+ <!-- I(fft log freq):L(fft-log-frequency)(fftlogfrequency) -->
+ <!-- I(select sound):L(selected-sound)(selectedsound) -->
+ <!-- I(multichannel ops):L(sync)(sync) -->
+ <!-- I(save control panel):L(save-controls)(savecontrols) -->
+ <!-- I(amp env):L(env-sound)(envsound) -->
+ <!-- I(filter):L(filter-control-envelope)(filtercontrolenvelope) -->
+ <!-- I(filter):M(Edit: Edit Env)(editenvelope) -->
+ <!-- I(axis bounds):L([xy]-bounds)(xbounds) -->
+ <!-- I(max amp):L(maxamp)(maxamp) -->
+ <!-- I(max amp):A(maxamp) -->
+ <!-- I(define mark):L(add-mark)(addmark) -->
+ <!-- I(color):L(color-orientation-dialog)(colororientationdialog) -->
+ <!-- I(color):O(color-scale,color-cutoff)(colorscale) -->
+ <!-- I(orientation):O(spectro-x-angle etc)(spectroxangle) -->
+ <!-- I(file lists):L(view-files-dialog)(viewfilesdialog) -->
+ <!-- I(define selection):L(make-region)(makeregion) -->
+ <!-- I(delete samples):L(delete-samples)(deletesamples) -->
+ <!-- I(temp directory):L(temp-dir)(tempdir) -->
+ <!-- I(continue session):L(load) -->
+ <!-- I(fft window):L(fft-window)(fftwindow) -->
+ <!-- I(fft size):L(transform-size)(transformsize) -->
+ <!-- I(fft window parameter):L(fft-window-beta)(fftbeta) -->
+ <!-- I(move cursor ahead):L(set cursor)(cursor) -->
+ <!-- I(move cursor back):L(set cursor)(cursor) -->
+ <!-- I(insert zeros):L(insert-silence)(insertsilence) -->
+ <!-- I(insert zeros):O(pad-channel)(padchannel) -->
+ <!-- I(change samples):L(set-samples)(setsamples) -->
+ <!-- I(srate conversion):L(src-sound)(srcsound) --><!-- I(srate conversion):M(Edit: Edit Env)(editenvelope) -->
+ <!-- I(srate conversion):O(src-selection)(srcsoundselection) --><!-- I(srate conversion):A(srcsound) -->
+ <!-- I(resample):L(src-sound)(srcsound) --><!-- I(resample):M(Edit: Edit Env)(editenvelope) --><!-- I(resample):A(srcsound) -->
+ <!-- I(resample):O(src-selection)(srcsoundselection) --><!-- I(reverse samples):A(reversesound) -->
+ <!-- I(reverse samples):L(reverse-sound)(reversesound) --><!-- I(reverse samples):O(reverse-selection)(reverseselection) -->
+ <!-- I(filter samples):L(filter-sound)(filtersound) --><!-- I(filter samples):M(Edit: Edit Env)(editenvelope) -->
+ <!-- I(filter samples):O(filter-selection)(filterselection) --><!-- I(filter samples):A(filtersound) -->
+ <!-- I(save marks):L(save-marks)(savemarks) -->
+ <!-- I(show freq domain):L(transform-graph?)(transformgraphp) -->
+ <!-- I(show time domain):L(time-graph?)(timegraphp) -->
+ <!-- I(keyboard macros):L(key)(key) -->
+ <!-- I(delete mark):L(delete-mark)(deletemark) --> <!-- I(delete mark):O(delete-marks)(deletemarks) -->
+ <!-- I(sonogram):L(transform-graph-type)(transformgraphtype) -->
+ <!-- I(spectrogram):L(transform-graph-type)(transformgraphtype) -->
+ <!-- I(X axis units):L(x-axis-style)(xaxisstyle) -->
+ <!-- I(speed units):L(speed-control-style)(speedstyle) -->
+ <!-- I(speed units):O(speed-control-tones)(speedtones) -->
+ <!-- I(change srate):L(src-sound)(srcsound) -->
+ <!-- I(edit env):L(enved-dialog)(enveddialog) -->
+ <!-- I(edit header):L(edit-header-dialog)(editheaderdialog) -->
+ <!-- I(insert file):L(insert-sound)(insertsound) -->
+ <!-- I(mix file):L(mix)(mix) -->
+ <!-- I(move mixed file):L(mix-position)(mixposition) -->
+ <!-- I(play selection):L(play-selection)(playselection) -->
+ <!-- I(play selection):O(play-region)(playregion) -->
+ <!-- I(update file):L(update)(updatesound) -->
+ <!-- I(view envs):L(enved-dialog)(enveddialog) -->
+ <!-- I(play channel):L(play-channel)(playchannel) -->
+ <!-- I(play channel):O(play)(play) -->
+ <!-- I(mix selection):O(mix-region)(mixregion) -->
+ <!-- I(mix selection):L(mix-selection)(mixselection) -->
+ <!-- I(interrupt Snd):L(stop-playing)(stopplaying) -->
+ <!-- I(interrupt Snd):O(c-g!)(cgx) -->
+ <!-- I(move window back):L(left-sample)(leftsample) -->
+ <!-- I(move window ahead):L(right-sample)(rightsample) -->
+ <!-- I(change tempo):L(expand)(expandcontrol) -->
+ <!-- I(wavelets):L(wavelet-type)(wavelettype) -->
+ <!-- I(save macros):L(save-macros)(savemacros) -->
+ <!-- I(save selection):L(save-region)(saveregion) --><!-- I(save selection):O(save-selection)(saveselection) -->
+ <!-- I(examine regions):L(view-regions-dialog)(viewregionsdialog) -->
+ <!-- I(zoom window):L(x-bounds)(xbounds) -->
+ <!-- I(describe audio):A(musaudiodescribe) --><!-- I(describe audio):L(mus-audio-describe)(musaudiodescribe) -->
+ <!-- I(abort command):L(c-g?)(cgp) -->
+ <!-- I(count matches):L(count-matches)(countmatches) --><!-- I(count matches):A(countmatches) -->
+ <!-- I(convolution):L(convolution)(convolve) --><!-- I(convolution):A(convolve) --><!-- I(convolution):O(convolve-with)(convolvewith) -->
+ <!-- I(auto save):O(autosave.scm) -->
+ <!-- I(reverberate file):L(convolve-with)(convolvewith) -->
+ <!-- I(record sound):L(recorder-dialog)(recorderdialog) -->
+ <!-- I(describe file):L(info)(sndinfo) -->
+ <!-- I(change pitch):L(src-sound)(srcsound) -->
+ <!-- I(change colors):L(make-color)(aboutcolors) --><!-- I(change colors):A(aboutcolors) --><!-- I(change colors):O(resources)(sndresources) -->
+ <!-- I(create new file):O(default-output-srate)(defaultoutputsrate) -->
+ <!-- I(autocorrelation):L(autocorrelate)(autocorrelate) -->
+ <!-- I(axis bounds):O(axis-info)(axisinfo) -->
+ <!-- I(horizontal panes):L(graphs-horizontal)(graphshorizontal) -->
+ <!-- I(extract channel):L(save-sound-as)(savesoundas) -->
+ <!-- I(save channel):L(save-sound-as)(savesoundas) -->
+ <!-- I(swap channels):L(swap-channels)(swapchannels) -->
+ <!-- I(overlay sounds):L(graph-data)(graphdata) -->
+ <!-- I(overlay sounds):A(graphdata) -->
+ <!-- I(edit env):O(enved-hook)(envedhook) -->
+ <!-- I(close file):O(close-hook)(closehook) -->
+ <!-- I(change samples):O(edit-hook)(edithook) -->
+ <!-- I(file lists):O(mouse-enter-label-hook)(mouseenterlabelhook) -->
+ <!-- I(swap channels):A(swapchannels) -->
+ <!-- I(extend file):L(pad-channel)(padchannel) -->
+ <!-- I(extract channel):O(channel-&gt;vct)(channeltovct) -->
+ <!-- I(fft normalization):L(transform-normalization)(normalizefft) -->
+ <!-- I(fft normalization):A(normalizefft) -->
+ <!-- I(file formats):L(data-format)(dataformat) -->
+
+<br><br>
+
+<center>
+<table bgcolor="aliceblue" border=0 cellspacing=8><tr>
+<td><small>related documentation:</small></td>
+<td><small><a href="snd.html" onmouseout="UnTip()" onmouseover="Tip(snd_html_tip)">snd.html</a></small></td>
+<td><small><a href="grfsnd.html" onmouseout="UnTip()" onmouseover="Tip(grfsnd_html_tip)">grfsnd.html</a></small></td>
+<td><small><a href="sndscm.html" onmouseout="UnTip()" onmouseover="Tip(sndscm_html_tip)">sndscm.html</a></small></td>
+<td><small><a href="sndclm.html" onmouseout="UnTip()" onmouseover="Tip(sndclm_html_tip)">sndclm.html</a></small></td>
+<td><small><a href="fm.html" onmouseout="UnTip()" onmouseover="Tip(fm_html_tip)">fm.html</a></small></td>
+<td><small><a href="sndlib.html" onmouseout="UnTip()" onmouseover="Tip(sndlib_html_tip)">sndlib.html</a></small></td>
+<td><small><a href="libxm.html" onmouseout="UnTip()" onmouseover="Tip(libxm_html_tip)">libxm.html</a></small></td>
+<td><small><a href="s7.html" onmouseout="UnTip()" onmouseover="Tip(s7_html_tip)">s7.html</a></small></td>
+<td><small><a href="index.html" onmouseout="UnTip()" onmouseover="Tip(index_html_tip)">index.html</a></small></td>
+</tr></table>
+</center>
+</body></html>