コード例 #1
0
    def armGenerator(self, generator_name):
        generator_name = self.validateGenerator(generator_name)

        armed = getattr(self.ns, 'armed', [])

        if generator_name is not None and generator_name not in armed:
            dsp.log('arming %s...' % generator_name)
            armed += [generator_name]
            setattr(self.ns, 'armed', armed)

            gen = self.loadGenerator(generator_name)
            ctl = self.setupCtl(gen)
            grid_ctl = self.loadGridCtl()
            trigger = midi.MidiTrigger(gen.trigger['device'],
                                       gen.trigger['notes'])

            respawn = mp.Event()

            p = mp.Process(target=self._armGenerator,
                           args=(generator_name, gen, ctl, trigger, respawn,
                                 grid_ctl))
            p.start()

            while generator_name in armed:
                respawn.wait()
                respawn.clear()
                p = mp.Process(target=self._armGenerator,
                               args=(generator_name, gen, ctl, trigger,
                                     respawn, grid_ctl))
                p.start()
                armed = getattr(self.ns, 'armed', [])
コード例 #2
0
ファイル: io.py プロジェクト: PaulBatchelor/pippi
    def armGenerator(self, generator_name):
        generator_name = self.validateGenerator(generator_name)

        armed = getattr(self.ns, 'armed', [])

        if generator_name is not None and generator_name not in armed:
            dsp.log('arming %s...' % generator_name)
            armed += [ generator_name ]
            setattr(self.ns, 'armed', armed)

            gen = self.loadGenerator(generator_name)
            ctl = self.setupCtl(gen)

            trigger = midi.MidiTrigger(gen.trigger['device'], gen.trigger['notes'])

            respawn = mp.Event()

            p = mp.Process(target=self._armGenerator, args=(generator_name, gen, ctl, trigger, respawn))
            p.start()

            while generator_name in armed:
                respawn.wait()
                respawn.clear()
                dsp.log('rearming %s...' % generator_name)
                p = mp.Process(target=self._armGenerator, args=(generator_name, gen, ctl, trigger, respawn))
                p.start()
                armed = getattr(self.ns, 'armed', [])
コード例 #3
0
    def wait(self):
        try:
            with mido.open_input(self.device_name) as incoming:
                for msg in incoming:
                    if msg.type == 'note_on' and msg.note in self.notes:
                        return (msg.note, msg.velocity)
        except IOError:
            dsp.log('Could not arm MIDI device %s' % self.device_name)

        return (None, None)
コード例 #4
0
ファイル: midi.py プロジェクト: bensteinberg/pippi
def register_midi_listener(device_name, ns):
    # check to see if this device has a listener already
    # start one up if not
    if not hasattr(ns, '%s-listener' % device_name):
        try:
            listener = mp.Process(target=device_scribe, args=(device_name, ns))
            listener.start()
            setattr(ns, '%s-listener' % device_name, listener.pid)
        except IOError:
            dsp.log('Could not start listener for unknown MIDI device: %s' % device_name)
コード例 #5
0
ファイル: midi.py プロジェクト: bensteinberg/pippi
    def wait(self):
        try:
            with mido.open_input(self.device_name) as incoming:
                for msg in incoming:
                    if msg.type == 'note_on' and msg.note in self.notes:
                        return (msg.note, msg.velocity)
        except IOError:
            dsp.log('Could not arm MIDI device %s' % self.device_name)

        return (None, None)
コード例 #6
0
ファイル: io.py プロジェクト: bensteinberg/pippi
    def _playGenerator(self, generator_name, gen, voice_id, ctl, grid_ctl):
        try:
            os.nice(-2)
        except OSError:
            os.nice(0)

        if not hasattr(self.ns, 'reload'):
            setattr(self.ns, 'reload', False)

        render_process = None
        def render_again(gen, ctl, generator_name, voice_id, ns):
            snd = gen.play(ctl)
            setattr(ns, 'buffer-%s-%s' % (generator_name, voice_id), snd)

        out = self.openAudioDevice()

        group = None
        if hasattr(gen, 'groups'):
            group = gen.groups[ voice_id % len(gen.groups) ]

        ctl['group'] = group

        iterations = 0
        while True:
            ctl['count'] = iterations
            iterations += 1

            if getattr(self.ns, 'reload') == True:
                reload(gen)

            if hasattr(self.ns, 'buffer-%s-%s' % (generator_name, voice_id)):
                snd = getattr(self.ns, 'buffer-%s-%s' % (generator_name, voice_id))
            else:
                # First play render
                snd = gen.play(ctl)

            if render_process is None or not render_process.is_alive():
                # async start render of next buffer
                render_process = mp.Process(name='render-%s-%s' % (generator_name, voice_id), target=render_again, args=(gen, ctl, generator_name, voice_id, self.ns))
                render_process.start()

            if self.ns.grid:
                div = grid_ctl.geti(self.divcc, low=0, high=4, default=0)
                div = self.divs[div]
                self.ticks[div].wait()

            out.write(snd)

            if getattr(self.ns, '%s-%s-loop' % (generator_name, voice_id)) == False:
                break

        try:
            delattr(self.ns, 'buffer-%s-%s' % (generator_name, voice_id))
        except AttributeError:
            dsp.log('Could not remove buffer-%s-%s' % (generator_name, voice_id))
