~ubuntu-branches/debian/sid/python-pyo/sid

« back to all changes in this revision

Viewing changes to pyolib/players.py

  • Committer: Package Import Robot
  • Author(s): Tiago Bortoletto Vaz
  • Date: 2012-06-08 20:35:45 UTC
  • Revision ID: package-import@ubuntu.com-20120608203545-4z7kcf2lgvpsk18y
Tags: upstream-0.6.1
ImportĀ upstreamĀ versionĀ 0.6.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Play soundfiles from the disk.
 
3
 
 
4
SfMarkerXXX objects use markers features (store in the header) from 
 
5
an AIFF file to create more specific reading patterns.
 
6
 
 
7
"""
 
8
"""
 
9
Copyright 2010 Olivier Belanger
 
10
 
 
11
This file is part of pyo, a python module to help digital signal
 
12
processing script creation.
 
13
 
 
14
pyo is free software: you can redistribute it and/or modify
 
15
it under the terms of the GNU General Public License as published by
 
16
the Free Software Foundation, either version 3 of the License, or
 
17
(at your option) any later version.
 
18
 
 
19
pyo is distributed in the hope that it will be useful,
 
20
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
GNU General Public License for more details.
 
23
 
 
24
You should have received a copy of the GNU General Public License
 
25
along with pyo.  If not, see <http://www.gnu.org/licenses/>.
 
26
"""
 
27
from _core import *
 
28
from _maps import *
 
29
import aifc
 
30
from types import ListType
 
31
 
 
32
class SfPlayer(PyoObject):
 
33
    """
 
34
    Soundfile player.
 
35
    
 
36
    Reads audio data from a file using one of several available interpolation 
 
37
    types. User can alter its pitch with the `speed` attribute. The object
 
38
    takes care of sampling rate conversion to match the Server sampling 
 
39
    rate setting.
 
40
    
 
41
    Parentclass: PyoObject
 
42
    
 
43
    Parameters:
 
44
    
 
45
    path : string
 
46
        Full path name of the sound to read.
 
47
    speed : float or PyoObject, optional
 
48
        Transpose the pitch of input sound by this factor. 1 is the 
 
49
        original pitch, lower values play sound slower, and higher 
 
50
        values play sound faster. Negative values results in playing 
 
51
        sound backward. Although the `speed` attribute accepts audio
 
52
        rate signal, its value is updated only once per buffer size. 
 
53
        Defaults to 1.
 
54
    loop : bool, optional
 
55
        If set to True, sound will play in loop. Defaults to False.
 
56
    offset : float, optional 
 
57
        Time in seconds of input sound to be skipped, assuming speed = 1. 
 
58
        Defaults to 0.
 
59
    interp : int, optional
 
60
        Interpolation type. Defaults to 2.
 
61
            1 : no interpolation
 
62
            2 : linear
 
63
            3 : cosinus
 
64
            4 : cubic
 
65
        
 
66
    Methods:
 
67
    
 
68
    setPath(path) : Replace the `path` attribute.
 
69
    setSound(path) : Replace the `path` attribute.
 
70
    setSpeed(x) : Replace the `speed` attribute.
 
71
    setLoop(x) : Replace the `loop` attribute.
 
72
    setOffset(x) : Replace the `offset` attribute.
 
73
    setInterp(x) : Replace the `interp` attribute.
 
74
    
 
75
    Attributes:
 
76
    
 
77
    path : string, Full path of the sound.
 
78
    sound : alias to the `path` attribute.
 
79
    speed : float or PyoObject, Transposition factor.
 
80
    loop : bool, Looping mode.
 
81
    offset : float, Time, in seconds, of the first sample to read.
 
82
    interp : int {1, 2, 3, 4}, Interpolation method.
 
83
    
 
84
    Notes:
 
85
    
 
86
    SfPlayer will sends a trigger signal at the end of the playback if 
 
87
    loop is off or any time it wraps around if loop is on. User can 
 
