My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env python
# encoding: utf-8
"""
modify.py

Created by Ben Lacker on 2009-06-12.
"""
from echonest.audio import *
import numpy
import soundtouch

class Modify(soundtouch.SoundTouch):
def __init__(self, sampleRate=44100, numChannels=1, blockSize = 10000):
self.setSampleRate(sampleRate)
self.setChannels(numChannels)
self.sampleRate = sampleRate
self.numChannels = numChannels
self.blockSize = blockSize

def doInBlocks(self, f, in_data, arg):
# For now, make everything mono. We'll deal with channels later
if in_data.ndim > 1:
in_data = in_data[:, 0]
collect = []
if len(in_data) > self.blockSize:
for x in range(len(in_data)/self.blockSize):
start = x * self.blockSize
data = in_data[start:start + self.blockSize -1]
collect.append(self.processAudio(f, data, arg))
data = in_data[-1*(len(in_data) % self.blockSize):]
collect.append(self.processAudio(f, data, arg))
else:
collect.append(self.processAudio(f, in_data, arg))
return assemble(collect, numChannels=self.numChannels, sampleRate=self.sampleRate)

def processAudio(self, f, data, arg):
f(arg)
self.putSamples(data)
out_data = numpy.array(numpy.zeros((len(data)*2,), dtype=numpy.float32))
out_samples = self.receiveSamples(out_data)
new_ad = AudioData(ndarray=out_data[:out_samples], shape=(out_samples, ),
sampleRate=self.sampleRate, numChannels=self.numChannels)
return new_ad

def shiftRate(self, audio_data, ratio=1):
if not isinstance(audio_data, AudioData):
raise TypeError('First argument must be an AudioData object.')
if not (isinstance(ratio, int) or isinstance(ratio, float)):
raise ValueError('Ratio must be an int or float.')
if (ratio < 0) or (ratio > 10):
raise ValueError('Ratio must be between 0 and 10.')
return self.doInBlocks(self.setRate, audio_data.data, ratio)

def shiftTempo(self, audio_data, ratio):
if not isinstance(audio_data, AudioData):
raise TypeError('First argument must be an AudioData object.')
if not (isinstance(ratio, int) or isinstance(ratio, float)):
raise ValueError('Ratio must be an int or float.')
if (ratio < 0) or (ratio > 10):
raise ValueError('Ratio must be between 0 and 10.')
return self.doInBlocks(self.setTempo, audio_data.data, ratio)

def shiftRateChange(self, audio_data, percent):
if not isinstance(audio_data, AudioData):
raise TypeError('First argument must be an AudioData object.')
if not (isinstance(percent, int) or isinstance(percent, float)):
raise ValueError('Percent must be an int or float.')
if (percent < -50) or (percent > 100):
raise ValueError('Percent must be between -50 and 100.')
return self.doInBlocks(self.setRateChange, audio_data.data, percent)

def shiftTempoChange(self, audio_data, percent):
if not isinstance(audio_data, AudioData):
raise TypeError('First argument must be an AudioData object.')
if not (isinstance(percent, int) or isinstance(percent, float)):
raise ValueError('Percent must be an int or float.')
if (percent < -50) or (percent > 100):
raise ValueError('Percent must be between -50 and 100.')
return self.doInBlocks(self.setTempoChange, audio_data.data, percent)

def shiftPitchSemiTones(self, audio_data, semitones=0):
if not isinstance(audio_data, AudioData):
raise TypeError('First argument must be an AudioData object.')
if not isinstance(semitones, int):
raise TypeError('Second argument must be an integer.')
# I think this is right, but maybe it has to be between -12 and 12?
if abs(semitones) > 60:
raise ValueError('Semitones argument must be an int between -60 and 60.')
return self.doInBlocks(self.setPitchSemiTones, audio_data.data, semitones)

def shiftPitchOctaves(self, audio_data, octaves=0):
if not isinstance(audio_data, AudioData):
raise TypeError('First argument must be an AudioData object.')
if not (isinstance(octaves, int) or isinstance(octaves, float)):
raise ValueError('Octaves must be an int or float.')
if abs(octaves) > 5:
raise ValueError('Octaves argument must be between -5 and 5.')
# what are the limits? Nothing in soundtouch documentation...
return self.doInBlocks(self.setPitchOctaves, audio_data.data, octaves)

def shiftPitch(self, audio_data, ratio=1):
if not isinstance(audio_data, AudioData):
raise TypeError('First argument must be an AudioData object.')
if not (isinstance(ratio, int) or isinstance(ratio, float)):
raise ValueError('Ratio must be an int or float.')
if (ratio < 0) or (ratio > 10):
raise ValueError('Ratio must be between 0 and 10.')
return self.doInBlocks(self.setPitch, audio_data.data, ratio)

Change log

r326 by blac...@echonest.com on Jul 10, 2009   Diff
Copied pre-release-1.2 to trunk
Go to: 
Project members, sign in to write a code review

Older revisions

r273 by blac...@echonest.com on Jul 7, 2009   Diff
folding in modify (time-stretching and
pitch-shifting module)
r236 by blac...@echonest.com on Jun 16, 2009   Diff
Now produces AudioData of the correct
length. Added audio.assemble()
function to stitch together multiple
AudioData
r234 by blac...@echonest.com on Jun 15, 2009   Diff
there's still a bug when trying to
time-stretch an entire file to be
longer than the original, but
otherwise this works.
All revisions of this file

File info

Size: 5230 bytes, 109 lines
Powered by Google Project Hosting