コード例 #7
0
ファイル: midi.py プロジェクト: shnend/pippi
def register_midi_listener(device_name, ns):
    # check to see if this device has a listener already
    # start one up if not
    if not hasattr(ns, '%s-listener' % device_name):
        try:
            listener = mp.Process(target=device_scribe, args=(device_name, ns))
            listener.start()
            setattr(ns, '%s-listener' % device_name, listener.pid)
        except IOError:
            dsp.log('Could not start listener for unknown MIDI device: %s' %
                    device_name)
コード例 #8
0
    def _playPattern(self, pattern):
        def _sendMidi(note, velocity, length, device):
            velocity = int(round(velocity * 127))
            note = int(note)
            dsp.log(device)
            out = mido.open_output(device)
            msg = mido.Message('note_on', note=note, velocity=velocity)
            out.send(msg)

            dsp.delay(length)

            msg = mido.Message('note_off', note=note, velocity=0)
            out.send(msg)

        def _sendOsc():
            pass

        device = getattr(self.ns, 'selected-pattern-device',
                         self.default_midi_device)
        dsp.log(device)

        if self.validateGenerator(device):
            handler = self._playOneshot
        elif midi.validate_output_device_by_id(device):
            device = midi.validate_output_device_by_id(device)  # FIXME dummy
            dsp.log(device)
            handler = _sendMidi
        elif osc.validateAddress(device):
            handler = _sendOsc
        else:
            # Fallback to internal generator
            handler = self._playOneshot
            device = 'default'

        setattr(self.ns, 'pattern-%s' % pattern.id, True)
        setattr(self.ns, 'pattern-play-%s' % pattern.id, True)

        grid_ctl = self.loadGridCtl()
        while getattr(self.ns, 'pattern-%s' % pattern.id):
            # wait for tick
            if self.ns.grid:
                div = getattr(self.ns, 'pattern-div-%s' % pattern.id)
                div = self.divs[div]
                self.ticks[div].wait()

            # freq, 0-1, frames
            note, velocity, length = pattern.next()
            note = tune.ftom(note)

            if velocity > 0 and getattr(self.ns,
                                        'pattern-play-%s' % pattern.id):
                n = mp.Process(target=handler,
                               args=(note, velocity, length, device))
                n.start()
コード例 #9
0
ファイル: midi.py プロジェクト: bensteinberg/pippi
 def log_listener():
     try:
         device_names = mido.get_input_names()
         devices = [ mido.open_input(device_name) for device_name in device_names ]
         devices = mido.ports.MultiPort(devices)
         for msg in devices:
             if hasattr(ns, 'midi_log_active'):
                 dsp.log(msg)
             else:
                 continue
     except IOError:
         dsp.log('Could not open MIDI devices for logging %s' % str(device_names))
コード例 #10
0
        def _sendMidi(note, velocity, length, device):
            velocity = int(round(velocity * 127))
            note = int(note)
            dsp.log(device)
            out = mido.open_output(device)
            msg = mido.Message('note_on', note=note, velocity=velocity)
            out.send(msg)

            dsp.delay(length)

            msg = mido.Message('note_off', note=note, velocity=0)
            out.send(msg)
コード例 #11
0
ファイル: io.py プロジェクト: bensteinberg/pippi
        def _sendMidi(note, velocity, length, device):
            velocity = int(round(velocity * 127))
            note = int(note)
            dsp.log(device)
            out = mido.open_output(device)
            msg = mido.Message('note_on', note=note, velocity=velocity)
            out.send(msg)

            dsp.delay(length)

            msg = mido.Message('note_off', note=note, velocity=0)
            out.send(msg)