88
    retrieve the trigger streams by calling obj['trig']:
 
89
    
 
90
    >>> sf = SfPlayer(SNDS_PATH + "/transparent.aif").out()
 
91
    >>> trig = TrigRand(sf['trig'])
 
92
    
 
93
    Examples:
 
94
    
 
95
    >>> s = Server().boot()
 
96
    >>> s.start()
 
97
    >>> snd = SNDS_PATH + "/transparent.aif"
 
98
    >>> sf = SfPlayer(snd, speed=[.75,.8], loop=True, mul=.3).out()
 
99
    
 
100
    """
 
101
    def __init__(self, path, speed=1, loop=False, offset=0, interp=2, mul=1, add=0):
 
102
        PyoObject.__init__(self)
 
103
        self._path = path
 
104
        self._speed = speed
 
105
        self._loop = loop
 
106
        self._offset = offset
 
107
        self._interp = interp
 
108
        self._mul = mul
 
109
        self._add = add
 
110
        path, speed, loop, offset, interp, mul, add, lmax = convertArgsToLists(path, speed, loop, offset, interp, mul, add)
 
111
        self._base_players = []
 
112
        self._base_objs = []
 
113
        _trig_objs_tmp = []
 
114
        for i in range(lmax):
 
115
            _snd_size, _dur, _snd_sr, _snd_chnls, _format, _type  = sndinfo(path[0])
 
116
            self._base_players.append(SfPlayer_base(wrap(path,i), wrap(speed,i), wrap(loop,i), wrap(offset,i), wrap(interp,i)))
 
117
            for j in range(_snd_chnls):
 
118
                self._base_objs.append(SfPlay_base(self._base_players[-1], j, wrap(mul,i), wrap(add,i)))
 
119
                _trig_objs_tmp.append(TriggerDummy_base(self._base_players[-1]))
 
120
        self._trig_objs = Dummy(_trig_objs_tmp)
 
121
 
 
122
    def __dir__(self):
 
123
        return ['path', 'speed', 'loop', 'offset', 'interp', 'mul', 'add']
 
124
 
 
125
    def __del__(self):
 
126
        del self._trig_objs
 
127
        for obj in self._base_objs:
 
128
            obj.deleteStream()
 
129
            del obj
 
130
        for obj in self._base_players:
 
131
            obj.deleteStream()
 
132
            del obj
 
133
 
 
134
    def play(self, dur=0, delay=0):
 
135
        dur, delay, lmax = convertArgsToLists(dur, delay)
 
136
        self._trig_objs.play(dur, delay)
 
137
        self._base_players = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_players)]
 
138
        self._base_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
139
        return self
 
140
 
 
141
    def out(self, chnl=0, inc=1, dur=0, delay=0):
 
142
        dur, delay, lmax = convertArgsToLists(dur, delay)
 
143
        self._trig_objs.play(dur, delay)
 
144
        self._base_players = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_players)]
 
145
        if type(chnl) == ListType:
 
146
            self._base_objs = [obj.out(wrap(chnl,i), wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
147
        else:
 
148
            if chnl < 0:    
 
149
                self._base_objs = [obj.out(i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(random.sample(self._base_objs, len(self._base_objs)))]
 
150
            else:   
 
151
                self._base_objs = [obj.out(chnl+i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
152
        return self
 
153
    
 
154
    def stop(self):
 
155
        self._trig_objs.stop()
 
156
        [obj.stop() for obj in self._base_players]
 
157
        [obj.stop() for obj in self._base_objs]
 
158
        return self
 
159
        
 
160
    def setPath(self, path):
 
161
        """
 
162
        Sets a new sound to read.
 
163
        
 
164
        The number of channels of the new sound must match those 
 
165
        of the sound loaded at initialization time.
 
166
        
 
167
        Parameters:
 
168
        
 
169
        path : string
 
170
            Full path of the new sound.
 
