]> git.parisson.com Git - timeside.git/commitdiff
make mp3_stream file writing conditional to the output arg, cleanup
authoryomguy <yomguy@parisson.com>
Wed, 9 Feb 2011 12:27:56 +0000 (12:27 +0000)
committeryomguy <yomguy@parisson.com>
Wed, 9 Feb 2011 12:27:56 +0000 (12:27 +0000)
timeside/analyzer/__init__.py
timeside/encoder/__init__.py
timeside/encoder/mp3.py
timeside/encoder/mp3_stream.py [new file with mode: 0644]
timeside/encoder/ogg.py
timeside/encoder/wav.py
timeside/grapher/core.py
timeside/grapher/spectrogram.py
timeside/grapher/waveform.py
timeside/grapher/waveform_awdio.py
timeside/grapher/waveform_joydiv.py

index 19db5e368bb28b9cec344f1bc82430df61526966..1cc1d5cd9bd123d89471c00f940d45df94c5bbb1 100644 (file)
@@ -1,4 +1,4 @@
-    # -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
 
 from core import *
 
index 1332cecd2ea240cdbeae390c6d4e3fa179fdfa03..28d1c4d96f4a23b2bb443d756795994e7531d812 100644 (file)
@@ -4,5 +4,7 @@ from core import *
 from ogg import *
 from wav import *
 from mp3 import *
+from mp3_stream import *
 from m4a import *
+
 #from timeside.encoder.flac import *
index 16251618e31d42acd70070a926135c216c93b5a8..9272c1c994a21129eb76e19ec3232b845ebb5937 100644 (file)
@@ -29,7 +29,7 @@ import pygst
 pygst.require('0.10')
 import gst
 import gobject
-gobject.threads_init ()
+gobject.threads_init()
 
 
 class Mp3Encoder(Processor):
@@ -101,7 +101,7 @@ class Mp3Encoder(Processor):
         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))
diff --git a/timeside/encoder/mp3_stream.py b/timeside/encoder/mp3_stream.py
new file mode 100644 (file)
index 0000000..e343520
--- /dev/null
@@ -0,0 +1,120 @@
+    # -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+
+# 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 <http://www.gnu.org/licenses/>.
+
+# Authors: Guillaume Pellerin <yomguy@parisson.com>
+#          Paul Brossier <piem@piem.org>
+
+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 Mp3EncoderStream(Processor):
+    """ gstreamer-based streaming mp3 encoder with an appsink tee"""
+    implements(IEncoder)
+
+    def __init__(self, output=None):
+#        self.file = None
+        self.filename = output
+        
+    @interfacedoc
+    def setup(self, channels=None, samplerate=None, nframes=None):
+        super(Mp3EncoderStream, self).setup(channels, samplerate, nframes)
+        #TODO: open file for writing
+        # the output data format we want
+        
+        pipe = '''appsrc name=src ! audioconvert 
+                  ! lame name=enc vbr=0 bitrate=256 ! id3v2mux 
+                  '''
+        if self.filename:
+            pipe += '''
+            ! queue2 name=q0 ! tee name=tee
+            tee. ! queue name=q1 ! appsink name=app
+            tee. ! queue name=q2 ! filesink location=%s
+            ''' % self.filename
+        else:
+            pipe += '! appsink name=app'
+            
+        pipeline = gst.parse_launch(pipe)
+        # store a pointer to appsrc in our encoder object
+        self.src = pipeline.get_by_name('src')
+        # store a pointer to appsink in our encoder object
+        self.app = pipeline.get_by_name('app')
+        
+        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 "gst_mp3_enc_stream"
+
+    @staticmethod
+    @interfacedoc
+    def description():
+        return "MP3 GStreamer based encoder and streamer"
+
+    @staticmethod
+    @interfacedoc
+    def format():
+        return "MP3"
+
+    @staticmethod
+    @interfacedoc
+    def file_extension():
+        return "mp3"
+
+    @staticmethod
+    @interfacedoc
+    def mime_type():
+        return "audio/mpeg"
+
+    @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)
+        appbuffer = self.app.emit('pull-buffer')
+        if eod: self.src.emit('end-of-stream')
+        return appbuffer, eod
+        
+    def numpy_array_to_gst_buffer(self, frames):
+        """ gstreamer buffer to numpy array conversion """
+        buf = gst.Buffer(getbuffer(frames))
+        return buf
+
index c7ad5e3fbb55f42378908f153e1c5024e1ce87cc..39de8dd2acccf2e966936c7c4099ee46aac08c37 100644 (file)
@@ -27,7 +27,7 @@ import pygst
 pygst.require('0.10')
 import gst
 import gobject
-gobject.threads_init ()
+gobject.threads_init()
 
 
 class VorbisEncoder(Processor):
