Пример #1
0
 def test_get_rms_dB_all(self):
     dB = self._leveller.get_rms_dB()
     self.assertEquals(len(dB), 1)
     time, value_dB = dB[0]
     self.assertEquals(time, level.SECOND)
     value = common.decibelToRaw(value_dB)
     # ms is ((1/2) ** 2 + (1/4) ** 2) / 2 = 5/32
     # to avoid float rounding errors, compare against 5/32 by multiplying
     # and inting
     self.assertEquals(int(value ** 2 * 32), 5)
Пример #2
0
    def do(self, args):
        import pygst
        pygst.require('0.10')
        import gobject
        gobject.threads_init()
        import gst

        from dadgst.task import level

        runner = task.SyncRunner()

        for path in filterFiles(self, args):

            t = level.LevellerTask(path)
            runner.run(t)

            if t.done:
                self.stdout.write('Successfully analyzed file %s.\n' %
                    path.encode('utf-8'))
                mixes = t.get_track_mixes()
                self.stdout.write('%d fragment(s)\n' % len(mixes))

                for i, m in enumerate(mixes):
                    self.stdout.write('- fragment %d: %s - %s\n' % (
                        i, gst.TIME_ARGS(m.start), gst.TIME_ARGS(m.end)))
                    self.stdout.write('  - peak              %02.3f dB (%03.3f %%)\n' % (
                        m.peak, common.decibelToRaw(m.peak) * 100.0))
                    self.stdout.write('  - rms               %r dB\n' % m.rms)
                    self.stdout.write('  - peak rms          %r dB\n' % m.rmsPeak)
                    self.stdout.write('  - 95 percentile rms %r dB\n' % m.rmsPercentile)
                    self.stdout.write('  - weighted rms      %r dB\n' % m.rmsWeighted)
                    start = m.attack.get(m.rmsPeak - 9)
                    end = m.decay.get(m.rmsPeak - 9)
                    self.stdout.write('  - weighted from %s to %s\n' % (
                        gst.TIME_ARGS(start), gst.TIME_ARGS(end)))
            else:
                self.stderr.write('Could not level %s\n' %
                    path.encode('utf-8'))

            t.clean()
Пример #3
0
    def _scheduled_cb(self, scheduler, scheduled):
        self.info('jukebox: scheduled %r' % scheduled)
        self._scheduling = False
        self.debug('scheduled %r' % scheduled)

        audiosource, gnlsource = self._makeGnlSource(scheduled.path,
            scheduled.path, volume=common.decibelToRaw(scheduled.volume))
        self._setGnlSourceProps(gnlsource, scheduled.start,
            scheduled.mediaStart, scheduled.duration)
        self.debug('adding %r' % gnlsource)
        self._composition.add(gnlsource)
        self._playing.append((scheduled, audiosource, gnlsource))

        # add a buffer probe so we can signal started
        pad = audiosource.get_pad('src')
        self._probes[pad] = pad.add_buffer_probe(self._buffer_probe)


        # if this track gets scheduled before lastend, we need an adder
        if scheduled.start < self._lastend:
            start = scheduled.start
            duration = self._lastend - scheduled.start

            self.debug('schedule adder at %r for %r' % (
                gst.TIME_ARGS(start), gst.TIME_ARGS(duration)))
            operation = gst.element_factory_make("gnloperation")
            adder = gst.element_factory_make("adder")
            operation.add(adder)
            #operation.props.sinks = 2
            operation.props.sinks = 2
            operation.props.start = start
            operation.props.duration = duration
            operation.props.priority = 0
            self._composition.add(operation)

        # update lastend
        self._lastend = scheduled.start + scheduled.duration
        self.debug('jukebox: lastend updated to %r' % 
            gst.TIME_ARGS(self._lastend))
Пример #4
0
    def setup(self):
        EXTRA = 5 * gst.SECOND # how much of tracks to play outside of mix

        # set up the mix
        track1 = self._tracks[self._path1][0]
        if not track1.name: track1.name = self._path1
        track2 = self._tracks[self._path2][0]
        if not track2.name: track2.name = self._path2

        mix = mixing.Mix(track1, track2)

        print 'Track 1: %s' % self._path1
        print '- from %s to %s' % (
            gst.TIME_ARGS(track1.start), gst.TIME_ARGS(track1.end))
        print '- leadout at %s for %s' % (
            gst.TIME_ARGS(track1.end - mix.leadout), gst.TIME_ARGS(mix.leadout))

        print 'Track 2: %s' % self._path2
        print '- from %s to %s' % (
            gst.TIME_ARGS(track2.start), gst.TIME_ARGS(track2.end))
        print '- leadin until %s for %s' % (
            gst.TIME_ARGS(track2.start + mix.leadin), gst.TIME_ARGS(mix.leadin))

        print 'mix start:    %s' % gst.TIME_ARGS(EXTRA)
        print 'mix duration: %s' % gst.TIME_ARGS(mix.duration)

        raw = common.decibelToRaw(mix.volume1)
        print 'Adjusting track 1 by %.3f dB' % mix.volume1
        asource1, source1 = self._makeGnlSource(
            'source1', self._path1, volume=raw)

        source1.props.start = 0 * gst.SECOND
        source1.props.duration = EXTRA + mix.duration
        source1.props.media_start = track1.end - (EXTRA + mix.duration)
        source1.props.media_duration = EXTRA + mix.duration
        source1.props.priority = 1

        self._composition.add(source1)

        raw = common.decibelToRaw(mix.volume2)
        print 'Adjusting track 2 by %.3f dB' % mix.volume2
        asource2, source2 = self._makeGnlSource(
            'source2', self._path2, volume=raw)

        source2.props.start = EXTRA
        source2.props.duration = EXTRA + mix.duration
        source2.props.media_start = track2.start
        source2.props.media_duration = EXTRA + mix.duration
        source2.props.priority = 2

        self._composition.add(source2)

        self._source1 = source1
        self._asource1 = asource1
        self._source2 = source2
        self._asource2 = asource2

        # add the mixer effect
        operation = gst.element_factory_make("gnloperation")
        adder = gst.element_factory_make("adder")
        operation.add(adder)
        operation.props.sinks = 2
        operation.props.start = EXTRA
        operation.props.duration = mix.duration
        operation.props.priority = 0

        self._composition.add(operation)

        # schedule a stop
        # FIXME: this should be done against the pipeline's clock instead;
        # imagine using a filesink
        gobject.timeout_add(((2 * EXTRA) + mix.duration) / 1000000, self.stop)
        source2.props.duration = EXTRA + mix.duration