171
 
 
172
        """
 
173
        if type(self._path) == ListType:
 
174
            curNchnls = sndinfo(self._path[0])[3]
 
175
        else:
 
176
            curNchnls = sndinfo(self._path)[3]
 
177
        if type(path) == ListType:
 
178
            p = path[0]
 
179
        else:
 
180
            p = path
 
181
        try:
 
182
            _snd_size, _dur, _snd_sr, _snd_chnls, _format, _type = sndinfo(p)
 
183
        except:
 
184
            return
 
185
        if _snd_chnls != curNchnls:
 
186
            print "Soundfile must contains exactly %d channels." % curNchnls
 
187
            return
 
188
    
 
189
        self._path = path
 
190
        path, lmax = convertArgsToLists(path)
 
191
        [obj.setSound(wrap(path,i)) for i, obj in enumerate(self._base_players)]
 
192
 
 
193
    def setSound(self, path):
 
194
        """
 
195
        Sets a new sound to read.
 
196
        
 
197
        The number of channels of the new sound must match those 
 
198
        of the sound loaded at initialization time.
 
199
        
 
200
        Parameters:
 
201
        
 
202
        path : string
 
203
            Full path of the new sound.
 
204
 
 
205
        """
 
206
        self.setPath(path)
 
207
 
 
208
    def setSpeed(self, x):
 
209
        """
 
210
        Replace the `speed` attribute.
 
211
        
 
212
        Parameters:
 
213
 
 
214
        x : float or PyoObject
 
215
            new `speed` attribute.
 
216
        
 
217
        """
 
218
        self._speed = x
 
219
        x, lmax = convertArgsToLists(x)
 
220
        [obj.setSpeed(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
221
 
 
222
    def setLoop(self, x):
 
223
        """
 
224
        Replace the `loop` attribute.
 
225
        
 
226
        Parameters:
 
227
 
 
228
        x : bool {True, False}
 
229
            new `loop` attribute.
 
230
        
 
231
        """
 
232
        self._loop = x
 
233
        x, lmax = convertArgsToLists(x)
 
234
        for i, obj in enumerate(self._base_players):
 
235
            if wrap(x,i): obj.setLoop(1)
 
236
            else: obj.setLoop(0)
 
237
 
 
238
    def setOffset(self, x):
 
239
        """
 
240
        Replace the `offset` attribute.
 
241
        
 
242
        Parameters:
 
243
 
 
244
        x : float
 
245
            new `offset` attribute.
 
246
        
 
247
        """
 
248
        self._offset = x
 
249
        x, lmax = convertArgsToLists(x)
 
250
        [obj.setOffset(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
251
 
 
252
    def setInterp(self, x):
 
253
        """
 
254
        Replace the `interp` attribute.
 
255
        
 
256
        Parameters:
 
257
 
 
258
        x : int {1, 2, 3, 4}
 
259
            new `interp` attribute.
 
260
        
 
261
        """
 
262
        self._interp = x
 
263
        x, lmax = convertArgsToLists(x)
 
264
        [obj.setInterp(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
265
 
 
266
    def ctrl(self, map_list=None, title=None, wxnoserver=False):
 
267
        self._map_list = [SLMap(-2., 2., 'lin', 'speed', self._speed), SLMapMul(self._mul)]
 
268
        PyoObject.ctrl(self, map_list, title, wxnoserver)
 
269
 
 
270
    @property
 
271
    def path(self): 
 
272
        """string. Full path of the sound."""
 
273
        return self._path
 
274
    @path.setter
 
275
    def path(self, x): self.setPath(x)
 
276
          
 
277
    @property
 
278
    def sound(self): 
 
279
        """string. Alias to the `path` attribute."""
 
280
        return self._path
 
281
    @sound.setter
 
282
    def sound(self, x): self.setPath(x)
 
283
    
 
284
    @property
 
285
    def speed(self): 
 
286
        """float or PyoObject. Transposition factor."""
 
287
        return self._speed
 
288
    @speed.setter
 
289
    def speed(self, x): self.setSpeed(x)
 
290
 
 
291
    @property
 
292
    def loop(self): 
 
293
        """bool. Looping mode."""
 
294
        return self._loop
 
295
    @loop.setter
 
296
    def loop(self, x): self.setLoop(x)
 
297
 
 
298
    @property
 
299
    def offset(self): 
 
300
        """float. Time, in seconds, of the first sample to read."""
 
301
        return self._offset
 
302
    @offset.setter
 
303
    def offset(self, x): self.setOffset(x)
 
304
 
 
305
    @property
 
306
    def interp(self): 
 
307
        """int {1, 2, 3, 4}. Interpolation method."""
 
308
        return self._interp
 
309
    @interp.setter
 
310
    def interp(self, x): self.setInterp(x)
 
311
 
 
312
class SfMarkerShuffler(PyoObject):
 
313
    """
 
