1package Audio::Ecasound;
2
3require 5.005_62;
4use Carp;
5use strict;
6use vars qw(@ISA @EXPORT %EXPORT_TAGS @EXPORT_OK $VERSION $AUTOLOAD);
7
8require Exporter;
9require DynaLoader;
10
11@ISA = qw(Exporter DynaLoader);
12
13# base names for methods (correspond to the C eci_X and eci_X_r versions)
14my @cmds = qw(
15        command
16        command_float_arg
17
18        last_float
19        last_integer
20        last_long_integer
21        last_string
22        last_string_list_count
23        last_string_list_item
24        last_type
25
26        error
27        last_error
28    );
29
30%EXPORT_TAGS = (
31    simple => [qw( eci on_error errmsg )],
32    std => [ @cmds ],
33    raw => [ map { "eci_$_" } @cmds ],
34    raw_r => [ qw(eci_init_r eci_cleanup_r), map { "eci_$_"."_r" } @cmds ],
35    # NOTE the :iam tag is added dynamically in &import
36);
37
38# NOTE :iam adds to this in &import
39@EXPORT_OK = ( map { @{$_} } @EXPORT_TAGS{'simple', 'std','raw','raw_r'} );
40
41my %iam_cmds;
42sub get_iam_cmds { return keys %iam_cmds; }
43
44sub import {
45    # When :iam is imported, the internal commands (len >=2)
46    # are found with eci 'int-cmd-list' and declared
47    # hyphens are converted to underscores to produce legal names
48    if(grep { /^:iam$/ } @_) {
49        my @iam_cmds = map { s/-/_/g; (/^\w{2,}$/)? $_ : () } eci('int-cmd-list');
50        $EXPORT_TAGS{iam} = [ @iam_cmds ];
51        push @EXPORT_OK, @iam_cmds;
52        $iam_cmds{$_} = 1 for (@iam_cmds);
53    }
54    Audio::Ecasound->export_to_level(1,@_);
55}
56
57# AUTOLOAD to proxy iam commands as functions
58# defines iam commands as they are used
59sub AUTOLOAD {
60    my $cmd = $AUTOLOAD;
61    $cmd =~ s/.*:://;
62
63    unless($iam_cmds{$cmd}) {
64        # can't you pass? Just pretend by doing what perl would do
65        croak "Undefined subroutine $AUTOLOAD called";
66    }
67
68    no strict 'refs';
69    *$cmd = sub {
70        $cmd =~ s/_/-/g; # eg cop_list => cop-list;
71        eci(join ' ', $cmd, @_);
72    };
73    goto &$cmd;
74}
75
76$VERSION = '1.01';
77bootstrap Audio::Ecasound $VERSION;
78
79# Generate wrappers(OO or not-OO) for raw C functions
80for my $cmd (@cmds) {
81    # eg. the 'command' sub is a perl wrapper which
82    # calls 'eci_command' or 'eci_command_r' depending
83    # on whether it's called as a method
84    no strict 'refs';
85    *$cmd = sub {
86        my $self = &_shift_self;
87        if(ref $self) {
88            # treat string as function name (symref), pass handle
89            "eci_${cmd}_r"->($self->{eci_handle}, @_);
90        } else {
91            "eci_$cmd"->(@_);
92        }
93    };
94}
95
96# Overriding DynaLoader's method so that .so symbols are
97# globally visible, hence ecasound-plugins (like libaudioio_af.so)
98# can link to them
99sub dl_load_flags { 0x01 }
100
101my %opts = (
102        on_error => 'warn', # 'die', '', 'cluck', 'confess'
103        errmsg => '',
104    );
105
106# generate accessors
107for my $option (keys %opts) {
108    no strict 'refs';
109    *$option = sub {
110
111        my $self = &_shift_self;
112        my $opts = \%opts;
113
114        if(ref $self) {
115            # use object's hash
116            $opts = $self;
117        }
118        $opts->{$option} = shift if @_;
119        return $opts->{$option};
120    };
121}
122
123sub new {
124    my $arg = shift;
125    my $class = ref($arg) || $arg;
126    my $self = { %opts }; # object gets current package values
127    $self->{eci_handle} = eci_init_r();
128    bless $self, $class;
129}
130
131sub do_error {
132    my $self = &_shift_self;
133    my $errstr = shift;
134
135    $self->errmsg($errstr);
136
137    my $on_error = $self->on_error;
138    no strict 'refs';
139    if($on_error eq 'die') {
140        die "Audio::Ecasound::error: $errstr\n";
141    } elsif($on_error eq 'warn') {
142        warn "Audio::Ecasound::error: $errstr\n";
143    } elsif(exists &{"Carp::$on_error"}) {
144        &{"Carp::$on_error"}("Audio::Ecasound::error: $errstr\n");
145    } elsif($on_error) {
146        die "Audio::Ecasound::error: $errstr\n"
147            ."(And on_error=$on_error is bad)\n";
148    }
149    return;
150}
151
152# do everything in one function
153sub eci {
154
155    my $self = &_shift_self;
156
157    my $cmdstr = shift;
158    if(@_) {
159        my $float = shift;
160        $self->command_float_arg($cmdstr, $float);
161        $cmdstr .= ' ' . $float;
162        # Handle an eci error
163        if($self->error()) {
164            my $errstr = $self->last_error() . "(in $cmdstr)";
165            return $self->do_error($errstr);
166        }
167    } else {
168        # multiline commands
169        for my $mcmdstr (split /\n/, $cmdstr) {
170
171            # Comments
172            $mcmdstr =~ s/#.*//;
173            $mcmdstr =~ s/^\s+//;
174            $mcmdstr =~ s/\s+$//;
175            # Skip blanks
176            next if $mcmdstr =~ /^$/;
177
178            $self->command($mcmdstr);
179
180            # Handle an eci error ( would be 'e' return code )
181            if($self->error()) {
182                my $errstr = $self->last_error() . "(in $mcmdstr)";
183                return $self->do_error($errstr);
184            }
185        }
186    }
187
188    # do return value
189    return unless defined wantarray;
190    my $ret;
191    my $type = $self->last_type();
192    if($type eq 'i') {
193        return $self->last_integer();
194    } elsif($type eq 'f') {
195        return $self->last_float();
196    } elsif($type eq 's') {
197        return $self->last_string();
198    } elsif($type eq 'li') {
199        return $self->last_long_integer();
200    } elsif($type eq '' || $type eq '-') { # - from python
201        return ''; # false but defined
202    } elsif($type eq 'S') {
203        my $count = $self->last_string_list_count();
204        # differentiate from () err when ambiguous
205        return ('') unless ($count && $self->on_error);
206        my @ret;
207        for my $n (0..$count-1) {
208            push @ret, $self->last_string_list_item($n);
209        }
210        return @ret;
211    } elsif($type eq 'e') { # should be handled above...
212        my $errstr = $self->last_error() . "(in $cmdstr)";
213        return $self->do_error($errstr);
214    } else {
215        die "last_type() returned unexpected type <$type>";
216    }
217}
218
219
220# Look at first argument and return something that
221# can be used as an object, either a blessed ref
222# a class name which isa A::E or the string
223# 'Audio::Ecasound' (can be used 'Audio::Ecasound'->eci($c))
224# NOTE: should be called &_shift_self to shift @_ for parent;
225sub _shift_self {
226    if(!defined $_[0]) {
227        return __PACKAGE__;
228    } elsif(ref $_[0]) {
229        return shift;
230    } elsif ( $_[0] =~ /^[_a-zA-Z][\w:']*$/ # Common package names
231            && UNIVERSAL::isa($_[0],__PACKAGE__) ) {
232            #&& $_[0]->isa(__PACKAGE__) ) {
233        return shift;
234    } else {
235        return __PACKAGE__;
236    }
237}
238
239DESTROY {
240    my $self = shift;
241    eci_cleanup_r($self->{eci_handle});
242}
243
244END {
245    # Partner eci_init in XS BOOT:
246    eci_cleanup();
247}
248
249
2501;
251__END__
252
253=head1 NAME
254
255Audio::Ecasound - Perl binding to the ecasound sampler, recorder, fx-processor
256
257=head1 SYNOPSIS
258
259One function interface:
260
261    use Audio::Ecasound qw(:simple);
262
263    eci("cs-add play_chainsetup");
264    eci("c-add 1st_chain");
265    eci("-i:some_file.wav");
266    eci("-o:/dev/dsp");
267    # multiple \n separated commands
268    eci("cop-add -efl:100
269         # with comments
270         cop-select 1
271         copp-select 1
272         cs-connect");
273    eci("start");
274    my $cutoff_inc = 500.0;
275    while (1) {
276        sleep(1);
277        last if eci("engine-status") ne "running";
278
279        my $curpos = eci("get-position");
280        last if $curpos > 15;
281
282        my $next_cutoff = $cutoff_inc + eci("copp-get");
283        # Optional float argument
284        eci("copp-set", $next_cutoff);
285    }
286    eci("stop");
287    eci("cs-disconnect");
288    print "Chain operator status: ", eci("cop-status");
289
290Object Interface
291
292  use Audio::Ecasound;
293
294  my $e = new Audio::Ecasound;
295  $e->on_error('');
296  $e->eci("cs-add play_chainsetup");
297  # etc.
298
299Vanilla Ecasound Control Interface (See Ecasound's Programmer Guide):
300
301  use Audio::Ecasound qw(:std);
302
303  command("copp-get");
304  $precise_float = last_float() / 2;
305  command_float_arg("copp-set", $precise_float);
306  warn last_error() if error();
307
308IAM Interface, pretend interactive mode commands are functions.
309
310  use Audio::Ecasound qw(:iam :simple);
311
312  # iam commands as functions with s/-/_/g
313  my $val = copp_get;
314  copp_set $val+0.1; # floats are stringified so beware
315  eci("-i /dev/dsp"); # not all commands are exported
316
317=head1 DESCRIPTION
318
319Audio::Ecasound provides perl bindings to the ecasound control interface of the
320ecasound program.  You can use perl to automate or interact with
321ecasound so you don't have to turn you back on the adoring masses
322packed into Wembly Stadium.
323
324Ecasound is a software package designed for multitrack audio processing.
325It can be used for audio playback, recording, format conversions,
326effects processing, mixing, as a LADSPA plugin host and JACK node.
327Version E<gt>= 2.2.X must be installed to use this package.
328L<SEE ALSO> for more info.
329
330=head1 INSTALLATION
331
332 perl Makefile.PL
333
334If your perl wasn't built with -Dusethreads or -D_REENTRANT you
335will be prompted whether to continue with the install.  It's in
336your hands... See L<THREADING NOTE>
337
338 make
339 make test
340 make install
341
342=head1 THREADING NOTE
343
344The ecasoundc library uses pthreads so will may only work if
345your perl was compiled with threading enabled, check with:
346
347 % perl -V:usethreads
348
349You are welcome to try using the module with non-threaded perls
350(perhaps -D_REENTRANT alone would work) it have worked for some.
351
352=head1 EXPORT
353
354=over 4
355
356=item *
357
358Nothing by default as when going OO.
359
360=item *
361
362:simple gives eci() which does most everything, also errmsg and on_error.
363Or you could just import 'eci' and call the others C<Audio::Ecasound::errmsg()>
364
365=item *
366
367:iam imports many iam commands so that you can use them as perl functions.
368Basically everything listed by ecasound's 'int-cmd-list' except the single
369letter commands and hyphens are replaced by underscores.
370The list is produced at run-time and returned by Audio::Ecasound::get_iam_cmds().
371See L<IAM COMMANDS>;
372
373=item *
374
375:std to import the full ecasound control interface detailed in the
376Ecasound Programmer's Guide.
377
378=item *
379
380:raw and raw_r, C functions with minimal wrapping, _r ones are reentrant
381and must be passed the object returned by eci_init_r().  I don't know why
382you would use these, presumably you do.  These options may be removed in
383future.
384
385=back
386
387=head1 METHODS AND FUNCTIONS
388
389The procedural and OO interfaces use the same functions, the differences
390are that when called on an Audio::Ecasound object the reentrant C versions
391are used so you can have multiple independent engine (with independent
392options).
393
394=over 2
395
396=item B<new()>
397
398Constructor for Audio::Ecasound objects, inherits the on_error and
399other options from the current package settings (defaults if untouched).
400
401=item B<eci('ecasound command string', [$float_argument])>
402
403Sends commands to the Ecasound engine. A single command may be called with an
404optional float argument (to avoid precision loss). Alternatively,
405multiple commands may be given separated by newlines (with C<#> starting
406a comment).
407
408If called in non-void context the result of the last command is
409returned, it may be an integer, float, string (ie. scalar) or a list of
410strings. Which will depend on the ecasound command, see L<ecasound-iam>
411for each function's return value.
412
413If there is an error the action given to on_error will be taken.
414See on_error below for return value caveats when on_error = ''.
415Error processing is performed for each command in a multiline command.
416
417=item B<on_error('die')>
418
419Set the action to be taken when an error occurs from and C<eci>
420command, may be 'die', 'warn', '', 'confess', ... (default is 'warn').
421
422When '' is selected C<return;> is used for an error, that is undef or
423().  To disamibiguate eci will return '' or ('') for no return value
424and no string list respectively.
425
426=item B<errmsg()>
427
428The last error message from an C<eci> command.  It is not reset
429so clear it yourself if required C<errmsg('')>.  This shouldn't
430be necessary as you can use C<defined> or on_error to find out
431when errors occur.
432
433=back
434
435The remainder of the functions/methods are the standard Ecasound
436Control Interface methods but they come in three flavours.
437The bare function name may be called with or without an object:
438
439  use Audio::Ecasound ':simple':
440  command($cmd);
441  # or
442  my $e = new Audio::Ecasound;
443  $e = command($cmd);
444
445The other two flavours are low-level, reentrant and non-reentrant.
446These are thinly wrapped C functions better documented in the ECI
447document with the ecasound distribution.  Just add 'eci_' to the
448names below for the non-reentrant version and then add a '_r'
449to the end for the reentrant version.  The reentrant version takes
450an extra first argument, the object returned by eci_init_r() which
451must be destroyed with eci_cleanup_r().
452
453=over 4
454
455=item B<command($cmd_string)>
456
457=item B<eci_command_float_arg($cmd_string, $float_arg)>
458
459=item B<$bool = eci_error()>
460
461=item B<$err_str = eci_last_error()>
462
463=item B<$float = eci_last_float()>
464
465=item B<$int = eci_last_integer()>
466
467=item B<$lint = eci_last_long_integer()>
468
469=item B<$str = eci_last_string()>
470
471=item B<$n = eci_last_string_list_count()>
472
473=item B<$str_n = eci_last_string_list_item($n)>
474
475=item B<$type_str = eci_last_type()> 's' 'S' 'i' 'li' 'f' ''
476
477=back
478
479=head1 IAM COMMANDS
480
481When the :iam tag is imported most of the commands in ecasounds
482interactive mode become perl functions.  The '-'s become '_'s
483to become valid perl names ('cop-get' is cop_get, etc.)
484The list is printed with:
485
486  use Audio::Ecasound qw(:iam :simple);
487  print join ' ', Audio::Ecasound::get_iam_cmds();
488
489The arguments joined together as a string and then sent to ecasound.
490This means that float precision is lost, unlike with the two
491argument C<eci> so use it.  Also use C<eci> for command-line style
492commands like C<eci "-i /dev/dsp">.  But most other things you
493can just use the iam command itself (s/-/_/g):
494
495  use Audio::Ecasound qw(:iam :simple);
496  ... # setup stuff
497  print status;
498  start;
499  $v = copp_get;
500  copp_set $v + 1.2;
501
502I would never encourage anyone to use C<no strict 'subs';> but with :iam you
503may enjoy a little less discipline.
504
505See the iam_int.pl example file in the eg directory.
506
507=head1 EXAMPLES
508
509See the C<eg/> subdirectory.
510
511=head1 TROUBLESHOOTING
512
513The ecasound command 'debug' could be useful, add C<eci "debug 63">
514to the top of your program.  The argument is various bits OR'd
515and controls the amount and type of debugging information, see the
516ecasound documentation of source or just try your favorite powers
517of two.
518
519There was a bug effecting Audio::Ecasound with ecasound version
5202.4.4, causing problems with :iam mode, and test failure
521("Do you need to predeclare cs_set_length").  See
522L<http://www.eca.cx/ecasound-list/2006/12/0007.html> and
523L<http://www.eca.cx/ecasound-list/2006/06/0004.html>.
524
525=head1 FILES AND ENVIRONMENT
526
527The libecasoundc library now uses the environment variable
528"ECASOUND" to find the ecasound executable.  If it is not set then
529the libarary will print a warning.  To suppress it, simply set
530the ECASOUND variable: eg. export ECASOUND=ecaosund
531
532The ecasound library will still process ~/.ecasoundrc and other
533setup files for default values.  See the library documentation.
534
535=head1 AUTHOR
536
537(c) 2001-2007 Brad Bowman E<lt>eci-perl@bereft.netE<gt>
538This software may be distributed under the same terms as Perl itself.
539
540=head1 SEE ALSO
541
542The Ecasound Programmer's Guide and ECI doc,
543L<ecasound>, L<ecasound-iam> http://eca.cx/, http://www.ladspa.org/
544
545The internals of libecasoundc have been rebuilt and now interact with
546a running ecasound via a socket using a protocol defined in the
547Programmer's Guide.  The C library is now just a compatibility layer
548and the Python version now talks directly to the socket.
549It would be straight forward to write an equivalent Perl version
550should the need arise.
551
552=cut
553