WaveSwissKnife 0.0.1.20101110-x86-cygwin
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +1 -0
- data/ChangeLog +5 -0
- data/Credits +3 -0
- data/LICENSE +31 -0
- data/README +18 -0
- data/ReleaseInfo +8 -0
- data/TODO +2 -0
- data/bin/WSK.rb +14 -0
- data/ext/WSK/AnalyzeUtils/AnalyzeUtils.c +272 -0
- data/ext/WSK/AnalyzeUtils/AnalyzeUtils.o +0 -0
- data/ext/WSK/AnalyzeUtils/AnalyzeUtils.so +0 -0
- data/ext/WSK/AnalyzeUtils/Makefile +149 -0
- data/ext/WSK/AnalyzeUtils/build.rb +18 -0
- data/ext/WSK/ArithmUtils/ArithmUtils.c +862 -0
- data/ext/WSK/ArithmUtils/ArithmUtils.o +0 -0
- data/ext/WSK/ArithmUtils/ArithmUtils.so +0 -0
- data/ext/WSK/ArithmUtils/Makefile +149 -0
- data/ext/WSK/ArithmUtils/build.rb +20 -0
- data/ext/WSK/FFTUtils/FFTUtils.c +662 -0
- data/ext/WSK/FFTUtils/FFTUtils.o +0 -0
- data/ext/WSK/FFTUtils/FFTUtils.so +0 -0
- data/ext/WSK/FFTUtils/Makefile +149 -0
- data/ext/WSK/FFTUtils/build.rb +20 -0
- data/ext/WSK/FunctionUtils/FunctionUtils.c +182 -0
- data/ext/WSK/FunctionUtils/FunctionUtils.o +0 -0
- data/ext/WSK/FunctionUtils/FunctionUtils.so +0 -0
- data/ext/WSK/FunctionUtils/Makefile +149 -0
- data/ext/WSK/FunctionUtils/build.rb +20 -0
- data/ext/WSK/SilentUtils/Makefile +149 -0
- data/ext/WSK/SilentUtils/SilentUtils.c +431 -0
- data/ext/WSK/SilentUtils/SilentUtils.o +0 -0
- data/ext/WSK/SilentUtils/SilentUtils.so +0 -0
- data/ext/WSK/SilentUtils/build.rb +18 -0
- data/ext/WSK/VolumeUtils/Makefile +149 -0
- data/ext/WSK/VolumeUtils/VolumeUtils.c +494 -0
- data/ext/WSK/VolumeUtils/VolumeUtils.o +0 -0
- data/ext/WSK/VolumeUtils/VolumeUtils.so +0 -0
- data/ext/WSK/VolumeUtils/build.rb +20 -0
- data/lib/WSK/Actions/Analyze.rb +176 -0
- data/lib/WSK/Actions/ApplyMap.desc.rb +15 -0
- data/lib/WSK/Actions/ApplyMap.rb +57 -0
- data/lib/WSK/Actions/ApplyVolumeFct.desc.rb +30 -0
- data/lib/WSK/Actions/ApplyVolumeFct.rb +72 -0
- data/lib/WSK/Actions/Compare.desc.rb +25 -0
- data/lib/WSK/Actions/Compare.rb +238 -0
- data/lib/WSK/Actions/ConstantCompare.desc.rb +20 -0
- data/lib/WSK/Actions/ConstantCompare.rb +61 -0
- data/lib/WSK/Actions/Cut.desc.rb +20 -0
- data/lib/WSK/Actions/Cut.rb +60 -0
- data/lib/WSK/Actions/CutFirstSignal.desc.rb +25 -0
- data/lib/WSK/Actions/CutFirstSignal.rb +72 -0
- data/lib/WSK/Actions/DCShifter.desc.rb +15 -0
- data/lib/WSK/Actions/DCShifter.rb +67 -0
- data/lib/WSK/Actions/DrawFct.desc.rb +20 -0
- data/lib/WSK/Actions/DrawFct.rb +59 -0
- data/lib/WSK/Actions/FFT.rb +104 -0
- data/lib/WSK/Actions/GenAllValues.rb +67 -0
- data/lib/WSK/Actions/GenConstant.desc.rb +20 -0
- data/lib/WSK/Actions/GenConstant.rb +56 -0
- data/lib/WSK/Actions/GenSawtooth.rb +57 -0
- data/lib/WSK/Actions/GenSine.desc.rb +20 -0
- data/lib/WSK/Actions/GenSine.rb +73 -0
- data/lib/WSK/Actions/Identity.rb +43 -0
- data/lib/WSK/Actions/Mix.desc.rb +15 -0
- data/lib/WSK/Actions/Mix.rb +149 -0
- data/lib/WSK/Actions/Multiply.desc.rb +15 -0
- data/lib/WSK/Actions/Multiply.rb +73 -0
- data/lib/WSK/Actions/NoiseGate.desc.rb +35 -0
- data/lib/WSK/Actions/NoiseGate.rb +129 -0
- data/lib/WSK/Actions/SilenceInserter.desc.rb +20 -0
- data/lib/WSK/Actions/SilenceInserter.rb +87 -0
- data/lib/WSK/Actions/SilenceRemover.desc.rb +30 -0
- data/lib/WSK/Actions/SilenceRemover.rb +74 -0
- data/lib/WSK/Actions/VolumeProfile.desc.rb +35 -0
- data/lib/WSK/Actions/VolumeProfile.rb +63 -0
- data/lib/WSK/Common.rb +292 -0
- data/lib/WSK/FFT.rb +527 -0
- data/lib/WSK/Functions.rb +770 -0
- data/lib/WSK/Launcher.rb +216 -0
- data/lib/WSK/Maps.rb +29 -0
- data/lib/WSK/Model/CachedBufferReader.rb +151 -0
- data/lib/WSK/Model/Header.rb +133 -0
- data/lib/WSK/Model/InputData.rb +193 -0
- data/lib/WSK/Model/RawReader.rb +78 -0
- data/lib/WSK/Model/WaveReader.rb +91 -0
- data/lib/WSK/OutputInterfaces/DirectStream.rb +146 -0
- data/lib/WSK/RIFFReader.rb +60 -0
- metadata +151 -0
@@ -0,0 +1,193 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'WSK/Model/RawReader.rb'
|
7
|
+
require 'WSK/Model/WaveReader.rb'
|
8
|
+
|
9
|
+
module WSK
|
10
|
+
|
11
|
+
module Model
|
12
|
+
|
13
|
+
class InputData
|
14
|
+
|
15
|
+
# Number of samples in the data
|
16
|
+
# Integer
|
17
|
+
attr_reader :NbrSamples
|
18
|
+
|
19
|
+
# Header of the input data
|
20
|
+
# WSK::Model::Header
|
21
|
+
attr_reader :Header
|
22
|
+
|
23
|
+
# Constructor
|
24
|
+
#
|
25
|
+
# Parameters:
|
26
|
+
# * *iFile* (_IO_): The file descriptor. Don't use it externally as long as it is used by this class.
|
27
|
+
# * *iHeader* (<em>WSK::Model::Header</em>): Corresponding file header
|
28
|
+
def initialize(iFile, iHeader)
|
29
|
+
@File, @Header = iFile, iHeader
|
30
|
+
@NbrSamples = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Check that data seems coherent, and initialize the cursor
|
34
|
+
#
|
35
|
+
# Return:
|
36
|
+
# * _Exception_: Error, or nil in case of success
|
37
|
+
def initCursor
|
38
|
+
rError = nil
|
39
|
+
|
40
|
+
# Size of a sample
|
41
|
+
# Integer
|
42
|
+
lSampleSize = (@Header.NbrChannels*@Header.NbrBitsPerSample)/8
|
43
|
+
# Read the size of the data
|
44
|
+
rError, lDataSize = RIFFReader.new(@File).setFilePos('data')
|
45
|
+
if (rError == nil)
|
46
|
+
# Check that the data size is coherent
|
47
|
+
if (lDataSize % lSampleSize == 0)
|
48
|
+
@NbrSamples = lDataSize / lSampleSize
|
49
|
+
@RawReader = RawReader.new(@File, @File.pos, lSampleSize, @NbrSamples)
|
50
|
+
@WaveReader = WaveReader.new(@RawReader, @Header)
|
51
|
+
logDebug "Number of samples: #{@NbrSamples}"
|
52
|
+
else
|
53
|
+
rError = RuntimeError.new("Data size (#{lDataSize} should be a multiple of #{lSampleSize} according to header.")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
return rError
|
58
|
+
end
|
59
|
+
|
60
|
+
# Iterate through the samples
|
61
|
+
#
|
62
|
+
# Parameters:
|
63
|
+
# * *iIdxBeginSample* (_Integer_): Index of the first sample to begin with [optional = 0]
|
64
|
+
# * *CodeBlock*: The code called for each iteration:
|
65
|
+
# ** *iInputSampleData* (<em>list<Integer></em>): The list of values (1 per channel)
|
66
|
+
def each(iIdxBeginSample = 0)
|
67
|
+
eachBuffer(iIdxBeginSample) do |iBuffer, iNbrSamples|
|
68
|
+
iBuffer.size.times do |iIdxSample|
|
69
|
+
yield(iBuffer[iIdxSample*@Header.NbrChannels..(iIdxSample+1)*@Header.NbrChannels-1])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Iterate through the buffers. This is far more efficient than iterating over samples.
|
75
|
+
#
|
76
|
+
# Parameters:
|
77
|
+
# * *iIdxBeginSample* (_Integer_): Index of the first sample to begin with [optional = 0]
|
78
|
+
# * *CodeBlock*: The code called for each iteration:
|
79
|
+
# ** *iInputBuffer* (<em>list<Integer></em>): The list of channel values
|
80
|
+
# ** *iNbrSamples* (_Integer_): The number of samples in this buffer
|
81
|
+
# ** *iNbrChannels* (_Integer_): The number of channels in this buffer
|
82
|
+
def eachBuffer(iIdxBeginSample = 0)
|
83
|
+
@WaveReader.eachBuffer(iIdxBeginSample) do |iBuffer, iNbrSamples|
|
84
|
+
yield(iBuffer, iNbrSamples, @Header.NbrChannels)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Get the current buffer.
|
89
|
+
# !!! This must be called only if the buffer was previously initialized (call getSampleSata to do so).
|
90
|
+
#
|
91
|
+
# Return:
|
92
|
+
# * <em>list<Integer></em>: The list of channel values
|
93
|
+
# * _Integer_: The number of samples in this buffer
|
94
|
+
# * _Integer_: The number of channels in this buffer
|
95
|
+
def getCurrentBuffer
|
96
|
+
rBuffer, lIdxStartSample, lIdxEndSample = @WaveReader.getCurrentBuffer
|
97
|
+
|
98
|
+
return rBuffer, lIdxEndSample-lIdxStartSample+1, @Header.NbrChannels
|
99
|
+
end
|
100
|
+
|
101
|
+
# Get the current raw buffer.
|
102
|
+
# !!! This must be called only if the buffer was previously initialized (call eachRawBuffer to do so).
|
103
|
+
#
|
104
|
+
# Return:
|
105
|
+
# * _String_: The raw buffer
|
106
|
+
# * _Integer_: The number of samples in this buffer
|
107
|
+
# * _Integer_: The number of channels in this buffer
|
108
|
+
def getCurrentRawBuffer
|
109
|
+
rBuffer, lIdxStartSample, lIdxEndSample = @RawReader.getCurrentBuffer
|
110
|
+
|
111
|
+
return rBuffer, lIdxEndSample-lIdxStartSample+1, @Header.NbrChannels
|
112
|
+
end
|
113
|
+
|
114
|
+
# Iterate through the buffers in the reverse order. This is far more efficient than iterating over samples.
|
115
|
+
#
|
116
|
+
# Parameters:
|
117
|
+
# * *iIdxEndSample* (_Integer_): Index of the first sample to begin with [optional = @NbrSamples-1]
|
118
|
+
# * *CodeBlock*: The code called for each iteration:
|
119
|
+
# ** *iInputBuffer* (<em>list<Integer></em>): The list of channel values
|
120
|
+
# ** *iNbrSamples* (_Integer_): The number of samples in this buffer
|
121
|
+
# ** *iNbrChannels* (_Integer_): The number of channels in this buffer
|
122
|
+
def eachReverseBuffer(iIdxEndSample = @NbrSamples-1)
|
123
|
+
@WaveReader.eachReverseBuffer(0, iIdxEndSample) do |iBuffer, iNbrSamples|
|
124
|
+
yield(iBuffer, iNbrSamples, @Header.NbrChannels)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Iterate through the buffers in raw mode (strings read directly without unpacking).
|
129
|
+
# This is far more efficient than iterating over samples or unpacked buffers.
|
130
|
+
#
|
131
|
+
# Parameters:
|
132
|
+
# * *iIdxBeginSample* (_Integer_): Index of the first sample to begin with [optional = 0]
|
133
|
+
# * *iIdxLastSample* (_Integer_): Index of the last sample to end with [optional = @NbrSamples-1]
|
134
|
+
# * *iOptions* (<em>map<Symbol,Object></em>): Additional options. See CachedBufferReader for documentation. [optional = {}]
|
135
|
+
# * *CodeBlock*: The code called for each iteration:
|
136
|
+
# ** *iInputRawBuffer* (_String_): The raw buffer
|
137
|
+
# ** *iNbrSamples* (_Integer_): The number of samples in this buffer
|
138
|
+
# ** *iNbrChannels* (_Integer_): The number of channels in this buffer
|
139
|
+
def eachRawBuffer(iIdxBeginSample = 0, iIdxLastSample = @NbrSamples-1, iOptions = {})
|
140
|
+
@RawReader.eachBuffer(iIdxBeginSample, iIdxLastSample, iOptions) do |iBuffer, iNbrSamples|
|
141
|
+
yield(iBuffer, iNbrSamples, @Header.NbrChannels)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Iterate through the buffers in the reverse order in raw mode (strings read directly without unpacking).
|
146
|
+
# This is far more efficient than iterating over samples or unpacked buffers.
|
147
|
+
#
|
148
|
+
# Parameters:
|
149
|
+
# * *iIdxBeginSample* (_Integer_): Index of the first sample to begin with [optional = 0]
|
150
|
+
# * *iIdxLastSample* (_Integer_): Index of the last sample to end with [optional = @NbrSamples-1]
|
151
|
+
# * *iOptions* (<em>map<Symbol,Object></em>): Additional options. See CachedBufferReader for documentation. [optional = {}]
|
152
|
+
# * *CodeBlock*: The code called for each iteration:
|
153
|
+
# ** *iInputRawBuffer* (_String_): The raw buffer
|
154
|
+
# ** *iNbrSamples* (_Integer_): The number of samples in this buffer
|
155
|
+
# ** *iNbrChannels* (_Integer_): The number of channels in this buffer
|
156
|
+
def eachReverseRawBuffer(iIdxBeginSample = 0, iIdxLastSample = @NbrSamples-1, iOptions = {})
|
157
|
+
@RawReader.eachReverseBuffer(iIdxBeginSample, iIdxLastSample, iOptions) do |iBuffer, iNbrSamples|
|
158
|
+
yield(iBuffer, iNbrSamples, @Header.NbrChannels)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Get a sample's data
|
163
|
+
#
|
164
|
+
# Parameters:
|
165
|
+
# * *iIdxSample* (_Integer_): Index of the sample to retrieve
|
166
|
+
# * *iOptions* (<em>map<Symbol,Object></em>): Additional options [optional = {}]
|
167
|
+
# ** *:ReverseBuffer* (_Boolean_): Do we load the previous buffer containing this sample if needed ? [optional = false]
|
168
|
+
# Return:
|
169
|
+
# * <em>list<Integer></em>: The list of values (1 per channel), or nil in case of error
|
170
|
+
def getSampleData(iIdxSample, iOptions = {})
|
171
|
+
rSampleData = nil
|
172
|
+
|
173
|
+
lReverseBuffer = (iOptions[:ReverseBuffer] != nil) ? iOptions[:ReverseBuffer] : false
|
174
|
+
if (lReverseBuffer)
|
175
|
+
@WaveReader.eachReverseBuffer(0, iIdxSample) do |iBuffer, iNbrSamples|
|
176
|
+
rSampleData = iBuffer[-@Header.NbrChannels..-1]
|
177
|
+
break
|
178
|
+
end
|
179
|
+
else
|
180
|
+
@WaveReader.eachBuffer(iIdxSample) do |iBuffer, iNbrSamples|
|
181
|
+
rSampleData = iBuffer[0..@Header.NbrChannels-1]
|
182
|
+
break
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
return rSampleData
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'WSK/Model/CachedBufferReader'
|
7
|
+
|
8
|
+
module WSK
|
9
|
+
|
10
|
+
module Model
|
11
|
+
|
12
|
+
# Implement a RAW file reader using cached buffer reader.
|
13
|
+
# Buffers returned are of type String.
|
14
|
+
class RawReader < CachedBufferReader
|
15
|
+
|
16
|
+
# Buffer size.
|
17
|
+
# It is expressed in bytes.
|
18
|
+
# Integer
|
19
|
+
BUFFER_SIZE = 8388608
|
20
|
+
|
21
|
+
# Constructor
|
22
|
+
#
|
23
|
+
# Parameters:
|
24
|
+
# * *iFile* (_IO_): The file descriptor. Don't use it externally as long as it is used by this class.
|
25
|
+
# * *iFirstSampleFilePos* (_Integer_): Position in the file of the first sample
|
26
|
+
# * *iSampleSize* (_Integer_): Size of a single sample to read
|
27
|
+
# * *iNbrSamples* (_Integer_): Total number of samples
|
28
|
+
def initialize(iFile, iFirstSampleFilePos, iSampleSize, iNbrSamples)
|
29
|
+
@File, @FirstSampleFilePos, @SampleSize, @NbrSamples = iFile, iFirstSampleFilePos, iSampleSize, iNbrSamples
|
30
|
+
super()
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the number of samples read per buffer
|
34
|
+
#
|
35
|
+
# Return:
|
36
|
+
# * _Integer_: Nnumber of samples in 1 buffer
|
37
|
+
def getNbrSamplesPerBuffer
|
38
|
+
return BUFFER_SIZE/@SampleSize
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get the total number of samples
|
42
|
+
#
|
43
|
+
# Return:
|
44
|
+
# * _Integer_: Total number of samples
|
45
|
+
def getNbrSamples
|
46
|
+
return @NbrSamples
|
47
|
+
end
|
48
|
+
|
49
|
+
# Read a buffer
|
50
|
+
#
|
51
|
+
# Parameters:
|
52
|
+
# * *iIdxStartSample* (_Integer_): Index of the first sample to begin with
|
53
|
+
# * *iIdxEndSample* (_Integer_): Index of the last sample to end with
|
54
|
+
# Return:
|
55
|
+
# * _Object_: The corresponding buffer
|
56
|
+
def readBuffer(iIdxStartSample, iIdxEndSample)
|
57
|
+
@File.seek(@FirstSampleFilePos + iIdxStartSample*@SampleSize)
|
58
|
+
logDebug "Raw read samples [#{iIdxStartSample} - #{iIdxEndSample}]"
|
59
|
+
return @File.read((iIdxEndSample-iIdxStartSample+1)*@SampleSize)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Extract a sub-buffer for the given index range
|
63
|
+
#
|
64
|
+
# Parameters:
|
65
|
+
# * *iBuffer* (_Object_): The buffer to extract from
|
66
|
+
# * *iIdxStartSample* (_Integer_): Index of the first sample to begin with
|
67
|
+
# * *iIdxEndSample* (_Integer_): Index of the last sample to end with
|
68
|
+
# Return:
|
69
|
+
# * _Object_: The sub buffer
|
70
|
+
def extractSubBuffer(iBuffer, iIdxStartSample, iIdxEndSample)
|
71
|
+
return iBuffer[iIdxStartSample*@SampleSize..(iIdxEndSample+1)*@SampleSize-1]
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'WSK/Model/CachedBufferReader'
|
7
|
+
|
8
|
+
module WSK
|
9
|
+
|
10
|
+
module Model
|
11
|
+
|
12
|
+
# Implement a Wave file reader using a raw buffer reader.
|
13
|
+
# Buffers returned are of type list<Integer>.
|
14
|
+
class WaveReader < CachedBufferReader
|
15
|
+
|
16
|
+
# Number of channel samples per buffer.
|
17
|
+
# Integer
|
18
|
+
NBR_CHANNEL_SAMPLES_PER_BUFFER = 2097152
|
19
|
+
|
20
|
+
# Constructor
|
21
|
+
#
|
22
|
+
# Parameters:
|
23
|
+
# * *iRawReader* (_CachedBufferReader_): The reader that provides raw data
|
24
|
+
# * *iHeader* (<em>WSK::Model::Header</em>): Corresponding file header
|
25
|
+
def initialize(iRawReader, iHeader)
|
26
|
+
@RawReader, @Header = iRawReader, iHeader
|
27
|
+
super()
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get the number of samples read per buffer
|
31
|
+
#
|
32
|
+
# Return:
|
33
|
+
# * _Integer_: Nnumber of samples in 1 buffer
|
34
|
+
def getNbrSamplesPerBuffer
|
35
|
+
return NBR_CHANNEL_SAMPLES_PER_BUFFER/@Header.NbrChannels
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get the total number of samples
|
39
|
+
#
|
40
|
+
# Return:
|
41
|
+
# * _Integer_: Total number of samples
|
42
|
+
def getNbrSamples
|
43
|
+
return @RawReader.getNbrSamples
|
44
|
+
end
|
45
|
+
|
46
|
+
# Read a buffer
|
47
|
+
#
|
48
|
+
# Parameters:
|
49
|
+
# * *iIdxStartSample* (_Integer_): Index of the first sample to begin with
|
50
|
+
# * *iIdxEndSample* (_Integer_): Index of the last sample to end with
|
51
|
+
# Return:
|
52
|
+
# * _Object_: The corresponding buffer
|
53
|
+
def readBuffer(iIdxStartSample, iIdxEndSample)
|
54
|
+
lRawBuffer = nil
|
55
|
+
lNbrSamplesToRead = iIdxEndSample - iIdxStartSample + 1
|
56
|
+
@RawReader.eachBuffer(iIdxStartSample, iIdxEndSample) do |iBuffer, iNbrSamples|
|
57
|
+
if (lRawBuffer == nil)
|
58
|
+
if (lNbrSamplesToRead == iNbrSamples)
|
59
|
+
# We have the buffer directly. No copy.
|
60
|
+
lRawBuffer = iBuffer
|
61
|
+
else
|
62
|
+
# We will need to concatenate other buffers. Clone it.
|
63
|
+
lRawBuffer = iBuffer.clone
|
64
|
+
end
|
65
|
+
else
|
66
|
+
# Concatenate
|
67
|
+
lRawBuffer.concat(iBuffer)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
logDebug "Decode samples [#{iIdxStartSample} - #{iIdxEndSample}]"
|
71
|
+
|
72
|
+
return @Header.getDecodedSamples(lRawBuffer, lNbrSamplesToRead)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Extract a sub-buffer for the given index range
|
76
|
+
#
|
77
|
+
# Parameters:
|
78
|
+
# * *iBuffer* (_Object_): The buffer to extract from
|
79
|
+
# * *iIdxStartSample* (_Integer_): Index of the first sample to begin with
|
80
|
+
# * *iIdxEndSample* (_Integer_): Index of the last sample to end with
|
81
|
+
# Return:
|
82
|
+
# * _Object_: The sub buffer
|
83
|
+
def extractSubBuffer(iBuffer, iIdxStartSample, iIdxEndSample)
|
84
|
+
return iBuffer[iIdxStartSample*@Header.NbrChannels..(iIdxEndSample+1)*@Header.NbrChannels-1]
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module OutputInterfaces
|
9
|
+
|
10
|
+
class DirectStream
|
11
|
+
|
12
|
+
# Here we define the buffer size.
|
13
|
+
# The buffer will be used to store contiguous audio data in RAM.
|
14
|
+
# Each OutputData object will never use more than this size.
|
15
|
+
# It is expressed in bytes.
|
16
|
+
# Integer
|
17
|
+
BUFFER_SIZE = 2097152
|
18
|
+
|
19
|
+
# Initialize the plugin
|
20
|
+
#
|
21
|
+
# Parameters:
|
22
|
+
# * *oFile* (_IO_): The file descriptor. Don't use it externally as long as it is used by this class.
|
23
|
+
# * *iHeader* (<em>WSK::Model::Header</em>): Corresponding file header
|
24
|
+
# * *iNbrOutputDataSamples* (_Integer_): The number of output data samples
|
25
|
+
# Return:
|
26
|
+
# * _Exception_: An error, or nil in case of success
|
27
|
+
def initInterface(oFile, iHeader, iNbrOutputDataSamples)
|
28
|
+
rError = nil
|
29
|
+
|
30
|
+
@File, @Header, @NbrSamples = oFile, iHeader, iNbrOutputDataSamples
|
31
|
+
@NbrSamplesWritten = 0
|
32
|
+
# Size of a sample
|
33
|
+
# Integer
|
34
|
+
@SampleSize = (@Header.NbrChannels*@Header.NbrBitsPerSample)/8
|
35
|
+
# Compute the number of samples to store in the buffer
|
36
|
+
@NbrSamplesPerBuffer = BUFFER_SIZE/@SampleSize
|
37
|
+
# The position of the last written sample in the buffer
|
38
|
+
# Integer
|
39
|
+
@IdxCurrentBufferSample = 0
|
40
|
+
# The buffer itself, list of channels values
|
41
|
+
# list< Integer >
|
42
|
+
@Buffer = []
|
43
|
+
|
44
|
+
return rError
|
45
|
+
end
|
46
|
+
|
47
|
+
# Finalize writing
|
48
|
+
#
|
49
|
+
# Return:
|
50
|
+
# * _Integer_: The number of samples written
|
51
|
+
def finalize
|
52
|
+
if (!@Buffer.empty?)
|
53
|
+
flushBuffer
|
54
|
+
end
|
55
|
+
|
56
|
+
return @NbrSamplesWritten
|
57
|
+
end
|
58
|
+
|
59
|
+
# Add a sample data
|
60
|
+
#
|
61
|
+
# Parameters:
|
62
|
+
# * *iSampleData* (<em>list<Integer></em>): The list of channel values for this sample
|
63
|
+
def pushSample(iSampleData)
|
64
|
+
# Write data in the buffer
|
65
|
+
@Buffer += iSampleData
|
66
|
+
@IdxCurrentBufferSample += 1
|
67
|
+
if (@IdxCurrentBufferSample == @NbrSamplesPerBuffer)
|
68
|
+
# We have to flush the buffer
|
69
|
+
flushBuffer
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Add a buffer
|
74
|
+
#
|
75
|
+
# Parameters:
|
76
|
+
# * *iBuffer* (<em>list<Integer></em>): The list of channel values for this buffer
|
77
|
+
def pushBuffer(iBuffer)
|
78
|
+
# Write data in the current buffer
|
79
|
+
@Buffer += iBuffer
|
80
|
+
@IdxCurrentBufferSample += iBuffer.size/@Header.NbrChannels
|
81
|
+
if (@IdxCurrentBufferSample >= @NbrSamplesPerBuffer)
|
82
|
+
# We have to flush the buffer
|
83
|
+
flushBuffer
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Add a raw buffer
|
88
|
+
#
|
89
|
+
# Parameters:
|
90
|
+
# * *iRawBuffer* (_String_): The raw buffer
|
91
|
+
def pushRawBuffer(iRawBuffer)
|
92
|
+
# First, flush eventually remaining buffer to encode
|
93
|
+
if (!@Buffer.empty?)
|
94
|
+
flushBuffer
|
95
|
+
end
|
96
|
+
# Then write our raw buffer
|
97
|
+
@File.write(iRawBuffer)
|
98
|
+
updateProgress(iRawBuffer.size/@SampleSize)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Loop on a range of samples split into buffers
|
102
|
+
#
|
103
|
+
# Parameters:
|
104
|
+
# * *iIdxBeginSample* (_Integer_): The beginning sample
|
105
|
+
# * *iIdxEndSample* (_Integer_): The ending sample
|
106
|
+
# * _CodeBlock_: The code called for each buffer:
|
107
|
+
# ** *iIdxBeginBufferSample* (_Integer_): The beginning of this buffer's sample
|
108
|
+
# ** *iIdxEndBufferSample* (_Integer_): The ending of this buffer's sample
|
109
|
+
def eachBuffer(iIdxBeginSample, iIdxEndSample)
|
110
|
+
lIdxBeginBufferSample = iIdxBeginSample
|
111
|
+
while (lIdxBeginBufferSample <= iIdxEndSample)
|
112
|
+
lIdxEndBufferSample = lIdxBeginBufferSample + @NbrSamplesPerBuffer - 1
|
113
|
+
if (lIdxEndBufferSample > iIdxEndSample)
|
114
|
+
lIdxEndBufferSample = iIdxEndSample
|
115
|
+
end
|
116
|
+
yield(lIdxBeginBufferSample, lIdxEndBufferSample)
|
117
|
+
lIdxBeginBufferSample = lIdxEndBufferSample + 1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
# Write the buffer to the disk
|
124
|
+
def flushBuffer
|
125
|
+
# Write it
|
126
|
+
@File.write(@Header.getEncodedString(@Buffer))
|
127
|
+
updateProgress(@Buffer.size/@Header.NbrChannels)
|
128
|
+
@IdxCurrentBufferSample = 0
|
129
|
+
@Buffer = []
|
130
|
+
end
|
131
|
+
|
132
|
+
# Add a samples' number to the progression
|
133
|
+
#
|
134
|
+
# Parameters:
|
135
|
+
# * *iNbrSamples* (_Integer_): Number of samples
|
136
|
+
def updateProgress(iNbrSamples)
|
137
|
+
@NbrSamplesWritten += iNbrSamples
|
138
|
+
$stdout.write("[#{(@NbrSamplesWritten*100)/@NbrSamples}%]\015")
|
139
|
+
$stdout.flush
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
# Class reading RIFF files
|
9
|
+
class RIFFReader
|
10
|
+
|
11
|
+
# Constructor
|
12
|
+
#
|
13
|
+
# Parameters:
|
14
|
+
# * *iFile* (_IO_): File to read
|
15
|
+
def initialize(iFile)
|
16
|
+
@File = iFile
|
17
|
+
end
|
18
|
+
|
19
|
+
# Position the file on the data associated to a given RIFF name
|
20
|
+
#
|
21
|
+
# Parameters:
|
22
|
+
# * *iRIFFName* (_String_): The RIFF name
|
23
|
+
# Return:
|
24
|
+
# * _Exception_: An error, or nil in case of success
|
25
|
+
# * _Integer_: The RIFF chunk size
|
26
|
+
def setFilePos(iRIFFName)
|
27
|
+
rError = nil
|
28
|
+
rSize = nil
|
29
|
+
|
30
|
+
# Loop through the names until we find ours
|
31
|
+
@File.seek(12)
|
32
|
+
lRIFFName, rSize = @File.read(8).unpack('a4V')
|
33
|
+
lCurrentPos = 20
|
34
|
+
while (lRIFFName != nil)
|
35
|
+
if (lRIFFName == iRIFFName)
|
36
|
+
# We are positioned correctly
|
37
|
+
lRIFFName = nil
|
38
|
+
logDebug "Found RIFF chunk #{iRIFFName} of size #{rSize}"
|
39
|
+
else
|
40
|
+
logDebug "Skip RIFF chunk #{lRIFFName} of size #{rSize}"
|
41
|
+
# Go to the next chunk
|
42
|
+
@File.seek(lCurrentPos + rSize)
|
43
|
+
lData = @File.read(8)
|
44
|
+
lCurrentPos += rSize + 8
|
45
|
+
if (lData == nil)
|
46
|
+
# End of the file
|
47
|
+
rError = RuntimeError.new("End of file met: no RIFF #{iRIFFName} chunk found.")
|
48
|
+
lRIFFName = nil
|
49
|
+
else
|
50
|
+
lRIFFName, rSize = lData.unpack('a4V')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
return rError, rSize
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|