From ae41072c7a6fd4fc51c4933fb7d3fca3a0ee8863 Mon Sep 17 00:00:00 2001 From: yomguy Date: Fri, 25 Jun 2010 17:12:38 +0000 Subject: [PATCH] add vorbis encoder, more tests, more BUGS ! --- timeside/encoder/__init__.py | 2 +- timeside/encoder/ogg.py | 163 ++++++++++++++---------------- timeside/encoder/wav.py | 30 +----- timeside/tests/api/test_vorbis.py | 14 +++ timeside/tests/api/test_wav.py | 15 +++ 5 files changed, 110 insertions(+), 114 deletions(-) create mode 100644 timeside/tests/api/test_vorbis.py create mode 100644 timeside/tests/api/test_wav.py diff --git a/timeside/encoder/__init__.py b/timeside/encoder/__init__.py index 8248164..67ee689 100644 --- a/timeside/encoder/__init__.py +++ b/timeside/encoder/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from core import * -#from timeside.encoder.ogg import * +from ogg import * from wav import * #from timeside.encoder.mp3 import * #from timeside.encoder.flac import * diff --git a/timeside/encoder/ogg.py b/timeside/encoder/ogg.py index 566c529..fb89fd3 100644 --- a/timeside/encoder/ogg.py +++ b/timeside/encoder/ogg.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2007-2009 Guillaume Pellerin +# Copyright (c) 2010 Paul Brossier +# Copyright (c) 2010 Guillaume Pellerin # This file is part of TimeSide. @@ -17,100 +18,88 @@ # You should have received a copy of the GNU General Public License # along with TimeSide. If not, see . -# Author: Guillaume Pellerin -import os -import string -import subprocess - -from timeside.encoder.core import * +from timeside.core import Processor, implements, interfacedoc from timeside.api import IEncoder +from numpy import array, frombuffer, getbuffer, float32 + +import pygst +pygst.require('0.10') +import gst +import gobject +gobject.threads_init () -class OggVorbisEncoder(EncoderCore): - """Defines methods to encode to OGG Vorbis""" +class VorbisEncoder(Processor): + """ gstreamer-based vorbis encoder """ implements(IEncoder) - def __init__(self): - self.bitrate_default = '192' - self.dub2args_dict = {'creator': 'artist', - 'relation': 'album' - } + def __init__(self, output): + self.file = None + if isinstance(output, basestring): + self.filename = output + else: + raise Exception("Streaming not supported") + + @interfacedoc + def setup(self, channels=None, samplerate=None, nframes=None): + super(VorbisEncoder, self).setup(channels, samplerate, nframes) + # TODO open file for writing + # the output data format we want + pipeline = gst.parse_launch(''' appsrc name=src + ! audioconvert + ! vorbisenc + ! oggmux + ! filesink location=%s ''' % self.filename) + # store a pointer to appsink in our encoder object + self.src = pipeline.get_by_name('src') + srccaps = gst.Caps("""audio/x-raw-float, + endianness=(int)1234, + channels=(int)%s, + width=(int)32, + rate=(int)%d""" % (int(channels), int(samplerate))) + self.src.set_property("caps", srccaps) + + # start pipeline + pipeline.set_state(gst.STATE_PLAYING) + self.pipeline = pipeline @staticmethod + @interfacedoc def id(): - return "oggenc" - - def format(self): - return 'OggVorbis' - - def file_extension(self): - return 'ogg' - - def mime_type(self): - return 'application/ogg' - - def description(self): - return """ - Vorbis is a free software / open source project headed by the Xiph.Org - Foundation (formerly Xiphophorus company). The project produces an audio - format specification and software implementation (codec) for lossy audio - compression. Vorbis is most commonly used in conjunction with the Ogg - container format and it is therefore often referred to as Ogg Vorbis. - (source Wikipedia) - """ - - def get_file_info(self, file): - try: - file_out1, file_out2 = os.popen4('ogginfo "' + file + '"') - info = [] - for line in file_out2.readlines(): - info.append(clean_word(line[:-1])) - self.info = info - return self.info - except: - raise IOError('EncoderError: file does not exist.') - - def write_tags(self, file): - from mutagen.oggvorbis import OggVorbis - media = OggVorbis(file) - for tag in self.metadata.keys(): - media[tag] = str(self.metadata[tag]) - media.save() - - def get_args(self): - """Get process options and return arguments for the encoder""" - args = [] - if not self.options is None: - if not ('verbose' in self.options and self.options['verbose'] != '0'): - args.append('-Q ') - if 'ogg_bitrate' in self.options: - args.append('-b '+self.options['ogg_bitrate']) - elif 'ogg_quality' in self.options: - args.append('-q '+self.options['ogg_quality']) - else: - args.append('-b '+self.bitrate_default) - else: - args.append('-Q -b '+self.bitrate_default) - - for tag in self.metadata: - name = tag[0] - value = clean_word(tag[1]) - args.append('-c %s="%s"' % (name, value)) - if name in self.dub2args_dict.keys(): - arg = self.dub2args_dict[name] - args.append('-c %s="%s"' % (arg, value)) - return args - - def process(self, source, metadata, options=None): - self.metadata = metadata - self.options = options - args = self.get_args() - args = ' '.join(args) - command = 'oggenc %s -' % args - - stream = self.core_process(command, source) - for __chunk in stream: - yield __chunk + return "gst_vorbis_enc" + + @staticmethod + @interfacedoc + def description(): + return "Vorbis GStreamer based encoder" + + @staticmethod + @interfacedoc + def file_extension(): + return "ogg" + + @staticmethod + @interfacedoc + def mime_type(): + return "audio/ogg" + + @interfacedoc + def set_metadata(self, metadata): + #TODO + pass + + @interfacedoc + def process(self, frames, eod=False): + buf = self.numpy_array_to_gst_buffer(frames) + self.src.emit('push-buffer', buf) + if eod: self.src.emit('end-of-stream') + return frames, eod + + def numpy_array_to_gst_buffer(self, frames): + """ gstreamer buffer to numpy array conversion """ + buf = gst.Buffer(getbuffer(frames)) + return buf + diff --git a/timeside/encoder/wav.py b/timeside/encoder/wav.py index d790aaa..786564a 100644 --- a/timeside/encoder/wav.py +++ b/timeside/encoder/wav.py @@ -1,29 +1,7 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2007-2009 Guillaume Pellerin - -# This file is part of TimeSide. - -# TimeSide 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. - -# TimeSide 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 TimeSide. If not, see . - -# Author: Guillaume Pellerin - -# -*- coding: utf-8 -*- -# -# Copyright (C) 2007-2009 Parisson -# Copyright (c) 2007 Olivier Guilyardi -# Copyright (c) 2007-2009 Guillaume Pellerin +# Copyright (c) 2007-2010 Parisson +# Copyright (c) 2010 Paul Brossier # # This file is part of TimeSide. @@ -89,12 +67,12 @@ class WavEncoder(Processor): @staticmethod @interfacedoc def id(): - return "gstreamerenc" + return "gst_wav_enc" @staticmethod @interfacedoc def description(): - return "Gstreamer based encoder" + return "Wav GStreamer based encoder" @staticmethod @interfacedoc diff --git a/timeside/tests/api/test_vorbis.py b/timeside/tests/api/test_vorbis.py new file mode 100644 index 0000000..ec2a568 --- /dev/null +++ b/timeside/tests/api/test_vorbis.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +from timeside.decoder import * +from timeside.analyzer import * +from timeside.encoder import * + +import os.path +source = os.path.join(os.path.dirname(__file__), "../samples/sweep.wav") +dest = os.path.join(os.path.dirname(__file__), "../results/sweep_wav.ogg") + +decoder = FileDecoder(source) +encoder = VorbisEncoder(dest) + +(decoder | encoder).run() diff --git a/timeside/tests/api/test_wav.py b/timeside/tests/api/test_wav.py new file mode 100644 index 0000000..077a01e --- /dev/null +++ b/timeside/tests/api/test_wav.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from timeside.decoder import * +from timeside.analyzer import * +from timeside.encoder import * + +import os.path +source = os.path.join(os.path.dirname(__file__), "../samples/sweep.wav") +dest = os.path.join(os.path.dirname(__file__), "../results/sweep_wav.wav") + +decoder = FileDecoder(source) +encoder = WavEncoder(dest) + +(decoder | encoder).run() + -- 2.39.5