1\documentclass{article}
2\usepackage[T1]{fontenc}
3\usepackage{ae}
4
5%\usepackage{html}
6%\bodytext{link="#662a00" vlink="#666655" bgcolor="#ffffff"}
7
8\title{Ecasound Control Interface Guide}
9\author{Kai Vehmanen, Brad Bowman, Tony Leake, Jan Weil, Mario Lang}
10\date{03062006}
11\begin{document}
12
13\maketitle
14\tableofcontents
15\clearpage
16
17% ----------------------------------------------------------------------
18% ----------------------------------------------------------------------
19\section{Introduction}
20The idea behind the Ecasound Control Interface (ECI) is to take a subset of
21functionality provided by libecasound, provide a simple API for it, and
22port it to various languages. At the moment, implementations of the
23ECI API are available for C, C++, elisp, Python and Ruby. These all
24come by default with the Ecasound package. Additional implementations,
25for example for Perl and PHP, are distributed independently.
26
27ECI is heavily based on Ecasound's interactive mode (EIAM), and the
28services it provides. See \texttt{ecasound-iam(1) manual page} for
29a detailed EIAM documentation.
30
31% ----------------------------------------------------------------------
32% ----------------------------------------------------------------------
33\section{Document history}
34\begin{itemize}
35\item 04.06.2006 - Added more information to the ``Tips for debugging'' section.
36\item 21.03.2005 - Updated the ``Tips for debugging'' section.
37\item 25.09.2004 - Updated the ``Return values'' section based on feedback
38                   from Adam Linson.
39\item 02.05.2004 - ``Emacs'' section added (written by Mario Lang).
40\item 28.11.2003 - ``Ruby'' section added  (written by Jan Weil).
41                   Updated the introduction.
42\item 26.11.2003 - Fix filename for the alternative Python API (eci.py).
43\item 18.11.2003 - Typo fixes. Updated documentation to reflect the new
44                   naming convention (ecasound refers to the binary,
45		   Ecasound refers to the whole package).
46\item 26.10.2002 - Changed the C++ linking example.
47\item 24.10.2002 - Added ``Notes Concerning Standalone ECI Implementations''
48                   section. Added compilation examples.
49\item 06.10.2002 - Added ``Application development'' section.
50\item 05.10.2002 - Changed the libecasoundc link path.
51\item 29.09.2002 - ``PHP'' section added (written by Tony Leake).
52\item 25.04.2002 - Changed headers path from ``<ecasoundc/file.h>'' to
53                   ``<file.h>'' and added library version number to
54                   link instructions.
55\item 21.10.2001 - Added this history section. Minor changes to
56      ECI examples.
57\end{itemize}
58
59% ----------------------------------------------------------------------
60% ----------------------------------------------------------------------
61\section{General}
62ECI doesn't provide any routines that directly manipulate audio or
63Ecasound objects. What it does provide is an easy and generic way
64to issue EIAM (Ecasound Inter-Active Mode) commands, access the
65command return-values and perform error handling.
66
67This approach has two benefits. First, it is possible to keep the API
68small, and thus make it easier to port ECI to new languages. Secondly,
69it's possible to keep ECI relatively stable. Ecasound itself is a large,
70developing library. New features are added all the time, and from time
71to time, older parts of the library will get rewritten to better suit
72new uses. Now for application developers wanting to take advantage of
73libecasound, these constant changes are very annoying, especially if
74your specific app doesn't need the latest new features. In these
75cases, ECI is the best platform for application development.
76
77
78% ----------------------------------------------------------------------
79\subsection{What's it good for?}
80
81Specific tasks ECI is aimed at:
82
83\begin{itemize}
84\item  1. automating (scripting in its traditional sense)
85\item  2. frontends (generic / specialized)
86\item  3. sound services to other apps
87\end{itemize}
88
89
90% ----------------------------------------------------------------------
91\subsection{Services and behaviour}
92
93Here is a list of services provided by all ECI implementations:
94
95\subsubsection{Actions}
96\begin{description}
97\item[command(string)]
98Issue an EIAM command.
99
100\item[command\_float\_arg(string, float)]
101Issue an EIAM command. This function can be used instead of
102\emph{command(string)}, if the command in question requires exactly one
103numerical parameter. This way it's possible to avoid the extra
104string -> float conversion, which would lead to lost precision.
105\end{description}
106
107\subsubsection{Return values}
108Each EIAM command has exactly one return value type. After a command
109has been issued, only one last\_type() functions returns a non-empty
110value. For example, last\_float() only returns a valid value if
111\emph{last\_type() == 'f'} holds true. Not all EIAM commands return
112a value (return type is void).
113
114\begin{description}
115\item[last\_string()]
116Returns the last string return value.
117
118\item[last\_string\_list()]
119Returns the last collection of strings (one or more strings).
120
121\item[last\_float()]
122Returns the last floating-point return value. Note! last\_float()
123doesn't refer to the C/C++ type 'float'. In most implementations,
124floats are 64bit values (doubles in C/C++).
125
126\item[last\_integer()]
127Returns the last integer return value. This function is also
128used to return boolean values, where non-zero means 'true'
129and zero 'false'.
130
131\item[last\_long\_integer()]
132Returns the last long integer return value. Long integers are
133used to pass values like 'length\_in\_samples' and 'length\_in\_bytes'.
134It's implementation specific whether there's any real difference
135between integers and long integers.
136\end{description}
137
138\subsubsection{Errors}
139\begin{description}
140\item[error()]
141Returns true (!= 0) if error has occured during the execution
142of last EIAM command. Otherwise returns false (= 0).
143
144\item[last\_error()]
145Returns a string describing the last error. If the last EIAM command
146was executed successfully, last\_error() returns an empty string.
147
148\end{description}
149
150\subsubsection{Other}
151\begin{description}
152\item[initialize()]
153Reserve resources.
154
155\item[cleanup()]
156Free all reserved resources.
157\end{description}
158
159
160
161% ----------------------------------------------------------------------
162\subsection{Porting to new environments}
163Porting ECI to new languages should be easy. All there is to do is
164to implement the services listed in the previous section to the target
165language. In most cases it's to easiest to use the C++ or C ECI
166as the underlying implementation to build upon.
167
168
169
170% ----------------------------------------------------------------------
171% ----------------------------------------------------------------------
172\section{Implementations}
173
174
175% ----------------------------------------------------------------------
176\subsection{General}
177
178\subsubsection{Overview}
179This section contains overview of how ECI is implemented in the
180discussed language (eg. as a single class, set of classes, set of
181routines, etc).
182
183\subsubsection{Usage}
184A quick tutorial to get you started.
185
186\subsubsection{Example}
187Implementation of the following:
188\begin{enumerate}
189\item  Setup ECI to read audio from file, apply a 100Hz lowpass filter, and
190      send it to the soundcard (/dev/dsp).
191\item  Every second, check the current position. If the stream has
192      been running for over 15 seconds, exit immediately. Also,
193      every second, increase the lowpass filter's cutoff frequency
194      by 500Hz.
195\item  Stop the stream (if not already finished) and disconnect the
196      chainsetup. Print chain operator status info.
197\end{enumerate}
198
199
200% ----------------------------------------------------------------------
201\subsection{Notes Concerning Standalone ECI Implementations}
202
203The C implementation of ECI is not directly linked against the main
204Ecasound libraries. Instead, the ecasound executable is launched
205on the background and command pipes are used to communicate with it.
206
207The launched ecasound executable can be selected by using the
208\emph{ECASOUND} environment variable. If it is not defined,
209the C ECI implementation will try to launch ``ecasound'' (ie.
210has to be somewhere in PATH).
211
212In addition to the C implementation, this also affects all
213ECI implementations that are based on the C version. Currently
214this includes at least the Perl, PHP and Python ECI modules.
215
216% ----------------------------------------------------------------------
217\subsection{C++}
218\subsubsection{Overview}
219C++ implementation is based around the ECA\_CONTROL\_INTERFACE class.
220STL vector is used for representing collections of objects
221(last\_string\_list()).
222
223\subsubsection{Usage}
224\begin{enumerate}
225\item \#include <eca-control-interface.h>
226\item create an instance of the ECA\_CONTROL\_INTERFACE class
227      and use its member functions
228\item link you app agains libecasoundc (-lecasoundc)
229\item compilation example: \emph{c++ -o ecidoc\_example ecidoc\_example.cpp `libecasoundc-config --cflags --libs`}
230\end{enumerate}
231
232\subsubsection{Example}
233\begin{verbatim}
234
235#include <iostream>
236#include <unistd.h>
237#include <eca-control-interface.h>
238
239int main(int argc, char *argv[])
240{
241  double cutoff_inc = 500.0;
242
243  ECA_CONTROL_INTERFACE e;
244  e.command("cs-add play_chainsetup");
245  e.command("c-add 1st_chain");
246  e.command("ai-add some_file.wav");
247  e.command("ao-add /dev/dsp");
248  e.command("cop-add -efl:100");
249  e.command("cop-select 1");
250  e.command("copp-select 1");
251  e.command("cs-connect");
252  e.command("start");
253  while(1) {
254    sleep(1);
255    e.command("engine-status");
256    if (e.last_string() != "running") break;
257    e.command("get-position");
258    double curpos = e.last_float();
259    if (curpos > 15.0) break;
260    e.command("copp-get");
261    double next_cutoff = cutoff_inc + e.last_float();
262    e.command_float_arg("copp-set", next_cutoff);
263  }
264
265  e.command("stop");
266  e.command("cs-disconnect");
267  e.command("cop-status");
268  cerr << "Chain operator status: " << e.last_string() << endl;
269
270  return(0);
271}
272
273\end{verbatim}
274
275% ----------------------------------------------------------------------
276\subsection{C}
277\subsubsection{Overview}
278All C ECI functions are prefixed with "eci\_". When returning string
279values, a const pointer to a null-terminated char array (const char*)
280is returned. It's important to keep in mind that these are "borrowed"
281references. If you need to later use the data, you must copy
282it to application's own buffers.
283
284Returning a list of strings is implemented using two functions:
285\emph{eci\_last\_string\_list\_count()} returns the number of strings
286available, and \emph{eci\_last\_string\_list\_item(int n)} returns a
287pointer (const char*) to the string at index \emph{n}.
288
289\emph{Note!} As of Ecasound 2.0.1, the C ECI implementation also
290	  provides reentrant access to the ECI API. These
291	  alternative routines are marked with '\_r' postfix.
292
293\subsubsection{Usage}
294
295\begin{enumerate}
296\item \#include <ecasoundc.h>
297\item use the eci\_* routines
298\item link your app against libecasoundc (-lecasoundc)
299\item compilation example: \emph{gcc -o ecidoc\_example ecidoc\_example.c `libecasoundc-config --cflags --libs`}
300\end{enumerate}
301
302\subsubsection{Example}
303\begin{verbatim}
304
305#include <stdio.h>
306#include <unistd.h>
307#include <ecasoundc.h>
308
309int main(int argc, char *argv[])
310{
311  double cutoff_inc = 500.0;
312
313  eci_init();
314  eci_command("cs-add play_chainsetup");
315  eci_command("c-add 1st_chain");
316  eci_command("ai-add some_file.wav");
317  eci_command("ao-add /dev/dsp");
318  eci_command("cop-add -efl:100");
319  eci_command("cop-select 1");
320  eci_command("copp-select 1");
321  eci_command("cs-connect");
322  eci_command("start");
323
324  while(1) {
325    double curpos, next_cutoff;
326
327    sleep(1);
328    eci_command("engine-status");
329    if (strcmp(eci_last_string(), "running") != 0) break;
330    eci_command("get-position");
331    curpos = eci_last_float();
332    if (curpos > 15.0) break;
333    eci_command("copp-get");
334    next_cutoff = cutoff_inc + eci_last_float();
335    eci_command_float_arg("copp-set", next_cutoff);
336  }
337
338  eci_command("stop");
339  eci_command("cs-disconnect");
340  eci_command("cop-status");
341  printf("Chain operator status: %s", eci_last_string());
342  eci_cleanup();
343
344  return(0);
345}
346
347\end{verbatim}
348
349% ----------------------------------------------------------------------
350\subsection{Emacs}
351\subsubsection{Overview}
352The Ecasound package comes with an 'Ecasound' library for Emacs included.
353ecasound.el is a implementation of the ECI API for Emacs, as well
354as an interactive interface to Ecasound sessions implemented
355on top of that.  Simply use "M-x ecasound RET" to fire up an
356interactive Ecasound session.
357
358All Emacs Lisp ECI functions are prefixed with ``eci\-''.
359'ecasound.el' is implemented in a high level manner which means
360that you won't find most of the commands known from libecasoundc like
361last\_string, last\_float, etc.
362Instead of that every call to function "eci-command", which accepts all
363the well known IAM commands, returns ecasound's response in an appropriate type
364automatically.
365If an error occurs, e. g. there's a typo in a command or a file is not found,
366the function returns ``nil''.  In all other cases, either an automatically
367converted Lisp value is returned, or ``t'' in the case where there was no
368particular value returned.
369
370Additionally, most of the available IAM commands have their own Emacs Lisp
371function including documentation and possibly a parameter list.  All these
372functions are interactive, so you can use them in ecasound-iam-mode simply
373by invoking them via M-x or by pressing an assigned key combination.
374Emacs will prompt you for the required parameters, providing completion
375wherever possible.
376
377As a convention, "eci-command" and its variants do take a buffer or process
378as an optional last argument.  If this is ``nil'', the current
379buffer is assumed to be the ecasound session refered to by this call.
380This makes it possible to use several ECI sessions concurrently, dispatching
381on the buffer or process in use.
382
383\subsubsection{Usage}
384\begin{enumerate}
385\item  make ecasound.el available in your ``load-path''
386\item  (require 'ecasound)
387\item  create a buffer with an associated Ecasound session (``eci-init'')
388\item  use ``eci\-'' functions with the new buffer
389\end{enumerate}
390
391\subsubsection{Example}
392\begin{verbatim}
393(require 'ecasound)
394
395(defun example (file &optional cutoff-increment session)
396  (unless cutoff-increment (setq cutoff-increment 500.0))
397  (with-current-buffer (or session (eci-init))
398    (eci-cs-add "play_chainsetup")
399    (eci-c-add "1st_chain")
400    (eci-ai-add file)
401    (eci-ao-add "/dev/dsp")
402    (eci-cop-add "-efl:100")
403    (eci-cop-select 1)
404    (eci-copp-select 1)
405    (eci-cs-connect)
406    (eci-start)
407    (sit-for 1)
408    (while (and (string= (eci-engine-status) "running")
409                (<= (eci-get-position) 15))
410      (eci-copp-set (+ cutoff-increment (eci-copp-get)))
411      (sit-for 1))
412    (eci-command "stop")
413    (when (eci-cs-disconnect)
414      (destructuring-bind
415	  ((cop n1 (copp n2 val)))
416	  (cdr (assoc "1st_chain" (eci-cop-status)))
417	(message "%s %s is now %f" cop copp val)))))
418\end{verbatim}
419
420NOTE: function ``eci-cop-status'' is actually a very high level function
421which already converts the returned information to a nested list
422structure.
423
424For more complex examples of the Emacs Lisp ECI implementation, see function
425``eci-example'', ``ecasound-normalize'' and ``ecasound-signalview'' in
426ecasound.el.
427
428% ----------------------------------------------------------------------
429\subsection{Python}
430\subsubsection{Overview}
431Python implementation is based around the ECA\_CONTROL\_INTERFACE class.
432Lists are used for representing collections of objects.
433
434Note! Eric S. Tiedemann has written an alternative Python interface
435      to ECI. You'll find this interface included in the main
436      Ecasound packege, in ``pyecasound/eci.py''. To use this instead
437      of the standard interface, just 'import eci' and you're set! :)
438
439\subsubsection{Usage}
440
441\begin{enumerate}
442\item  import pyeca
443\item  create an instance of the ECA\_CONTROL\_INTERFACE class
444      and use its member functions
445\item  python 'yourapp.py' and that's it :)
446\end{enumerate}
447
448\subsubsection{Example}
449\begin{verbatim}
450
451#!/usr/local/bin/python
452import time
453from pyeca import *
454e = ECA_CONTROL_INTERFACE()
455e.command("cs-add play_chainsetup")
456e.command("c-add 1st_chain")
457e.command("ai-add some_file.wav")
458e.command("ao-add /dev/dsp")
459e.command("cop-add -efl:100")
460e.command("cop-select 1")
461e.command("copp-select 1")
462e.command("cs-connect")
463e.command("start")
464cutoff_inc = 500.0
465while 1:
466    time.sleep(1)
467    e.command("engine-status")
468    if e.last_string() != "running": break
469    e.command("get-position")
470    curpos = e.last_float()
471    if curpos > 15: break
472    e.command("copp-get")
473    next_cutoff = cutoff_inc + e.last_float()
474    e.command_float_arg("copp-set", next_cutoff)
475e.command("stop")
476e.command("cs-disconnect")
477e.command("cop-status")
478print "Chain operator status: ", e.last_string()
479
480\end{verbatim}
481
482% ----------------------------------------------------------------------
483\subsection{Perl}
484\subsubsection{Overview}
485Audio::Ecasound provides perl bindings to the Ecasound
486control interface of the Ecasound program.  You can use
487perl to automate or interact with Ecasound so you don't
488have to turn you back on the adoring masses packed into
489Wembly Stadium.
490
491Audio::Ecasound was written by Brad Bowman. At the moment this module
492is not distributed with Ecasound. To get the latest version, check the
493following \texttt{CPAN link}.
494
495\subsubsection{Usage}
496See the below example. For more info, here's another
497\texttt{CPAN link}.
498
499\subsubsection{Example}
500use Audio::Ecasound qw(:simple);
501
502\begin{verbatim}
503
504eci("cs-add play_chainsetup");
505eci("c-add 1st_chain");
506eci("ai-add some_file.wav");
507eci("ao-add /dev/dsp");
508# multiple \n separated commands
509eci("cop-add -efl:100
510     # with comments
511     cop-select 1
512     copp-select 1
513     cs-connect");
514eci("start");
515my $cutoff_inc = 500.0;
516while (1) {
517    sleep(1);
518    last if eci("engine-status") ne "running";
519    my $curpos = eci("get-position");
520    last if $curpos > 15;
521    my $next_cutoff = $cutoff_inc + eci("copp-get");
522    # Optional float argument
523    eci("copp-set", $next_cutoff);
524}
525eci("stop");
526eci("cs-disconnect");
527print "Chain operator status: ", eci("cop-status");
528
529\end{verbatim}
530
531% ----------------------------------------------------------------------
532\subsection{PHP}
533\subsubsection{Overview}
534This PHP extension provides bindings to the Ecasound
535control interface.  It is useful both for scripting Ecasound
536and for writing graphical audio applications with PHP Gtk.
537
538The PHP Ecasound extension was written by Tony Leake. At the moment this module
539is not distributed with Ecasound. The latest version and example scripts, are
540available from  \texttt{http://www.webwise-data.co.uk/php\_audio/php\_audio\_extension.html}.
541
542\subsubsection{Usage}
543\begin{enumerate}
544\item Obtain and build the Ecasound PHP extension
545\item Initialise Ecasound, eci\_int();
546\item Issue EAM commands eg, eci\_command("cs-add my\_chain\_setup");
547\item Free resources, eci\_cleanup();
548\end{enumerate}
549
550\subsubsection{Example}
551\begin{verbatim}
552
553Implementation of the following:
554
5551. Setup ECI to read audio from file, apply a 100Hz lowpass filter,
556and send it to the soundcard (/dev/dsp).
5572. Every second, check the current position. If the stream has been
558running for over 15 seconds, exit immediately. Also, every second,
559increase the lowpass filter's cutoff frequency by 500Hz.
5603. Stop the stream (if not already finished) and disconnect the chainsetup.
561Print chain operator status info
562
563<?php
564
565$cutoff_inc = 500.0;
566$curpos=0;
567$next_cutoff=0;
568
569eci_init();
570eci_command("cs-add play_chainsetup");
571eci_command("c-add 1st_chain");
572eci_command("ai-add /tmp/somefile.wav");
573eci_command("ao-add /dev/dsp");
574eci_command("cop-add -efl:10");
575eci_command("cop-select 1");
576eci_command("copp-select 1");
577eci_command("cs-connect");
578eci_command("start");
579
580while(1) {
581
582    sleep(1);
583
584    eci_command("engine-status");
585    if (eci_last_string() !="running"){
586        break;
587    }
588
589    eci_command("get-position");
590    $curpos = eci_last_float();
591    if ($curpos > 15.0){
592        break;
593    }
594
595    eci_command("copp-get");
596    $next_cutoff = $cutoff_inc + eci_last_float();
597    eci_command_float_arg("copp-set",$next_cutoff);
598}
599
600eci_command("stop");
601eci_command("cs-disconnect");
602eci_command("cop-status");
603
604printf("Chain operator status: %s", eci_last_string());
605
606eci_cleanup();
607?>
608\end{verbatim}
609
610% ----------------------------------------------------------------------
611\subsection{Ruby}
612\subsubsection{Overview}
613The Ecasound package comes with an 'Ecasound' module for Ruby included.
614If ruby is detected during the installation process it is installed
615automatically (assuming you are installing ecasound from source code).
616The module contains the class definition of a native ecasound control interface
617called "ControlInterface".
618
619'Ecasound::ControlInterface' is implemented in a high level manner which means
620that you won't find most of the commands known from libecasoundc like
621last\_string, last\_float, etc.
622Instead of that every call to the instance method "command", which accepts all
623the well known IAM commands, returns ecasound's response in an appropriate type
624automatically.
625If an error occurs, e. g. there's a typo in a command or a file is not found,
626an exception of type EcasoundError is raised.
627
628\subsubsection{Usage}
629\begin{enumerate}
630\item  require 'ecasound'
631\item  create an instance of Ecasound::ControlInterface
632\item  use it's command method to send IAM commands to ecasound
633\item  catch an EcasoundError if necessary
634\end{enumerate}
635
636\subsubsection{Example}
637\begin{verbatim}
638#!/usr/bin/env ruby
639require "ecasound"
640
641SOME_FILE = "path/to/file.wav"
642
643e = Ecasound::ControlInterface.new()
644e.command("cs-add play_chainsetup")
645e.command("c-add 1st_chain")
646e.command("ai-add #{SOME_FILE}")
647e.command("ao-add /dev/dsp")
648e.command("cop-add -efl:100")
649e.command("cop-select 1")
650e.command("copp-select 1")
651e.command("cs-connect")
652e.command("start")
653
654cutoff_inc = 500.0
655
656loop do
657    sleep(1)
658    break if e.command("engine-status") != "running"
659    break if e.command("get-position") > 15
660    e.command("copp-set #{cutoff_inc + e.command('copp-get')}")
661end
662
663e.command("stop")
664e.command("cs-disconnect")
665
666$stdout << "Chain operator status: " + e.command("cop-status") + "\n"
667\end{verbatim}
668
669% ----------------------------------------------------------------------
670% ----------------------------------------------------------------------
671\section{Application development}
672
673% ----------------------------------------------------------------------
674\subsection{Tips for debugging}
675
676Here's a few tips what to do if the ECI app you have developed
677is not working correctly.
678
679\begin{enumerate}
680\item Check your Ecasound installation. Try to run the ``ecasound''
681      console user-interface and verify that the basic functionality
682      is working (ie. something like ``ecasound -i foo.wav -o
683      /dev/dsp''.
684
685\item If developing in C or C++, check that your application
686      is correcly linked: ``ldd /path/to/myapp''. All the libraries
687      should be properly found.
688
689\item Check error conditions. You should remember to check
690      for errors in your ECI apps using the eci\_error() and
691      eci\_last\_error() functions. Especially when intializing
692      ECI for the first time and after important commands
693      like ``cs-connect'', you should always check for errors.
694
695\item Use the ECASOUND\_LOGFILE environment variable to write all
696      engine output to a separate logfile. See ecasound(1) manpage
697      for details on how to use this mechanism. Requires Ecasound
698      version 2.4.5 or newer.
699
700\item Utilize the ``int-log-history'' ECI command added to
701      version 2.4.0 of Ecasound. Recent messages from the
702      engine can help to track down the problem. Before use, you
703      need to first set the history length to a non-zero value with
704      ``int-set-log-history-length''.
705
706\item Launch Ecasound in interactive mode (``ecasound -c''),
707      and issue the commands your ECI application is using,
708      manually one-by-one and see what happens. If something
709      goes wrong, increase Ecasound's debug level (for instance
710      ``-ddd'') and re-run the test.
711
712\end{enumerate}
713
714\end{document}
715