@@ -100,6 +100,7 @@ class VorbisEncoder(Processor):
         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 """
index 026d6b9f1f32233874d5fc403ef5be3b09c7f858..234763a409dd46fac49c07c7faa89cb81983009d 100644 (file)
@@ -28,7 +28,7 @@ import pygst
 pygst.require('0.10')
 import gst
 import gobject
-gobject.threads_init ()
+gobject.threads_init()
 
 
 class WavEncoder(Processor):
index 0f94be9b656bd8d07120c68c37e6aa0772d7b7df..e79ecb719f7e068ed8d3bc3b2fd91ddd25838e99 100644 (file)
@@ -255,10 +255,7 @@ class WaveformImage(object):
         self.image.save(filename)
 
     def release(self):
-        self.pixel = 0
-        self.image = 0
-        self.draw = 0
-        self.spectrum = 0
+        pass
 
 class WaveformImageJoyContour(WaveformImage):
 
@@ -370,6 +367,8 @@ class WaveformImageJoyContour(WaveformImage):
         #self.image = self.image.transpose(Image.FLIP_TOP_BOTTOM)
         self.image.save(filename)
         
+    def release(self):
+        pass
         
 class WaveformImageSimple(object):
     """ Builds a PIL image representing a waveform of the audio stream.
@@ -467,11 +466,7 @@ class WaveformImageSimple(object):
         self.image.save(filename)
     
     def release(self):
-        self.pixels_adapter.process = 0
-        self.pixel = 0
-        self.image = 0
-        self.draw = 0
-        self.spectrum = 0
+        pass
         
 class SpectrogramImage(object):
     """ Builds a PIL image representing a spectrogram of the audio stream (level vs. frequency vs. time).
@@ -547,7 +542,9 @@ class SpectrogramImage(object):
         self.image.putdata(self.pixels)
         self.image.transpose(Image.ROTATE_90).save(filename)
 
-
+    def release(self):
+        pass
+        
 class Noise(object):
     """A class that mimics audiolab.sndfile but generates noise instead of reading
     a wave file. Additionally it can be told to have a "broken" header and thus crashing
index 5d533311bb0485ef6b63e017e8fb5dcf3a09bad1..0d98a0d1b59da0a696386cfa767b163cb7afcf4d 100644 (file)
@@ -55,8 +55,6 @@ class Spectrogram(Processor):
     @interfacedoc
     def setup(self, channels=None, samplerate=None, nframes=None):
         super(Spectrogram, self).setup(channels, samplerate, nframes)
-        if self.graph:
-            self.graph = None
         self.graph = SpectrogramImage(self.width, self.height, self.nframes(), self.samplerate(), self.FFT_SIZE,
                                     bg_color=self.bg_color, color_scheme=self.color_scheme)
 
index 486802f50c7970ae504a76410e925badb9c2e904..3077d093e9265fedaec03a8c36629a080ba94900 100644 (file)
@@ -55,8 +55,6 @@ class Waveform(Processor):
     @interfacedoc
     def setup(self, channels=None, samplerate=None, nframes=None):
         super(Waveform, self).setup(channels, samplerate, nframes)
-        if self.graph:
-            self.graph = None
         self.graph = WaveformImage(self.width, self.height, self.nframes(), self.samplerate(), self.FFT_SIZE,
                                     bg_color=self.bg_color, color_scheme=self.color_scheme)
 
@@ -70,3 +68,4 @@ class Waveform(Processor):
         if output:
             self.graph.save(output)
         return self.graph.image
+        
index 5f2746bac19e1a1b3f1537b742c81c907a82a94a..49c848fa43a3f3aa80750fed98d74f845db9da45 100644 (file)
@@ -61,12 +61,10 @@ class WaveformAwdio(Processor):
     def process(self, frames, eod=False):
         self.graph.process(frames, eod)
         return frames, eod
-#
-#    def release(self):
-#        self.graph.release()
 
     @interfacedoc
     def render(self, output):
         if output:
             self.graph.save(output)
-#        return self.graph.image
+        return self.graph.image
+        
index 83b2535daa0786e0451e7a9ee7a939c5f884341a..526541cbb65af0f00ee5a5d6924ef0baeac24de3 100644 (file)
@@ -57,8 +57,8 @@ class WaveformJoyDiv(Processor):
     @interfacedoc
     def setup(self, channels=None, samplerate=None, nframes=None):
         super(WaveformJoyDiv, self).setup(channels, samplerate, nframes)
-        if self.graph:
-            self.graph = None
+#        if self.graph:
+#            self.graph = None
         self.graph = WaveformImageJoyContour(self.width, self.height, self.nframes(), self.samplerate(), self.FFT_SIZE,
                                     bg_color=self.bg_color, color_scheme=self.color_scheme,  ndiv=self.ndiv, symetry=self.symetry)
 
@@ -72,3 +72,6 @@ class WaveformJoyDiv(Processor):
         if output:
             self.graph.save(output)
         return self.graph.image
+
+    def release(self):
+        self.graph.release()