314
    AIFF with markers soundfile shuffler.
 
315
    
 
316
    Reads audio data from a AIFF file using one of several available 
 
317
    interpolation types. User can alter its pitch with the `speed` 
 
318
    attribute. The object takes care of sampling rate conversion to 
 
319
    match the Server sampling rate setting. 
 
320
    
 
321
    The reading pointer randomly choose a marker (from the MARK chunk
 
322
    in the header of the AIFF file) as its starting point and reads 
 
323
    the samples until it reaches the following marker. Then, it choose 
 
324
    another marker and reads from the new position and so on...
 
325
    
 
326
    Parentclass: PyoObject
 
327
    
 
328
    Parameters:
 
329
    
 
330
    path : string
 
331
        Full path name of the sound to read. Can't e changed after
 
332
        initialization.
 
333
    speed : float or PyoObject, optional
 
334
        Transpose the pitch of input sound by this factor. 1 is the 
 
335
        original pitch, lower values play sound slower, and higher 
 
336
        values play sound faster. Negative values results in playing 
 
337
        sound backward. Although the `speed` attribute accepts audio
 
338
        rate signal, its value is updated only once per buffer size. 
 
339
        Defaults to 1.
 
340
    interp : int, optional
 
341
        Choice of the interpolation method. Defaults to 2.
 
342
            1 : no interpolation
 
343
            2 : linear
 
344
            3 : cosinus
 
345
            4 : cubic
 
346
        
 
347
    Methods:
 
348
    
 
349
    setSpeed(x) : Replace the `speed` attribute.
 
350
    setInterp(x) : Replace the `interp` attribute.
 
351
    getMarkers() : Returns a list of marker time values in samples.
 
352
    
 
353
    Attributes:
 
354
    
 
355
    speed : float or PyoObject, Transposition factor.
 
356
    interp : int {1, 2, 3, 4}, Interpolation method.
 
357
 
 
358
    Examples:
 
359
    
 
360
    >>> s = Server().boot()
 
361
    >>> s.start()
 
362
    >>> sf = SfMarkerShuffler(SNDS_PATH + "/transparent.aif", speed=[1,1], mul=.3).out()
 