コード例 #12
0
ファイル: io.py プロジェクト: PaulBatchelor/pippi
    def stopGenerator(self, generator_name, kill=False):
        if generator_name in self.looping:
            for voice_id, process in self.looping[generator_name].iteritems():
                setattr(self.ns, '%s-%s-loop' % (generator_name, voice_id), False)

                if kill:
                    process.terminate()

            del self.looping[generator_name]
            return True
        
        dsp.log('Could not stop %s generators: none currently playing' % generator_name)
        return False
コード例 #13
0
ファイル: io.py プロジェクト: bensteinberg/pippi
    def _playPattern(self, pattern):
        def _sendMidi(note, velocity, length, device):
            velocity = int(round(velocity * 127))
            note = int(note)
            dsp.log(device)
            out = mido.open_output(device)
            msg = mido.Message('note_on', note=note, velocity=velocity)
            out.send(msg)

            dsp.delay(length)

            msg = mido.Message('note_off', note=note, velocity=0)
            out.send(msg)

        def _sendOsc():
            pass

        device = getattr(self.ns, 'selected-pattern-device', self.default_midi_device)
        dsp.log(device)

        if self.validateGenerator(device):
            handler = self._playOneshot
        elif midi.validate_output_device_by_id(device):
            device = midi.validate_output_device_by_id(device) # FIXME dummy
            dsp.log(device)
            handler = _sendMidi
        elif osc.validateAddress(device):
            handler = _sendOsc
        else:
            # Fallback to internal generator
            handler = self._playOneshot
            device = 'default'

        setattr(self.ns, 'pattern-%s' % pattern.id, True)
        setattr(self.ns, 'pattern-play-%s' % pattern.id, True)

        grid_ctl = self.loadGridCtl()
        while getattr(self.ns, 'pattern-%s' % pattern.id):
            # wait for tick
            if self.ns.grid:
                div = getattr(self.ns, 'pattern-div-%s' % pattern.id)
                div = self.divs[div]
                self.ticks[div].wait()

            # freq, 0-1, frames
            note, velocity, length = pattern.next()
            note = tune.ftom(note)

            if velocity > 0 and getattr(self.ns, 'pattern-play-%s' % pattern.id):
                n = mp.Process(target=handler, args=(note, velocity, length, device))
                n.start()
コード例 #14
0
ファイル: midi.py プロジェクト: shnend/pippi
    def wait(self):
        try:
            with mido.open_input(self.device_name) as incoming:
                for msg in incoming:
                    if self.notes is not None:
                        if msg.type == 'note_on' and msg.note in self.notes:
                            return (msg.note, msg.velocity)

                    if self.cc is not None:
                        if msg.type == 'control_change' and msg.control in self.cc and msg.value > 0:
                            return (msg.control, msg.value)
        except IOError:
            dsp.log('Could not arm MIDI device %s' % self.device_name)

        return (None, None)
コード例 #15
0
    def stopGenerator(self, generator_name, kill=False):
        if generator_name in self.looping:
            for voice_id, process in self.looping[generator_name].iteritems():
                setattr(self.ns, '%s-%s-loop' % (generator_name, voice_id),
                        False)

                if kill:
                    process.terminate()

            del self.looping[generator_name]
            return True

        dsp.log('Could not stop %s generators: none currently playing' %
                generator_name)
        return False
コード例 #16
0
    def wait(self):
        try:
            with mido.open_input(self.device_name) as incoming:
                for msg in incoming:
                    if self.notes is not None:
                        if msg.type == 'note_on' and msg.note in self.notes:
                            return (msg.note, msg.velocity)

                    if self.cc is not None:
                        if msg.type == 'control_change' and msg.control in self.cc and msg.value > 0:
                            return (msg.control, msg.value)
        except IOError:
            dsp.log('Could not arm MIDI device %s' % self.device_name)

        return (None, None)
コード例 #17
0
ファイル: midi.py プロジェクト: shnend/pippi
 def log_listener():
     try:
         device_names = mido.get_input_names()
         devices = [
             mido.open_input(device_name) for device_name in device_names
         ]
         devices = mido.ports.MultiPort(devices)
         for msg in devices:
             if hasattr(ns, 'midi_log_active'):
                 dsp.log(msg)
             else:
                 continue
     except IOError:
         dsp.log('Could not open MIDI devices for logging %s' %
                 str(device_names))
