#self.artist = self.metadata['Artist']
#self.title = self.metadata['Title']
- # Decode the source if needed
- #if os.path.exists(self.source) and not iswav16(self.source):
- # TO FIX !
- # self.source = self.export.decode()
-
# Normalize if demanded
if not options is None:
self.options = options
self.options['normalize'] == True:
self.normalize()
- # Define the cache directory
+ # Define the export directory
self.ext = self.get_file_extension()
-
- # Define and create the destination path
- # At the moment, the target directory is built with this scheme in
- # the cache directory : ./%Format/%Collection/%Artist/
- #self.cache_dir = os.path.join(self.cache_dir,'cache')
-
- #export_dir = os.path.join(self.ext,self.collection,self.artist)
export_dir = os.path.join(self.cache_dir,self.ext)
if not os.path.exists(export_dir):
path = export_dir
# Set the target file
- #target_file = file_name_wo_ext+'.'+self.ext
target_file = self.item_id+'.'+self.ext
dest = os.path.join(path,target_file)
return dest
yield __chunk
file_out.write(__chunk)
- #file_in.close()
file_out.close()
def post_process(self, item_id, source, metadata, ext,
from telemeta.visualization.api import *
from telemeta.visualization.waveform import *
from telemeta.visualization.spectrogram import *
+from telemeta.visualization.spectrogram2 import *
+from telemeta.visualization.waveform2 import *
\ No newline at end of file
--- /dev/null
+function J = jet(m)
+%JET Variant of HSV
+% JET(M), a variant of HSV(M), is an M-by-3 matrix containing
+% the default colormap used by CONTOUR, SURF and PCOLOR.
+% The colors begin with dark blue, range through shades of
+% blue, cyan, green, yellow and red, and end with dark red.
+% JET, by itself, is the same length as the current figure's
+% colormap. If no figure exists, MATLAB creates one.
+%
+% See also HSV, HOT, PINK, FLAG, COLORMAP, RGBPLOT.
+
+% Copyright 1984-2004 The MathWorks, Inc.
+% $Revision: 5.7.4.2 $ $Date: 2005/06/21 19:31:40 $
+
+if nargin < 1
+ m = size(get(gcf,'colormap'),1);
+end
+n = ceil(m/4);
+u = [(1:1:n)/n ones(1,n-1) (n:-1:1)/n]';
+g = ceil(n/2) - (mod(m,4)==1) + (1:length(u))';
+r = g + n;
+b = g - n;
+g(g>m) = [];
+r(r>m) = [];
+b(b<1) = [];
+J = zeros(m,3);
+J(r,1) = u(1:length(r));
+J(g,2) = u(1:length(g));
+J(b,3) = u(end-length(b)+1:end);
\ No newline at end of file
--- /dev/null
+## Copyright (C) 2000 Paul Kienzle
+##
+## This program is free software and may be used for any purpose. This
+## copyright notice must be maintained. Paul Kienzle is not responsible
+## for the consequences of using this software.
+
+## usage: [S, f, t] = spectrogram(x, Fs, window, step, maxF, shape, minE)
+##
+## Generate a spectrogram for the signal. This chops the signal into
+## overlapping slices, windows each slice and applies a Fourier
+## transform to determine the frequency components at that slice.
+##
+## x: signal to analyse
+## Fs: sampling rate for the signal
+## window: analysis window length (default 30 msec)
+## step: time between windows, start to start (default 5 ms)
+## maxF: maximum frequency to display (default 4000 Hz)
+## Alternatively, use [maxF, nF], where nF is the minimum
+## of frequency points to display. If nF is greater than
+## what it would normally be for the given window size and
+## maximum displayed frequency, the FFT is zero-padded until
+## it at least nF points are displayed on the y axis.
+## shape: window analysis function (default 'hanning')
+## Shape is any function which takes an integer n and returns
+## a vector of length n. If shape contains %d and ends with
+## ')', as for example '(1:%d)' or 'kaiser(%d,0.5)' do, then
+## %d is replaced with the desired window length, and the
+## expression is evaluated.
+## minE: noise floor (default -40dB)
+## Any value less than the noise floor is clipped before the
+## spectrogram is displayed. This limits the dynamic range
+## that your spectrogram must accomodate. Alternatively,
+## use [minE, maxE], where maxE is the clipping ceiling, also
+## in decibels.
+##
+## Return values
+## S is the spectrogram in S with linear magnitude normalized to 1.
+## f is the frequency indices corresponding to the rows of S.
+## t is the time indices corresponding to the columns of S.
+## If no return value is requested, the spectrogram is displayed instead.
+##
+## Global variables
+## spectrogram_{window,step,maxF,nF,shape,minE,maxE} can override
+## the default values with your own.
+##
+## To make a good spectrogram, generating spectral slices is only half
+## the problem. Before you generate them, you must first choose your
+## window size, step size and FFT size. A wide window shows more
+## harmonic detail, a narrow window shows more formant structure. This
+## defines your time-frequency resolution. Step size controls the
+## horizontal scale of the spectrogram. Decrease it to stretch, or
+## increase it to compress. Certainly, increasing step size will reduce
+## time resolution, but decreasing it will not improve it much beyond
+## the limits imposed by the window size (you do gain a little bit,
+## depending on the shape of your window, as the peak of the window
+## slides over peaks in the signal energy). The range 1-5 msec is good
+## for speech. Finally, FFT length controls the vertical scale, with
+## larger values stretching the frequency range. Clearly, padding with
+## zeros does not add any information to the spectrum, but it is a
+## cheap, easy and good way to interpolate between frequency points, and
+## can make for prettier spectrograms.
+##
+## After you have generated the spectral slices, there are a number of
+## decisions for displaying them. Firstly, the entire frequency range
+## does not need to be displayed. The frequency range of the FFT is
+## determined by sampling rate. If most of your signal is below 4 kHz
+## (in speech for example), there is no reason to display up to the
+## Nyquist frequency of 10 kHz for a 20 kHz sampling rate. Next, there
+## is the dynamic range of the signal. Since the information in speech
+## is well above the noise floor, it makes sense to eliminate any
+## dynamic range at the bottom end. This is done by taking the max of
+## the normalized magnitude and some lower limit such as -40 dB.
+## Similarly, there is not much information in the very top of the
+## range, so clipping to -3 dB makes sense there. Finally, there is the
+## choice of colormap. A brightness varying colormap such as copper or
+## bone gives good shape to the ridges and valleys. A hue varying
+## colormap such as jet or hsv gives an indication of the steepness of
+## the slopes.
+
+## TODO: Accept vector of frequencies at which to sample the signal.
+## TODO: Consider accepting maxF (values > 0), shape (value is string)
+## TODO: and dynamic range (values <= 0) in any order.
+## TODO: Consider defaulting step and maxF so that the spectrogram is
+## TODO: an appropriate size for the screen (eg, 600x100).
+## TODO: Consider drawing in frequency/time grid;
+## TODO: (necessary with automatic sizing as suggested above)
+## TODO: Consider using step vs. [nT, nF] rather than maxF vs [maxF, nF]
+## TODO: Figure out why exist() is so slow: 50 ms vs 1 ms for lookup.
+
+function [S_r, f_r, t_r] = spectrogram(x, Fs, window, step, maxF, shape, minE)
+ global spectrogram_window=30;
+ global spectrogram_step=5;
+ global spectrogram_maxF=4000;
+ global spectrogram_shape="hanning";
+ global spectrogram_minE=-40;
+ global spectrogram_maxE=0;
+ global spectrogram_nF=[];
+
+ if nargin < 2 || nargin > 7
+ usage ("[S, f, t] = spectrogram(x, fs, window, step, maxF, shape, minE)");
+ end
+
+ if nargin<3 || isempty(window),
+ window=spectrogram_window;
+ endif
+ if nargin<4 || isempty(step),
+ step=spectrogram_step;
+ endif
+ if nargin<5 || isempty(maxF),
+ maxF=spectrogram_maxF;
+ endif
+ if nargin<6 || isempty(shape),
+ shape=spectrogram_shape;
+ endif
+ if nargin<7 || isempty(minE),
+ minE=spectrogram_minE;
+ endif
+ if any(minE>0)
+ error ("spectrogram clipping range must use values less than 0 dB");
+ endif
+ if length(minE)>1,
+ maxE=minE(2);
+ minE=minE(1);
+ else
+ maxE = spectrogram_maxE;
+ endif
+ if length(maxF)>1,
+ min_nF=maxF(2);
+ maxF=maxF(1);
+ else
+ min_nF=spectrogram_nF;
+ endif
+
+ ## make sure x is a column vector
+ if size(x,2) != 1 && size(x,1) != 1
+ error ("spectrogram data must be a vector");
+ end
+ if size(x,2) != 1, x = x'; end
+
+ if (maxF>Fs/2)
+ ## warning("spectrogram: cannot display frequencies greater than Fs/2");
+ maxF = Fs/2;
+ endif
+
+ step_n = fix(step*Fs/1000); # one spectral slice every step ms
+
+ ## generate window from duration and shape function name
+ win_n = fix(window*Fs/1000);
+ if shape(length(shape)) == ')'
+ shape = sprintf(shape, win_n);
+ else
+ shape = sprintf("%s(%d)", shape, win_n);
+ endif
+ win_vec = eval(strcat(shape,";"));
+ if size(win_vec,2) != 1, win_vec = win_vec'; endif
+ if size(win_vec,2) != 1 || size(win_vec,1) != win_n,
+ error("spectrogram %s did not return a window of length %d", \
+ shape, win_n);
+ endif
+
+ ## FFT length from size of window and number of freq. pts requested
+ fft_n = 2^nextpow2(win_n); # next highest power of 2
+ dF = Fs/fft_n; # freq. step with current fft_n
+ nF = ceil(maxF(1)/dF); # freq. pts with current fft_n,maxF
+ if !isempty(min_nF) # make sure there are at least n freq. pts
+ if min_nF > nF, # if not enough
+ dF = maxF/min_nF; # figure out what freq. step we need
+ fft_n = 2^nextpow2(Fs/dF); # figure out what fft_n this requires
+ dF = Fs/fft_n; # freq. step with new fft_n
+ nF = ceil(maxF/dF); # freq. pts with new fft_n,maxF
+ endif
+ endif
+
+ ## build matrix of windowed data slices
+ offset = 1:step_n:length(x)-win_n;
+ S = zeros (fft_n, length(offset));
+ for i=1:length(offset)
+ S(1:win_n, i) = x(offset(i):offset(i)+win_n-1) .* win_vec;
+ endfor
+
+ ## compute fourier transform
+ S = fft (S);
+ S = abs(S(1:nF,:)); # select the desired frequencies
+ S = S/max(S(:)); # normalize magnitude so that max is 0 dB.
+ S = max(S, 10^(minE/10)); # clip below minF dB.
+ S = min(S, 10^(maxE/10)); # clip above maxF dB.
+
+ f = [0:nF-1]*Fs/fft_n;
+ t = offset/Fs;
+ if nargout==0
+ imagesc(f,t,20*log10(flipud(S)));
+ else
+ S_r = S;
+ f_r = f;
+ t_r = t;
+ endif
+
+endfunction
\ No newline at end of file
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Guillaume Pellerin <pellerin@parisson.com>
+#
+# SpectrogramVisualizer2.m
+#
+# Depends: octave2.9, spectrogram.m, xloadimage, imagemagick
+
+clear all;
+close all;
+
+dest_image = $IMGFILE;
+wav_file = $WAVFILE;
+octave_path = $OCTAVEPATH;
+
+cd(octave_path);
+ncmap = 128; % number of points for colormap
+step = 6; % spectral slice period (ms)
+% step_length = fix(5*Fs/1000);
+window = 30; % filter window (ms)
+% window = fix(40*Fs/1000);
+lim_x_length = 10; % (s)
+
+[x, Fs] = wavread(wav_file);
+x = x(:,1); % mono
+lim_x_samples = Fs.*lim_x_length;
+if length(x) > lim_x_samples;
+ x = x(1:lim_x_samples)
+end
+
+%fftn = 2^nextpow2(window); % next highest power of 2
+[S, f, t] = spectrogram(x, Fs, window, step, 4000, 'hanning', -30);
+S = flipud(20*log10(S));
+%
+% cmap = [0:1:ncmap-1];
+% map_cos = cos(cmap*3.141/(2*ncmap));
+% map_lin = cmap./ncmap;
+% map_one = ones(1,ncmap);
+%
+% cmap = [ [map_cos]' [map_cos]' [fliplr(map_cos)]' ];
+% colormap(jet(ncmap));
+cmap = colormap(jet(ncmap));
+
+img = imagesc(t, f, S);
+%stdin(imagesc(t, f, S));
+saveimage(dest_image, img, 'ppm', cmap);
+%print([img_dir wav_file '.eps'], '-depsc');
+
+quit
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Parisson SARL
+# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Author: Guillaume Pellerin <pellerin@parisson.com>
+#
+# SpectrogramVisualizer2.m
+#
+# Depends: octave2.9, spectrogram.m, xloadimage, imagemagick
+
+clear all;
+close all;
+
+dest_image = $IMGFILE;
+wav_file = $WAVFILE;
+octave_path = $OCTAVEPATH;
+
+cd(octave_path);
+ncmap = 128; % number of points for colormap
+step = 6; % spectral slice period (ms)
+% step_length = fix(5*Fs/1000);
+window = 30; % filter window (ms)
+% window = fix(40*Fs/1000);
+lim_x_length = 10; % (s)
+
+[x, Fs] = wavread(wav_file);
+x = x(:,1); % mono
+lx = length(x);
+lim_x_samples = Fs.*lim_x_length;
+
+if lx > lim_x_samples;
+ x = x(1:lim_x_samples)
+end
+
+t = [1:1:lx]./Fs;
+
+img = plot(t,x);
+print(dest_image, '-dpng')
+
+quit
--- /dev/null
+
+from telemeta.core import *
+from telemeta.export import *
+from telemeta.visualization.api import IMediaItemVisualizer
+from django.conf import settings
+from tempfile import NamedTemporaryFile
+import os
+import random
+import subprocess
+import signal
+import time
+
+class OctaveCoreVisualizer(Component):
+ """Parent class for Octave visualization drivers"""
+
+ def get_mFile_line(self):
+ octave_path = os.path.dirname(__file__) + '/octave/'
+ mFile_path = os.path.dirname(__file__) + '/octave/' + self.mFile
+ mFile = open(mFile_path,'r')
+
+ while True:
+ line = mFile.readline()
+ if 'quit' in line:
+ break
+ if '$OCTAVEPATH' in line:
+ line = line.replace('$OCTAVEPATH','"'+octave_path+'"')
+ if '$WAVFILE' in line:
+ line = line.replace('$WAVFILE','"'+self.wavFile_path+'"')
+ if '$IMGFILE' in line:
+ line = line.replace('$IMGFILE','"'+self.ppmFile.name+'"')
+ yield line
+
+ mFile.close()
+
+ def set_m_file(self,mFile):
+ self.mFile = mFile
+
+ def get_wav_path(self, media_item):
+ self.wavFile_path = settings.MEDIA_ROOT + '/' + media_item.file
+
+ def octave_to_png_stream(self, media_item):
+
+ self.pngFile = NamedTemporaryFile(suffix='.png')
+ self.ppmFile = NamedTemporaryFile(suffix='.'+self.dest_type)
+ self.wavFile = self.get_wav_path(media_item)
+ #command = 'octave2.9 ' + self.mFile_tmp.name
+ command = 'octave2.9'
+
+ proc = subprocess.Popen(command,
+ shell = True,
+ #bufsize = buffer_size,
+ stdin = subprocess.PIPE,
+ stdout = subprocess.PIPE,
+ close_fds = True)
+
+ for line in self.get_mFile_line():
+ proc.stdin.write(line)
+
+ # Wait for ppm
+ status = os.stat(self.ppmFile.name).st_size
+ while True:
+ if status == os.stat(self.ppmFile.name).st_size and status != 0:
+ break
+ status = os.stat(self.ppmFile.name).st_size
+ #print status
+ time.sleep(1)
+
+ # Convert
+ os.system('convert ' + self.ppmFile.name + ' -scale 300x300 ' + self.pngFile.name)
+
+ os.kill(proc.pid, signal.SIGKILL)
+
+ # Stream
+ while True :
+ buffer = self.pngFile.read(self.buffer_size)
+ if len(buffer) == 0:
+ break
+ yield buffer
+
+ self.ppmFile.close()
+ self.pngFile.close()
def cleanup(self):
self.snd.destroy()
self.tk_root.destroy()
+
canvas.create_spectrogram(0, 10, sound=snd, height=180, width=300 ,
windowtype="hamming", fftlength=1024, topfrequency=5000, channel="all", winlength=64)
-
stream = self.canvas_to_png_stream(canvas)
return stream
--- /dev/null
+# Copyright (C) 2007 Samalyse SARL
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Authors: Olivier Guilyardi <olivier@samalyse.com>
+# Guillaume Pellerin <pellerin@parisson.com>
+
+from telemeta.core import *
+from telemeta.visualization.api import IMediaItemVisualizer
+from telemeta.visualization.octave_core import OctaveCoreVisualizer
+
+class SpectrogramVisualizer2(OctaveCoreVisualizer):
+ """Octave spectral view visualization driver"""
+
+ implements(IMediaItemVisualizer)
+
+ def __init__(self):
+ self.set_m_file('spectrogram2img.m')
+ self.buffer_size = 0xFFFF
+ self.dest_type = 'ppm'
+
+ def get_id(self):
+ return "spectrogram2"
+
+ def get_name(self):
+ return "Spectrogram2"
+
+ def render(self, media_item, options=None):
+ """Generator that streams the spectral view as a PNG image"""
+
+ stream = self.octave_to_png_stream(media_item)
+ return stream
+
buffer = pngFile.read(0xFFFF)
pngFile.close()
-
-
-
-
-
-
-
--- /dev/null
+# Copyright (C) 2007 Samalyse SARL
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://svn.parisson.org/telemeta/TelemetaLicense.
+#
+# Authors: Olivier Guilyardi <olivier@samalyse.com>
+# Guillaume Pellerin <pellerin@parisson.com>
+
+from telemeta.core import *
+from telemeta.visualization.api import IMediaItemVisualizer
+from telemeta.visualization.octave_core import OctaveCoreVisualizer
+
+class WaveformVisualizer2(OctaveCoreVisualizer):
+ """Octave temporal view visualization driver"""
+
+ implements(IMediaItemVisualizer)
+
+ def __init__(self):
+ self.set_m_file('waveform2img.m')
+ self.buffer_size = 0xFFFF
+ self.dest_type = 'png'
+
+ def get_id(self):
+ return "waveform2"
+
+ def get_name(self):
+ return "Waveform2"
+
+ def render(self, media_item, options=None):
+ """Generator that streams the temporal view as a PNG image"""
+
+ stream = self.octave_to_png_stream(media_item)
+ return stream
+