363
    
 
364
    """
 
365
    def __init__(self, path, speed=1, interp=2, mul=1, add=0):
 
366
        PyoObject.__init__(self)
 
367
        self._speed = speed
 
368
        self._interp = interp
 
369
        self._mul = mul
 
370
        self._add = add
 
371
        path, speed, interp, mul, add, lmax = convertArgsToLists(path, speed, interp, mul, add)
 
372
        self._base_players = []
 
373
        self._base_objs = []
 
374
        self._snd_size, self._dur, self._snd_sr, self._snd_chnls, _format, _type = sndinfo(path[0])
 
375
        for i in range(lmax):
 
376
            try:
 
377
                sf = aifc.open(wrap(path,i))
 
378
                markerstmp = sf.getmarkers()
 
379
                sf.close()
 
380
                self._markers = [m[1] for m in markerstmp]
 
381
            except:
 
382
                self._markers = []    
 
383
            self._base_players.append(SfMarkerShuffler_base(wrap(path,i), self._markers, wrap(speed,i), wrap(interp,i)))
 
384
        for i in range(lmax * self._snd_chnls):
 
385
            j = i / self._snd_chnls
 
386
            self._base_objs.append(SfMarkerShuffle_base(wrap(self._base_players,j), i % self._snd_chnls, wrap(mul,j), wrap(add,j)))
 
387
 
 
388
    def __dir__(self):
 
389
        return ['speed', 'interp', 'mul', 'add']
 
390
 
 
391
    def __del__(self):
 
392
        for obj in self._base_objs:
 
393
            obj.deleteStream()
 
394
            del obj
 
395
        for obj in self._base_players:
 
396
            obj.deleteStream()
 
397
            del obj
 
398
                        
 
399
    def play(self, dur=0, delay=0):
 
400
        dur, delay, lmax = convertArgsToLists(dur, delay)
 
401
        self._base_players = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_players)]
 
402
        self._base_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
403
        return self
 
404
 
 
405
    def out(self, chnl=0, inc=1, dur=0, delay=0):
 
406
        dur, delay, lmax = convertArgsToLists(dur, delay)
 
407
        self._base_players = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_players)]
 
408
        if type(chnl) == ListType:
 
409
            self._base_objs = [obj.out(wrap(chnl,i), wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
410
        else:
 
411
            if chnl < 0:    
 
412
                self._base_objs = [obj.out(i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(random.sample(self._base_objs, len(self._base_objs)))]
 
413
            else:   
 
414
                self._base_objs = [obj.out(chnl+i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
415
        return self
 
416
    
 
417
    def stop(self):
 
418
        [obj.stop() for obj in self._base_players]
 
419
        [obj.stop() for obj in self._base_objs]
 
420
        return self
 
421
        
 
422
    def setSpeed(self, x):
 
423
        """
 
424
        Replace the `speed` attribute.
 
425
        
 
426
        Parameters:
 
427
 
 
428
        x : float or PyoObject
 
429
            new `speed` attribute.
 
430
        
 
431
        """
 
432
        self._speed = x
 
433
        x, lmax = convertArgsToLists(x)
 
434
        [obj.setSpeed(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
435
 
 
436
    def setInterp(self, x):
 
437
        """
 
438
        Replace the `interp` attribute.
 
439
        
 
440
        Parameters:
 
441
 
 
442
        x : int {1, 2, 3, 4}
 
443
            new `interp` attribute.
 
444
        
 
445
        """
 
446
        self._interp = x
 
447
        x, lmax = convertArgsToLists(x)
 
448
        [obj.setInterp(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
449
 
 
450
    def getMarkers(self):
 
451
        """
 
452
        Returns a list of marker time values in samples.
 
453
        
 
454
        """
 
455
        return self._markers
 
456
        
 
457
    def ctrl(self, map_list=None, title=None, wxnoserver=False):
 
458
        self._map_list = [SLMap(0.01, 2., 'lin', 'speed', self._speed), SLMapMul(self._mul)]
 
459
        PyoObject.ctrl(self, map_list, title, wxnoserver)
 
460
                    
 
461
    @property
 
462
    def speed(self): 
 
463
        """float or PyoObject. Transposition factor."""
 
464
        return self._speed
 
465
    @speed.setter
 
466
    def speed(self, x): self.setSpeed(x)
 
467
 
 
468
    @property
 
469
    def interp(self): 
 
470
        """int {1, 2, 3, 4}. Interpolation method."""
 
471
        return self._interp
 
472
    @interp.setter
 
473
    def interp(self, x): self.setInterp(x)
 
474
 
 
475
class SfMarkerLooper(PyoObject):
 
476
    """
 
477
    AIFF with markers soundfile looper.
 