コード例 #18
0
ファイル: __init__.py プロジェクト: joshnroy/pippi
    def play(self, generator, ns, voice_id, voice_index, loop=True):
        sys.path.insert(0, os.getcwd())
        gen = __import__(generator)

        midi_devices = {}

        if hasattr(gen, 'midi'):
            for device, device_id in gen.midi.iteritems():
                dsp.log('\ndevice: %s device_id: %s' % (device, device_id))
                try:
                    midi_devices[device] = MidiManager(device_id, ns)
                    dsp.log('setting midi manager %s' % device_id)
                except:
                    dsp.log('Could not load midi device %s with id %s' % (device, device_id))

        param_manager = ParamManager(ns)

        if audio_engine == 'alsa':
            out = self.open_alsa_pcm(ns.device)
        elif audio_engine == 'portaudio':
            out = self.open_pyaudio_pcm(ns.device)
        else:
            print 'Playback is disabled.'
            return False

        try:
            os.nice(-2)
        except OSError:
            os.nice(0)

        group = None
        if hasattr(gen, 'groups'):
            group = gen.groups[ voice_index % len(gen.groups) ]

        meta = {
            'midi': midi_devices,
            'param': param_manager,
            'id': voice_id,
            'group': group
        }

        if not hasattr(ns, 'reload'):
            setattr(ns, 'reload', False)

        while getattr(ns, '%s-%s-loop' % (generator, voice_id)) == True:
            if getattr(ns, 'reload') == True:
                reload(gen)

            snd = gen.play(meta)
            snd = dsp.split(snd, 500)
            for s in snd:
                try:
                    out.write(s)
                except AttributeError:
                    dsp.log('Could not write to audio device')
                    return False

        return True
コード例 #19
0
ファイル: midi.py プロジェクト: bensteinberg/pippi
def device_scribe(device_name, ns):
    try:
        with mido.open_input(device_name) as incoming:
            for msg in incoming:
                msg_id = None
                value = None
                if hasattr(msg, 'control'):
                    msg_id = msg.control
                    value = msg.value

                if hasattr(msg, 'note'):
                    msg_id = msg.note
                    value = msg.velocity
                    
                setattr(ns, '%s-%s-%s' % (device_name, msg.type, msg_id), value)

        delattr(ns, '%s-listener' % device_name)
    except IOError:
        dsp.log('Could not open MIDI device %s' % device_name)
コード例 #20
0
ファイル: midi.py プロジェクト: shnend/pippi
def device_scribe(device_name, ns):
    try:
        with mido.open_input(device_name) as incoming:
            for msg in incoming:
                msg_id = None
                value = None
                if hasattr(msg, 'control'):
                    msg_id = msg.control
                    value = msg.value

                if hasattr(msg, 'note'):
                    msg_id = msg.note
                    value = msg.velocity

                setattr(ns, '%s-%s-%s' % (device_name, msg.type, msg_id),
                        value)

        delattr(ns, '%s-listener' % device_name)
    except IOError:
        dsp.log('Could not open MIDI device %s' % device_name)
コード例 #21
0
ファイル: io.py プロジェクト: PaulBatchelor/pippi
    def findGenerators(self):
        generators = []

        try:
            gens = glob.glob("*.py")
            for filename in gens:
                # Get base filename and strip .py extension
                filename = os.path.basename(filename)[:-3]
                generators += [ filename ]

            if len(generators) > 0:
                return generators

            dsp.log('Discovered %s available generator scripts' % len(generators))

        except OSError:
            pass

        dsp.log('No generators found')

        return False
コード例 #22
0
    def findGenerators(self):
        generators = []

        try:
            gens = glob.glob("*.py")
            for filename in gens:
                # Get base filename and strip .py extension
                filename = os.path.basename(filename)[:-3]
                generators += [filename]

            if len(generators) > 0:
                return generators

            dsp.log('Discovered %s available generator scripts' %
                    len(generators))

        except OSError:
            pass

        dsp.log('No generators found')

        return generators
