#!/usr/bin/python # -*- mode: python; coding: utf-8 -*- # Copyright © 2009 Jeffrey C. Ollie # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # Based upon code originally posted by Jono Bacon to his blog: # http://www.jonobacon.org/2006/12/27/using-gnonlin-with-gstreamer-and-python/ import sys import optparse import pygst pygst.require('0.10') import gst import gobject # Cisco ringtones can be at most 16080 bytes long max_ringtone_length_bytes = 16080 ringtone_sample_rate = 8000.0 ringtone_bytes_per_sample = 1 max_ringtone_duration = max_ringtone_length_bytes / (ringtone_bytes_per_sample * ringtone_sample_rate) class Main: def __init__(self, mainloop, source, destination, start, duration): if duration > max_ringtone_duration: sys.stderr.write('Cisco ring tones may be at most %4.2f seconds long, reducing duration.\n' % max_ringtone_duration) duration = max_ringtone_duration self.mainloop = mainloop self.pipeline = gst.Pipeline() bus = self.pipeline.get_bus() bus.add_signal_watch() bus.connect('message', self.handle_message) self.gnlcomposition = gst.element_factory_make('gnlcomposition') self.gnlcomposition.connect('pad-added', self.on_pad_added) self.pipeline.add(self.gnlcomposition) self.gnlfilesource = gst.element_factory_make('gnlfilesource') self.gnlfilesource.set_property('caps', gst.caps_from_string('audio/x-raw-int; audio/x-raw-float')) self.gnlfilesource.set_property('location', source) self.gnlfilesource.set_property('start', 0 * gst.SECOND) self.gnlfilesource.set_property('duration', int(duration * gst.SECOND)) self.gnlfilesource.set_property('media-start', int(start * gst.SECOND)) self.gnlfilesource.set_property('media-duration', int(duration * gst.SECOND)) self.gnlcomposition.add(self.gnlfilesource) self.audioconvert = gst.element_factory_make('audioconvert') self.pipeline.add(self.audioconvert) self.audioresample = gst.element_factory_make('audioresample') self.pipeline.add(self.audioresample) self.audioconvert.link(self.audioresample) self.mulawenc = gst.element_factory_make('mulawenc') self.pipeline.add(self.mulawenc) self.audioresample.link(self.mulawenc) self.capsfilter = gst.element_factory_make('capsfilter') self.capsfilter.set_property('caps', gst.caps_from_string('audio/x-mulaw,rate=8000,channels=1')) self.pipeline.add(self.capsfilter) self.mulawenc.link(self.capsfilter) self.filesink = gst.element_factory_make('filesink') self.filesink.set_property('location', destination) self.pipeline.add(self.filesink) self.capsfilter.link(self.filesink) self.pipeline.set_state(gst.STATE_PLAYING) def on_pad_added(self, element, pad): if element == self.gnlcomposition: pad.link(self.audioconvert.get_compatible_pad(pad, pad.get_caps())) def handle_message(self, bus, message): if message.type == gst.MESSAGE_EOS: self.pipeline.set_state(gst.STATE_NULL) self.mainloop.quit() elif message.type == gst.MESSAGE_ERROR: error, debug = message.parse_error() sys.stderr.write('Error %s: %s\n' % (error, debug)) self.pipeline.set_state(gst.STATE_NULL) self.mainloop.quit() parser = optparse.OptionParser(version='0.1') parser.add_option('-s', '--start', action = 'store', type = 'float', dest = 'start', default = 0.0, help = 'Position in the audio file to start extracting ring tone from.', metavar = 'SECONDS') parser.add_option('-d', '--duration', action = 'store', type = 'float', dest = 'duration', default = max_ringtone_duration, help = 'Duration of ring tone to extract from the audio file.', metavar = 'SECONDS') options, args = parser.parse_args() if len(args) != 2: sys.stderr.write('Must specify a source and a destination!\n') sys.exit(1) gobject.threads_init() mainloop = gobject.MainLoop() start=Main(mainloop, args[0], args[1], options.start, options.duration) mainloop.run()