478
 
 
479
    Reads audio data from a AIFF file using one of several available 
 
480
    interpolation types. User can alter its pitch with the `speed`
 
481
    attribute. The object takes care of sampling rate conversion to 
 
482
    match the Server sampling rate setting. 
 
483
    
 
484
    The reading pointer loops a specific marker (from the MARK chunk
 
485
    in the header of the AIFF file) until it received a new integer 
 
486
    in the `mark` attribute.
 
487
 
 
488
    Parentclass: PyoObject
 
489
 
 
490
    Parameters:
 
491
 
 
492
    path : string
 
493
        Full path name of the sound to read.
 
494
    speed : float or PyoObject, optional
 
495
        Transpose the pitch of input sound by this factor. 1 is the 
 
496
        original pitch, lower values play sound slower, and higher 
 
497
        values play sound faster. Negative values results in playing 
 
498
        sound backward. Although the `speed` attribute accepts audio
 
499
        rate signal, its value is updated only once per buffer size. 
 
500
        Defaults to 1.
 
501
    mark : float or PyoObject, optional
 
502
        Integer denoting the marker to loop, in the range 
 
503
        0 -> len(getMarkers()). Defaults to 0.
 
504
    interp : int, optional
 
505
        Choice of the interpolation method. Defaults to 2.
 
506
            1 : no interpolation
 
507
            2 : linear
 
508
            3 : cosinus
 
509
            4 : cubic
 
510
 
 
511
    Methods:
 
512
 
 
513
    setSpeed(x) : Replace the `speed` attribute.
 
514
    setInterp(x) : Replace the `interp` attribute.
 
515
    setMark(x) : Replace the `mark` attribute.
 
516
    getMarkers() : Returns a list of marker time values in samples.
 
517
 
 
518
    Attributes:
 
519
 
 
520
    speed : float or PyoObject, Transposition factor.
 
521
    mark : float or PyoObject, Marker to loop.
 
522
    interp : int {1, 2, 3, 4}, Interpolation method.
 
523
 
 
524
    Examples:
 
525
 
 
526
    >>> s = Server().boot()
 
527
    >>> s.start()
 
528
    >>> a = SfMarkerLooper(SNDS_PATH + '/transparent.aif', speed=[.999,1], mul=.3).out()
 
529
    >>> rnd = RandInt(len(a.getMarkers()), 2)
 
530
    >>> a.mark = rnd
 
531
 
 
532
    """
 
533
    def __init__(self, path, speed=1, mark=0, interp=2, mul=1, add=0):
 
534
        PyoObject.__init__(self)
 
535
        self._speed = speed
 
536
        self._mark = mark
 
537
        self._interp = interp
 
538
        self._mul = mul
 
539
        self._add = add
 
540
        path, speed, mark, interp, mul, add, lmax = convertArgsToLists(path, speed, mark, interp, mul, add)
 
541
        self._base_players = []
 
542
        self._base_objs = []
 
543
        self._snd_size, self._dur, self._snd_sr, self._snd_chnls, _format, _type = sndinfo(path[0])
 
544
        for i in range(lmax):
 
545
            try:
 
546
                sf = aifc.open(wrap(path,i))
 
547
                markerstmp = sf.getmarkers()
 
548
                sf.close()
 
549
                self._markers = [m[1] for m in markerstmp]
 
550
            except:
 
551
                self._markers = []    
 
552
            self._base_players.append(SfMarkerLooper_base(wrap(path,i), self._markers, wrap(speed,i), wrap(mark,i), wrap(interp,i)))
 
553
        for i in range(lmax * self._snd_chnls):
 
554
            j = i / self._snd_chnls
 
555
            self._base_objs.append(SfMarkerLoop_base(wrap(self._base_players,j), i % self._snd_chnls, wrap(mul,j), wrap(add,j)))
 
556
 
 
557
    def __dir__(self):
 
558
        return ['speed', 'mark', 'interp', 'mul', 'add']
 
559
 
 
560
    def __del__(self):
 
561
        for obj in self._base_objs:
 
562
            obj.deleteStream()
 
563
            del obj
 
564
        for obj in self._base_players:
 
565
            obj.deleteStream()
 
566
            del obj
 
567
 
 
568
    def play(self, dur=0, delay=0):
 
569
        dur, delay, lmax = convertArgsToLists(dur, delay)
 
570
        self._base_players = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_players)]
 
571
        self._base_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
572
        return self
 
573
 
 
574
    def out(self, chnl=0, inc=1, dur=0, delay=0):
 
575
        dur, delay, lmax = convertArgsToLists(dur, delay)
 
576
        self._base_players = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_players)]
 
577
        if type(chnl) == ListType:
 
578
            self._base_objs = [obj.out(wrap(chnl,i), wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
579
        else:
 
580
            if chnl < 0:    
 
581
                self._base_objs = [obj.out(i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(random.sample(self._base_objs, len(self._base_objs)))]
 
582
            else:   
 
583
                self._base_objs = [obj.out(chnl+i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
 
584
        return self
 
585
 
 
586
    def stop(self):
 
587
        [obj.stop() for obj in self._base_players]
 
588
        [obj.stop() for obj in self._base_objs]
 
589
        return self
 
590
 
 
591
    def setSpeed(self, x):
 
592
        """
 