コード例 #23
0
    def play(self, generator, ns, voice_id, voice_index, loop=True):
        sys.path.insert(0, os.getcwd())
        gen = __import__(generator)

        midi_devices = {}

        if hasattr(gen, 'midi'):
            for device, device_id in gen.midi.iteritems():
                dsp.log('\ndevice: %s device_id: %s' % (device, device_id))

                try:
                    pygame.midi.init()
                    device_info = pygame.midi.get_device_info(device_id)
                    device_type = 'input' if device_info[2] else 'output'
                    pygame.midi.quit()
                except:
                    dsp.log('could not read device %s' % device_id)
                    device_type = 'output'

                try:
                    mappings = None
                    if hasattr(gen, 'mappings'):
                        if device in gen.mappings:
                            mappings = gen.mappings[device]

                    midi_devices[device] = MidiManager(device_id, ns,
                                                       device_type, mappings)
                    dsp.log('setting midi manager %s' % device_id)
                except:
                    dsp.log('Could not load midi device %s with id %s' %
                            (device, device_id))

        param_manager = ParamManager(ns)

        if audio_engine == 'alsa':
            out = self.open_alsa_pcm(ns.device)
        elif audio_engine == 'portaudio':
            out = self.open_pyaudio_pcm(ns.device)
        else:
            print 'Playback is disabled.'
            return False

        try:
            os.nice(-2)
        except OSError:
            os.nice(0)

        group = None
        if hasattr(gen, 'groups'):
            group = gen.groups[voice_index % len(gen.groups)]

        if hasattr(gen, 'sbank'):
            sbank = {}
            for snd in gen.sbank:
                sbank[snd[0]] = dsp.read(snd[1]).data
        else:
            sbank = None

        meta = {
            'midi': midi_devices,
            'param': param_manager,
            'id': voice_id,
            'group': group,
            'sbank': sbank
        }

        if not hasattr(ns, 'reload'):
            setattr(ns, 'reload', False)

        render_process = None

        def render_again(gen, meta, voice_id, ns):
            snd = gen.play(meta)
            setattr(ns, 'buffer-%s' % voice_id, snd)

        iterations = 0
        while getattr(ns, '%s-%s-loop' % (generator, voice_id)) == True:
            meta['iterations'] = iterations
            iterations += 1

            dsp.log('playing %s, id %s, iter %s' %
                    (generator, voice_id, iterations))

            if getattr(ns, 'reload') == True and not hasattr(gen, 'automate'):
                reload(gen)

            # automate will always override play
            if hasattr(gen, 'play') and not hasattr(gen, 'automate'):
                if hasattr(ns, 'buffer-%s' % voice_id):
                    snd = getattr(ns, 'buffer-%s' % voice_id)
                else:
                    # First play render
                    snd = gen.play(meta)

                if render_process is None or not render_process.is_alive():
                    # async start render of next buffer
                    render_process = mp.Process(name='render-%s' % voice_id,
                                                target=render_again,
                                                args=(gen, meta, voice_id, ns))
                    render_process.start()

                snd = dsp.split(snd, 500)

                # if grid is on, wait for a tick to start playback
                if ns.grid:
                    self.tick.wait()

                for s in snd:
                    try:
                        out.write(s)
                    except AttributeError:
                        dsp.log('Could not write to audio device')
                        return False

            if hasattr(gen, 'automate'):
                gen.automate(meta)

                if hasattr(gen, 'loop_time'):
                    time.sleep(gen.loop_time)

        delattr(ns, 'buffer-%s' % voice_id)

        return True
コード例 #24
0
    def _playGenerator(self, generator_name, gen, voice_id, ctl, grid_ctl):
        try:
            os.nice(-2)
        except OSError:
            os.nice(0)

        if not hasattr(self.ns, 'reload'):
            setattr(self.ns, 'reload', False)

        render_process = None

        def render_again(gen, ctl, generator_name, voice_id, ns):
            snd = gen.play(ctl)
            setattr(ns, 'buffer-%s-%s' % (generator_name, voice_id), snd)

        out = self.openAudioDevice()

        group = None
        if hasattr(gen, 'groups'):
            group = gen.groups[voice_id % len(gen.groups)]

        ctl['group'] = group

        iterations = 0
        while True:
            ctl['count'] = iterations
            iterations += 1

            if getattr(self.ns, 'reload') == True:
                reload(gen)

            if hasattr(self.ns, 'buffer-%s-%s' % (generator_name, voice_id)):
                snd = getattr(self.ns,
                              'buffer-%s-%s' % (generator_name, voice_id))
            else:
                # First play render
                snd = gen.play(ctl)

            if render_process is None or not render_process.is_alive():
                # async start render of next buffer
                render_process = mp.Process(
                    name='render-%s-%s' % (generator_name, voice_id),
                    target=render_again,
                    args=(gen, ctl, generator_name, voice_id, self.ns))
                render_process.start()

            if self.ns.grid:
                div = grid_ctl.geti(self.divcc, low=0, high=4, default=0)
                div = self.divs[div]
                self.ticks[div].wait()

            out.write(snd)

            if getattr(self.ns,
                       '%s-%s-loop' % (generator_name, voice_id)) == False:
                break

        try:
            delattr(self.ns, 'buffer-%s-%s' % (generator_name, voice_id))
        except AttributeError:
            dsp.log('Could not remove buffer-%s-%s' %
                    (generator_name, voice_id))
