diff options
author | Alessio Treglia <quadrispro@ubuntu.com> | 2009-10-19 09:55:11 +0200 |
---|---|---|
committer | Alessio Treglia <quadrispro@ubuntu.com> | 2009-10-19 09:55:11 +0200 |
commit | 5cd66eecc95be11cacc5aaf4db8c67a499bb2d4d (patch) | |
tree | f9fe35437c9a69b886676bbdeff692ebc728bec2 /extsnd.html |
Imported Upstream version 11
Diffstat (limited to 'extsnd.html')
-rw-r--r-- | extsnd.html | 13944 |
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 ">". 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> +><em class=typing>(+ 1 2)</em> +<em class=listener>3</em> +</pre></td><td width=60></td> + +<td bgcolor="#FdFdf2"><pre> +><em class=typing>1+2</em> +<em class=listener>3</em> +</pre></td><td width=60></td> + +<td bgcolor="#EefdEe"><pre> +><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 "0" returned is the new sound\'s \'index\'')"><pre> +><em class=typing>(open-sound "oboe.snd")</em> +<em class=listener>#<sound 0></em> +</pre></td><td></td> + +<td bgcolor="#FdFdf2"><pre> +><em class=typing>open_sound("oboe.snd")</em> +<em class=listener>0</em> +</pre></td><td></td> + +<td bgcolor="#EefdEe"><pre> +><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> +><em class=typing>(auto-resize)</em> +<em class=listener>#t</em> +</pre></td><td></td> + +<td bgcolor="#FdFdf2"><pre> +><em class=typing>auto_resize</em> +<em class=listener>true</em> +</pre></td><td></td> + +<td bgcolor="#EefdEe"><pre> +><em class=typing>auto-resize</em> +<em class=listener>#t</em> +</pre></td> +</tr> +<!-- ------------ --> + +<tr> +<td bgcolor="#fbfbff"><pre> +><em class=typing>(set! (auto-resize) #f)</em> +<em class=listener>#f</em> +</pre></td><td></td> + +<td bgcolor="#FdFdf2"><pre> +><em class=typing>set_auto_resize false</em> +<em class=listener>false</em> +</pre></td><td></td> + +<td bgcolor="#EefdEe"><pre> +><em class=typing>#f set-auto-resize</em> +<em class=listener>#f</em> +</pre></td> +</tr> +<!-- ------------ --> + +<tr> +<td bgcolor="#fbfbff"><pre> +><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: "0.01.0" should be "0.0 1.0"')"><pre> +><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> +><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> +><em class=typing>(load "bird.scm")</em> +<em class=listener>make-birds</em> +</pre></td><td></td> + +<td bgcolor="#FdFdf2"><pre> +><em class=typing>load "bird.rb"</em> +<em class=listener>true</em> +</pre></td><td></td> + +<td bgcolor="#EefdEe"><pre> +><em class=typing>"bird.fs" file-eval</em> +<em class=listener>0</em> +</pre></td> +</tr> +<!-- ------------ --> + +<tr> +<td bgcolor="#fbfbff"><pre> +><em class=typing>(map-channel (lambda (y) (* y 2)))</em> +<em class=listener>0</em> +</pre></td><td></td> + +<td bgcolor="#FdFdf2"><pre> +><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> +><em class=typing>lambda: <{ y }> y 2.0 f* ; map-channel</em> +<em class=listener>-0.00158691</em> +</pre></td> +</tr> +<!-- ------------ --> + +<tr> +<td bgcolor="#fbfbff"><pre> +><em class=typing>(define (plus a b) (+ a b))</em> +<em class=listener>plus</em> +</pre></td><td></td> + +<td bgcolor="#FdFdf2"><pre> +><em class=typing>def plus(a, b) a+b end</em> + +</pre></td><td></td> + +<td bgcolor="#EefdEe"><pre> +><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> +><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> +><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> +><em class=typing>1 0 0 make-color set-basic-color</em> +<em class=listener>#<XmRaw: Pixel 0x9d3b430></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 (> (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 — 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 "header-format" and "data-type"<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 "headerless",<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->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->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->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->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>></em><em class=typing>(set! (print-length) 3)</em> + <em class=listener>3</em> + <em class=listener>></em><em class=typing>(make-vct 10 .1)</em> + <em class=listener>#<vct[len=10]: 0.100 0.100 0.100 ...></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("/tmp"), Forth: "/tmp" 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 — 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: <{ snd }> "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> — can cancel request + no header?: <a class=quiet href="#openrawsoundhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openrawsoundhook_tip)">open-raw-sound-hook</a> — can cancel request + file ok: + <a class=quiet href="#openhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openhook_tip)">open-hook</a> — 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> — 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> — 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> — 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> — 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> — 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->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->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->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 (> (<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->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->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->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 — 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->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 — normally invisible) + 1: sound-open, File:open etc — the normal path to open a sound + 2: copy reader — 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 — 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 (> x 0.0) (< 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 (> dots 100) + (set! (<a class=quiet href="#dotsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_dotsize_tip)">dot-size</a> snd chn) 1) + (if (> dots 50) + (set! (<a class=quiet href="#dotsize" onmouseout="UnTip()" onmouseover="Tip(extsnd_dotsize_tip)">dot-size</a> snd chn) 2) + (if (> 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)) + (< (<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->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->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 (> (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->exact (/ (* beat sr) bps))) + (higher (inexact->exact (/ (* (+ 1 beat) sr) bps)))) + (set! (<a class=quiet href="#marksample" onmouseout="UnTip()" onmouseover="Tip(extsnd_marksample_tip)">mark-sample</a> mrk) + (if (< (- 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->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->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->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 -> 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: <{ snd chn button state x y axis -- }> + 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->x</a> and <a href="#positiontoy">position->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->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, ">(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 — 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 (> 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 (> (cadr (<a class=quiet href="#ybounds" onmouseout="UnTip()" onmouseover="Tip(extsnd_ybounds_tip)">y-bounds</a> snd)) 1.0) ; previous (pre-update) version was > 1.0 + (<= 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->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 — 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: <{ }> #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 (< (<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->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 "&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->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->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->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>#<sound 0></em> + :<em class=typing>(define reader (make-sampler 1000))</em> + <em class=listener>reader</em> + :<em class=typing>reader</em> + <em class=listener>#<sampler: oboe.snd[0: 0] from 1000, at 1000, forward></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>(#<sound 0> 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->vct reg :optional (chn 0)) + (if (<a class=quiet href="#regionok" onmouseout="UnTip()" onmouseover="Tip(extsnd_regionok_tip)">region?</a> reg) + (if (< 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->vct" reg chn))) + (throw 'no-such-region (list "region->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->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->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->sample</a> (:optional snd)</code> +</td></tr><tr><td width=30><br></td><td> +make-snd->sample creates a Snd data reader for use with CLM's in-any, file->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->sample</a> (gen frame :optional chan)</code> +</td></tr><tr><td><br></td><td> +snd->sample gets the next sample from the data accessed by 'gen', similar to file->sample. +If *reverb* is a snd->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->sample</a> actually call snd->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->sample?</a> (obj)</code> +</td></tr><tr><td><br></td><td> +snd->sample? returns #t if 'obj' is a snd->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 — 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->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->vct (list 0.1 0.2 0.3))</em> + <em class=listener>#<vct[len=3]: 0.100 0.200 0.300></em> + :<em class=typing>(vct 0.1 0.2 0.3)</em> + <em class=listener>#<vct[len=3]: 0.100 0.200 0.300></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>#<vct[len=3]: 0.100 0.100 0.100></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->vct</em> (sdobj (chan 0) (v #f))</code> +</td></tr><tr><td></td><td> +sound-data->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->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->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>#<unspecified></em> +:<em class=typing>(vct-add! v1 (vct .3 .2 .1))</em> +<em class=listener>#<vct[len=3]: 0.400 0.400 0.400></em> +:<em class=typing>v1</em> +<em class=listener>#<vct[len=3]: 0.400 0.400 0.400></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->vector</a>, <a href="sndscm.html#vcttoframe">vct->frame</a><br> +copy mix: <a href="sndscm.html#mixtovct">mix->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->vct</a>, or <a href="#savesoundas">save-sound-as</a><br> +copy selection data: <a href="#selection2vct">selection->vct</a> or <a href="#saveselection">save-selection</a><br> +copy region data: <a href="#regiontovct">region->vct</a>, <a href="#regiontovct">region->vct</a>, <a href="#saveregion">save-region</a>, or <a href="sndscm.html#regiontosounddata">region->sound-data</a><br> +copy transform data: <a href="#transformtovct">transform->vct</a><br> +copy sound-data: <a href="#sounddatatovct">sound-data->vct</a><br> +copy a frame: <a href="sndscm.html#framecopy">frame-copy</a>, <a href="sndscm.html#frametovct">frame->vct</a><br> +copy vector: <a href="#vectortovct">vector->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>#<unspecified></em> +:<em class=typing>(vct-move! v1 0 5)</em> +<em class=listener>#<vct[len=10]: 6.000 7.000 8.000 9.000 10.000 6.000 7.000 8.000 9.000 10.000></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>#<unspecified></em> +:<em class=typing>(vct-subseq v1 3 6)</em> +<em class=listener>#<vct[len=4]: 4.000 5.000 6.000 7.000></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->channel</a> (v :optional (beg 0) dur snd chn edpos origin)</code> +</td></tr><tr><td></td><td> +vct->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->channel to paste in an fm-violin note as +an edit: +<pre> + + (vct->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->list</a> (v)</code> +</td></tr><tr><td></td><td> +vct->list returns a list with elements of 'v'. +<pre> + ;; Scheme: + :<em class=typing>(vct->list (list->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></em> <em class=typing>'( 0.1 0.2 0.3 ) list->vct vct->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->sound-data</em> (v sd :optional (chan 0))</code> +</td></tr><tr><td></td><td> +vct->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->string</a> (v)</code> +</td></tr><tr><td></td> +<td> +vct->string returns a Scheme-readable string describing 'v'. The standard way of displaying a vct +uses "#<vct...>" 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>#<vct[len=3]: 0.100 0.100 0.100></em> + :<em class=typing>(vct->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->vector --> +<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vcttovector">vct->vector</a> (v)</code> +</td></tr><tr><td></td><td> +vct->vector returns a vector with the elements of 'v'. +</td></tr><tr><td colspan=2 height=16></td></tr> + + +<!-- vector->vct --> +<tr><td colspan=2 bgcolor="#f2f4ff"><code><a class=def name="vectortovct">vector->vct</a> (vect)</code> +</td></tr><tr><td></td><td> +vector->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->vct</a> region samples to vct + <a href="#transformtovct">transform->vct</a> fft data to vct + <a href="#channeltovct">channel->vct</a> channel samples to vct + <a href="sndscm.html#mixtovct">mix->vct</a> mix samples to vct + <a href="#sounddatatovct">sound-data->vct</a> sound-data samples to vct + <a href="#vectortovct">vector->vct</a> vector data to vct (assumed to be floats) + <a href="#selection2vct">selection->vct</a> selected samples to vct + <a href="sndscm.html#filetovct">file->vct</a> file data to vct + <a href="sndscm.html#frametovct">frame->vct</a> frame data to vct + <a href="sndscm.html#vcttoframe">vct->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))) + ((< 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->channel</em> (vct-polynomial (<em class=red>channel->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, <=>, etc. See vct.c and the Ruby documentation for a complete list. +</p> +<pre> + :<em class=typing>v1</em> + <em class=listener>#<vct[len=10]: 0.100 0.100 0.100 3.000 0.100 0.100 0.100 0.100 0.100 0.100></em> + :<em class=typing>v1.find_all {|x| x > 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>#<vct[len=10]: 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100></em> + :<em class=typing>v2 < 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>#<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)></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>#<unspecified></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>#<unspecified></em> + :<em class=typing>sd1</em> + <em class=listener>#<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)></em> + :<em class=typing>(sound-data-add! (sound-data-fill! (make-sound-data 2 5) .25) sd1)</em> + <em class=listener>#<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)></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>#<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)></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>></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>#<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)></em> + :<em class=typing>(sound-data-reverse! sd1)</em> + <em class=listener>#<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)></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>></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->sound-data</a> (sd-in sd-out beg dur cycle)</code> +</td></tr><tr><td></td><td> +sound-data->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->vct</a> (sd chan v)</code> +</td></tr><tr><td></td><td> +sound-data->vct copies sound-data sd's channel 'chan' data into vct v. +<pre> + :<em class=typing>sd1</em> + <em class=listener>#<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)></em> + :<em class=typing>(sound-data->vct sd1 1)</em> + <em class=listener>#<vct[len=5]: 9.000 8.000 7.000 6.000 5.000></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->sound-data</a> (v sd chan)</code> +</td></tr><tr><td></td><td> +vct->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 + ((> 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> — 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->string</a> (format)</code> +</td></tr><tr><td></td><td> +mus-data-format->string converts 'format' from an integer to a string, e.g. "mus-mulaw". +<pre> + :<em class=typing>(mus-data-format->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->string</a> (error)</code> +</td></tr><tr><td></td><td> +mus-error-type->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->string</a> (type)</code> +</td></tr><tr><td></td><td> +mus-header-type->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->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->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->string (channels file)) + ", srate: " (number->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->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>#<mark 0></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->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->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->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->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>(#<mark 0>)</em> ; just one + :<em class=typing>(mark-home (car (marks 0 0)))</em> ; what is that mark's snd/chn? + <em class=listener>(#<sound 0> 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 "now the same piece is played".<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>(#<mark 1> #<mark 0>)</em> ; these are mark id's, as returned by the add-mark function for example + :<em class=typing>(marks 1)</em> + <em class=listener>(() (#<mark 2>))</em> ; no mark in channel 0, one in channel 1 + :<em class=typing>(marks)</em> + <em class=listener>(((#<mark 1> #<mark 0>)) (() (#<mark 2>)))</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 +<sound's file-name>.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->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->integer and integer->mix. +Say we have a mix object stored in the variable "id": +</p> +<pre> + ><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->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->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->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->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>(#<mix 0> #<mix 2>)</em> ; these are mix objects, as returned by the mix function for example + :<em class=typing>(mixes 1)</em> + <em class=listener>(() (#<mix 1>))</em> ; no mix in channel 0, one in channel 1 + :<em class=typing>(mixes)</em> + <em class=listener>(((#<mix 0> #<mix 2>)) (() (#<mix 1>)))</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>#<mix 0></em> + :<em class=typing>(mix-home mx)</em> + <em class=listener>(#<sound 0> 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>#<mix 1></em> + :<em class=typing>(mix-home mx)</em> + <em class=listener>(#<sound 0> 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->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->tag-y freq lo octs) ; tag height dependent on freq + (inexact->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)">->frequency</a> freq #t) amp)) ; our favorite FM instrument + (<a class=quiet href="sndscm.html#tosample" onmouseout="UnTip()" onmouseover="Tip(sndscm_tosample_tip)">->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->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->tag-y (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">->frequency</a> freq #t) (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">->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)">->frequency</a> freq #t) amp :fm-index 1.5)) + (<a class=quiet href="sndscm.html#tosample" onmouseout="UnTip()" onmouseover="Tip(sndscm_tosample_tip)">->sample</a> beg) 0 index 0 + #t #t))) + (if (symbol? freq) + (set! (<em class=red>mix-name</em> id) (symbol->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->tag-y (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">->frequency</a> freq #t) (<a class=quiet href="sndscm.html#tofrequency" onmouseout="UnTip()" onmouseover="Tip(sndscm_tofrequency_tip)">->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->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->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)">->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)">->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->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->vct 1000 3)</em> ; what are these 3 samples before the mix? + <em class=listener>#<vct[len=3]: -0.065 -0.059 -0.060></em> + :<em class=typing>(define mx (mix-vct (vct .1 .2 .3) 1000))</em> ; add these 3 values + <em class=listener>#<mix 3></em> + :<em class=typing>(channel->vct 1000 3)</em> ; now we hope they were added... + <em class=listener>#<vct[len=3]: 0.035 0.141 0.240></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>#<mix 4></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->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->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->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 -> 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>#<region 1></em> + :<em class=typing>(region-frames (integer->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->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->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->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->vct</a> reg :optional samp samps chan v</code> +</td></tr><tr><td></td><td> +region->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->vct</em> (integer->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)">&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->frame</a><br> +<a href="sndscm.html#regiontosounddata">region->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)">&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->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))) + ((>= 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->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>#<region 1></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>#<region 2></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->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->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->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->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->position</a> +could be: + +<table border=0 cellpadding=5 vspace=10><tr><td><pre> +(define (x->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->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 (> 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 (> (<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->vct</a> (:optional beg dur snd chn edpos)</code> +</td></tr><tr><td></td><td> +channel->vct returns a vct with the specified data. In Ruby, the "->" 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->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->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->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->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 — 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) (> y .1))) + + Ruby: count_matches(lambda do |y| y > 0.1 end) + + Forth: lambda: <{ y }> y 0.1 f- f0< ; 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->x</a> and <a href="#positiontoy">position->y</a>: +<pre> + (<a class=quiet href="#positiontox" onmouseout="UnTip()" onmouseover="Tip(extsnd_positiontox_tip)">position->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->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 — 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 — 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 — 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' < 1.0 gives convex curves (i.e. bowed +out), and 'env-base' > 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->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->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> +><em class=typing>(find-channel (lambda (y) (> y .1)))</em> +<em class=listener>(#t 4423)</em> + +><em class=typing>(find-channel (lambda (y) (and (> y .1) 'a-big-sample)))</em> +<em class=listener>(a-big-sample 4423)</em> ; if optimization is on, this will be (#t 4423) + +><em class=typing>lambda: <{ y }> 0.1 y f< ; 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 (< 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->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->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->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: + ><em class=typing>(map-channel (lambda (y) (+ y 0.2)))</em> + <em class=listener>0</em> + +Ruby: + ><em class=typing>map_channel(lambda do |y| y + 0.2 end)</em> + <em class=listener>-0.0015869140625</em> + +Forth: + ><em class=typing>lambda: <{ y }> 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>></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>></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>></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>></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 (> 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 (> 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 (> y 1.0) + (begin + (set! go-on stop) + (throw 'oops))))) + .2)) +</pre></td></tr></table> + +If this hits a sample > 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 — 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->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)">&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)">&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 > ~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> — can cancel request + no header?: <a class=quiet href="#openrawsoundhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openrawsoundhook_tip)">open-raw-sound-hook</a> — can cancel request + file ok: + <a class=quiet href="#openhook" onmouseout="UnTip()" onmouseover="Tip(extsnd_openhook_tip)">open-hook</a> — 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->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->sample</a> and +<a class=quiet href="sndclm.html#filetoarray" onmouseout="UnTip()" onmouseover="Tip(sndclm_filetoarray_tip)">file->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->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->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->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 (<= 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> — 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->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->exact (round (* (<a class=quiet href="#srate" onmouseout="UnTip()" onmouseover="Tip(extsnd_srate_tip)">srate</a> snd) (position->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->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->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 => 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 — 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 (> 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->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->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->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 — if you're +running a loop through a bunch of samples, use the <a href="#samplers">samplers</a> +or <a href="#channeltovct">channel->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>#<vct[len=10]: 0.033 0.035 0.034 0.031 0.026 0.020 0.013 0.009 0.005 0.004></em> + <em class=listener>:</em><em class=typing>(set! (samples 1000 10) (make-vct 10 .1))</em> + <em class=listener>#<vct[len=10]: 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100 0.100></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)">&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> — 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->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->vct</a>) 2.0) 0) +(<a class=quiet href="sndscm.html#sounddatatosound" onmouseout="UnTip()" onmouseover="Tip(sndscm_sounddatatosound_tip)">sound-data->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->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->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->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->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->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! — 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 (<= 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> +><em class=typing>(scan-channel (lambda (y) (> 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)))) + +><em class=typing>(every-sample? (lambda (y) (< 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))) + (> 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) (> 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) (> 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->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> + ><em class=typing>(open-sound "oboe.snd")</em> + <em class=listener>#<sound 0></em> + ><em class=typing>(file-name (integer->sound 0))</em> + <em class=listener>"/home/bil/cl/oboe.snd"</em> + ><em class=typing>(short-file-name (integer->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 (> 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->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))) + ((< 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>#<env linear, pass: 35236 (dur: 20000), index: 1, scaler: 1.0000, offset: 0.0000, ...></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))) + ((>= 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 (< (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)) -> 0.693147180559945 +:;; (src-duration '(0 1 1 .5)) -> 1.38629436111989 +;;; (src-duration '(0 .5 .5 3 .6 1 .7 .1 .8 1.5 1 1)) -> 1.02474349685432 + +;;; here we're using this in the Snd listener: +<em class=listener>></em><em class=typing>(frames)</em> +<em class=listener>220501</em> +<em class=listener>></em><em class=typing>(src-duration '(0 1 1 2))</em> +<em class=listener>0.693147180559945</em> +<em class=listener>></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>></em><em class=typing>(frames)</em> +<em class=listener>152842</em> +<em class=listener>></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->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->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 — 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 -> 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 — 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 — 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->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->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->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->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->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->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 — .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 — 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>#<sound 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>(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->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->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->function</em><em class=typing>))</em> ; same example as above + <em class=listener>#<unspecified></em> + :<em class=typing>our-edits</em> + <em class=listener>#<procedure our-edits ((snd chn) (scale-channel 2.0 0 #f 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 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>#<Proc:0x40c713ec@(eval):2></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> <em class=typing>"oboe.snd" open-sound</em> + <em class=listener>0</em> + snd> <em class=typing>2.0 scale-channel</em> + <em class=listener>2.0</em> + snd> <em class=typing>100 200 pad-channel</em> + <em class=listener>100</em> + snd> <em class=typing>0 0 edit-list->function value our-edits</em> + <em class=listener>nil</em> + snd> <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> <em class=typing>2 undo</em> + <em class=listener>2</em> + snd> <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 (<= pos rs) + (>= nxtpos ls)) ; fragment is at least partially visible + (let ((x0pos (<a class=quiet href="#xtoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_xtoposition_tip)">x->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->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 &" 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->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->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->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->unvoiced effect: <a href="sndscm.html#voicedtounvoiced">voiced->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 (> dur1 dur2) 1 + (if (< 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: <{ }> "item1" snd-print ; undef add-to-menu drop + new-menu "Second Item" lambda: <{ }> "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" — 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->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->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 ">". 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 — 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></em> <em class=typing>"this is a test" report-in-minibuffer</em> + <em class=listener>this is a test</em> + <em class=listener>snd></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 <X11/xkeysymdef.h>, 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->cursor-on-left") + +(<em class=red>bind-key</em> #\v 4 + (lambda () + "move ahead one window" + (if (< (<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->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->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 (> (- 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->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->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 (>= val 0.0) (< newval 0.0)) + (and (< val 0.0) (>= 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 (> 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 (> 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 (< 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 <Key>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-<something> + (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-<something> + (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>></em> <em class=typing>(outer 456)</em> + <em class=listener>hiho></em> + <em class=listener>snd-top-level</em> + <em class=listener>hiho></em> <em class=typing>x</em> + <em class=listener>32</em> + <em class=listener>hiho></em> <em class=typing>arg</em> + <em class=listener>1</em> + <em class=listener>hiho></em> <em class=typing>y</em> + <em class=listener>"a string"</em> + <em class=listener>hiho></em> <em class=typing>(break-ok)</em> + <em class=listener>></em> + <em class=listener>outer></em> + <em class=listener>snd-top-level</em> + <em class=listener>outer></em> <em class=typing>y</em> + <em class=listener>123</em> + <em class=listener>outer></em> <em class=typing>(break-ok)</em> + <em class=listener>></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 — 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 — 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> — 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> + ><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>#<procedure #f (() "move one pixel forward" (move-one-pixel (selected-sound) (selected-channel) #t))></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 — +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 — 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->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> + ><em class=typing>(selection-position)</em> + <em class=listener>selection-position: no-active-selection</em> + ><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> +><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> + ><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> + ><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&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> + ><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->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->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->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->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->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->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->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 (< ls samp) + (> rs samp)) + (let ((xpos (<a class=quiet href="#xtoposition" onmouseout="UnTip()" onmouseover="Tip(extsnd_xtoposition_tip)">x->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->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 (-> 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->exact (- y0 (* .4 size))) + (* 2 size) + (inexact->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 (< left 2000) + (> 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->exact (round (/ (* size left-offset) samps)))) + (right-offset (- (min 2000 right) left)) + (right-bin (inexact->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 (< 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->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->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> |