Пример #5
0
        # message, if set, holds a ref to leveller, so we delete it here
        # to assure cleanup of leveller when we del it
        del message
        utils.gc_collect('deleted message')

        l.stop()

        if success:
            print 'Successfully analyzed file %r' % path
            trackMixes = l.get_track_mixes()
            print '%d slice(s) found.' % len(trackMixes)
            for i, m in enumerate(trackMixes):
                print '- slice %d: %s - %s' % (
                    i, gst.TIME_ARGS(m.start), gst.TIME_ARGS(m.end))
                print '  - peak              %02.3f dB (%03.3f %%)' % (
                    m.peak, common.decibelToRaw(m.peak) * 100.0)
                print '  - rms               %r dB' % m.rms
                print '  - peak rms          %r dB' % m.rmsPeak
                print '  - 95 percentile rms %r dB' % m.rmsPercentile
                print '  - weighted rms      %r dB' % m.rmsWeighted
                start = m.attack.get(m.rmsPeak - 9)
                end = m.decay.get(m.rmsPeak - 9)
                print '  - weighted from %s to %s' % (
                    gst.TIME_ARGS(start), gst.TIME_ARGS(end))

            tracks[path] = trackMixes
            handle = open(args[0], 'wb')
            pickle.dump(tracks, handle, 2)
            handle.close()
            print
Пример #6
0
    def slice(self, delta=5 * SECOND, threshold=None):
        """
        Find all slices of the track that have their value over the given
        threshold for at least the given delta.

        If start or end point of a slice is within delta of beginning or end
        of the track, then it gets reset to beginning or end of track.

        @param threshold: the threshold for slice detection; should be in
                          the same scale as the object.  If not given, the
                          equivalent of -90 dB is used.

        @rtype:   list of L{Level}
        @returns: list of slices with their start and end point.
        """
        ret = []

        if threshold is None:
            threshold = -90
            if self._scale == SCALE_RAW:
                threshold = common.decibelToRaw(threshold) 

        previous = 0L # end of previous section
        length = 0L # length of current section
        start = 0L # start of slice
        end = 0L # end of slice

        # implement a state machine with 4 states
        BELOW, CLIMBING, ABOVE, FALLING = range(4)

        state = BELOW

        for endtime, value in self:
            length = endtime - previous
            previous = endtime
            
            if state is BELOW:
                if value < threshold:
                    continue

                self._log('at %r value %r is above threshold %r' % (
                    endtime, value, threshold))
                state = CLIMBING
                
                # start of interval is start of previous block ...
                start = endtime - length

                # ... but if it's close to 0, then pick 0 instead
                if start < delta:
                    self._log('resetting start to 0')
                    start = 0L
                self._log('set start to %r' % start)
            elif state is CLIMBING:
                if value < threshold:
                    # fell again, reset
                    self._log('at %r value %r is below threshold %r' % (
                        endtime, value, threshold))
                    self._log('fell again')
                    state = BELOW
                    continue

                if endtime - start > delta:
                    # long enough, so approve
                    state = ABOVE
            elif state is ABOVE:
                if value > threshold:
                    continue

                self._log('at %r value %r is below threshold %r' % (
                    endtime, value, threshold))
                state = FALLING

                # end time of slice is end time of this section ...
                end = endtime
                # ... but if we're close to the end, then pick the end
                last = self.end()
                if last - end < delta:
                    self._log('resetting end to last %r' % last)
                    end = last
 
            elif state is FALLING:
                if value > threshold:
                    # rose again, reset
                    state = ABOVE
                    continue

                if endtime - end > delta:
                    # long enough, so approve
                    state = BELOW
                    self._log('appending section from %r to %r' % (start, end))
                    ret.append(self.trim(start, end))

        # make sure we finish even if there's not enough data left
        if state in (ABOVE, FALLING):
            self._log('appending section from %r to %r' % (start, endtime))
            ret.append(self.trim(start, endtime))

        return ret