コード例 #25
0
ファイル: __init__.py プロジェクト: celesteh/pippi
    def play(self, generator, ns, voice_id, voice_index, loop=True):
        sys.path.insert(0, os.getcwd())
        gen = __import__(generator)

        midi_devices = {}

        if hasattr(gen, 'midi'):
            for device, device_id in gen.midi.iteritems():
                dsp.log('\ndevice: %s device_id: %s' % (device, device_id))

                try:
                    pygame.midi.init()
                    device_info = pygame.midi.get_device_info(device_id)
                    device_type = 'input' if device_info[2] else 'output'
                    pygame.midi.quit()
                except:
                    dsp.log('could not read device %s' % device_id)
                    device_type = 'output'

                try:
                    mappings = None
                    if hasattr(gen, 'mappings'):
                        if device in gen.mappings:
                            mappings = gen.mappings[device]

                    midi_devices[device] = MidiManager(device_id, ns, device_type, mappings)
                    dsp.log('setting midi manager %s' % device_id)
                except:
                    dsp.log('Could not load midi device %s with id %s' % (device, device_id))

        param_manager = ParamManager(ns)

        if audio_engine == 'alsa':
            out = self.open_alsa_pcm(ns.device)
        elif audio_engine == 'portaudio':
            out = self.open_pyaudio_pcm(ns.device)
        else:
            print 'Playback is disabled.'
            return False

        try:
            os.nice(-2)
        except OSError:
            os.nice(0)

        group = None
        if hasattr(gen, 'groups'):
            group = gen.groups[ voice_index % len(gen.groups) ]

        if hasattr(gen, 'sbank'):
            sbank = {}
            for snd in gen.sbank:
                sbank[snd[0]] = dsp.read(snd[1]).data
        else:
            sbank = None

        meta = {
            'midi': midi_devices,
            'param': param_manager,
            'id': voice_id,
            'group': group, 
            'sbank': sbank
        }

        if not hasattr(ns, 'reload'):
            setattr(ns, 'reload', False)

        render_process = None

        def render_again(gen, meta, voice_id, ns):
            snd = gen.play(meta)
            setattr(ns, 'buffer-%s' % voice_id, snd)

        iterations = 0
        while getattr(ns, '%s-%s-loop' % (generator, voice_id)) == True:
            meta['iterations'] = iterations
            iterations += 1

            dsp.log('playing %s, id %s, iter %s' % (generator, voice_id, iterations))

            if getattr(ns, 'reload') == True and not hasattr(gen, 'automate'):
                reload(gen)

            # automate will always override play
            if hasattr(gen, 'play') and not hasattr(gen, 'automate'):
                if hasattr(ns, 'buffer-%s' % voice_id):
                    snd = getattr(ns, 'buffer-%s' % voice_id)
                else:
                    # First play render
                    snd = gen.play(meta)

                if render_process is None or not render_process.is_alive():
                    # async start render of next buffer
                    render_process = mp.Process(name='render-%s' % voice_id, target=render_again, args=(gen, meta, voice_id, ns))
                    render_process.start()

                snd = dsp.split(snd, 500)

                # if grid is on, wait for a tick to start playback
                if ns.grid:
                    self.tick.wait()

                for s in snd:
                    try:
                        out.write(s)
                    except AttributeError:
                        dsp.log('Could not write to audio device')
                        return False

            if hasattr(gen, 'automate'):
                gen.automate(meta)

                if hasattr(gen, 'loop_time'):
                    time.sleep(gen.loop_time)

        delattr(ns, 'buffer-%s' % voice_id)

        return True