593
        Replace the `speed` attribute.
 
594
 
 
595
        Parameters:
 
596
 
 
597
        x : float or PyoObject
 
598
            new `speed` attribute.
 
599
 
 
600
        """
 
601
        self._speed = x
 
602
        x, lmax = convertArgsToLists(x)
 
603
        [obj.setSpeed(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
604
 
 
605
    def setMark(self, x):
 
606
        """
 
607
        Replace the `mark` attribute.
 
608
 
 
609
        Parameters:
 
610
 
 
611
        x : float or PyoObject
 
612
            new `mark` attribute.
 
613
 
 
614
        """
 
615
        self._mark = x
 
616
        x, lmax = convertArgsToLists(x)
 
617
        [obj.setMark(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
618
 
 
619
    def setInterp(self, x):
 
620
        """
 
621
        Replace the `interp` attribute.
 
622
 
 
623
        Parameters:
 
624
 
 
625
        x : int {1, 2, 3, 4}
 
626
            new `interp` attribute.
 
627
 
 
628
        """
 
629
        self._interp = x
 
630
        x, lmax = convertArgsToLists(x)
 
631
        [obj.setInterp(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
632
 
 
633
    def getMarkers(self):
 
634
        """
 
635
        Returns a list of marker time values in samples.
 
636
 
 
637
        """
 
638
        return self._markers
 
639
 
 
640
    def ctrl(self, map_list=None, title=None, wxnoserver=False):
 
641
        self._map_list = [SLMap(0.01, 2., 'lin', 'speed', self._speed), 
 
642
                          SLMap(0, len(self._markers)-1, 'lin', 'mark', self._mark, 'int'),
 
643
                          SLMapMul(self._mul)]
 
644
        PyoObject.ctrl(self, map_list, title, wxnoserver)
 
645
 
 
646
    @property
 
647
    def speed(self): 
 
648
        """float or PyoObject. Transposition factor."""
 
649
        return self._speed
 
650
    @speed.setter
 
651
    def speed(self, x): self.setSpeed(x)
 
652
 
 
653
    @property
 
654
    def mark(self): 
 
655
        """float or PyoObject. Marker to loop."""
 
656
        return self._marker
 
657
    @mark.setter
 
658
    def mark(self, x): self.setMark(x)
 
659
 
 
660
    @property
 
661
    def interp(self): 
 
662
        """int {1, 2, 3, 4}. Interpolation method."""
 
663
        return self._interp
 
664
    @interp.setter
 
665
    def interp(self, x): self.setInterp(x)