WaveSwissKnife 0.2.0.20120302
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +4 -0
- data/ChangeLog +31 -0
- data/Credits +3 -0
- data/LICENSE +31 -0
- data/README +15 -0
- data/ReleaseInfo +8 -0
- data/bin/WSK.rb +14 -0
- data/ext/WSK/AnalyzeUtils/AnalyzeUtils.c +272 -0
- data/ext/WSK/AnalyzeUtils/extconf.rb +7 -0
- data/ext/WSK/ArithmUtils/ArithmUtils.c +862 -0
- data/ext/WSK/ArithmUtils/extconf.rb +15 -0
- data/ext/WSK/CommonBuild.rb +29 -0
- data/ext/WSK/FFTUtils/FFTUtils.c +662 -0
- data/ext/WSK/FFTUtils/extconf.rb +15 -0
- data/ext/WSK/FunctionUtils/FunctionUtils.c +182 -0
- data/ext/WSK/FunctionUtils/extconf.rb +15 -0
- data/ext/WSK/SilentUtils/SilentUtils.c +431 -0
- data/ext/WSK/SilentUtils/extconf.rb +7 -0
- data/ext/WSK/VolumeUtils/VolumeUtils.c +494 -0
- data/ext/WSK/VolumeUtils/extconf.rb +15 -0
- data/external/CommonUtils/build.rb +28 -0
- data/external/CommonUtils/include/CommonUtils.h +177 -0
- data/external/CommonUtils/src/CommonUtils.c +639 -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 +155 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module Actions
|
9
|
+
|
10
|
+
class ConstantCompare
|
11
|
+
|
12
|
+
include WSK::Common
|
13
|
+
|
14
|
+
# Get the number of samples that will be written.
|
15
|
+
# This is called before execute, as it is needed to write the output file.
|
16
|
+
# It is possible to give a majoration: it will be padded with silence.
|
17
|
+
#
|
18
|
+
# Parameters::
|
19
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
20
|
+
# Return::
|
21
|
+
# * _Integer_: The number of samples to be written
|
22
|
+
def get_nbr_samples(iInputData)
|
23
|
+
return 0
|
24
|
+
end
|
25
|
+
|
26
|
+
# Execute
|
27
|
+
#
|
28
|
+
# Parameters::
|
29
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
30
|
+
# * *oOutputData* (_Object_): The output data to fill
|
31
|
+
# Return::
|
32
|
+
# * _Exception_: An error, or nil if success
|
33
|
+
def execute(iInputData, oOutputData)
|
34
|
+
if (iInputData.NbrSamples != @NbrSamples)
|
35
|
+
log_err "Input data has #{iInputData.NbrSamples} samples. It should be #{@NbrSamples}"
|
36
|
+
end
|
37
|
+
lRawSample = iInputData.Header.getEncodedString([@Value]*iInputData.Header.NbrChannels)
|
38
|
+
lCompareBuffer = nil
|
39
|
+
lNbrSamplesProcessed = 0
|
40
|
+
iInputData.each_raw_buffer do |iRawBuffer, iNbrSamples, iNbrChannels|
|
41
|
+
if ((lCompareBuffer == nil) or
|
42
|
+
(lCompareBuffer.size != iRawBuffer.size))
|
43
|
+
# Create the comparison buffer
|
44
|
+
lCompareBuffer = lRawSample*iNbrSamples
|
45
|
+
end
|
46
|
+
if (lCompareBuffer != iRawBuffer)
|
47
|
+
log_err "Differences found between samples #{lNbrSamplesProcessed} and #{lNbrSamplesProcessed+iNbrSamples-1}"
|
48
|
+
end
|
49
|
+
lNbrSamplesProcessed += iNbrSamples
|
50
|
+
$stdout.write("#{(lNbrSamplesProcessed*100)/iInputData.NbrSamples} %\015")
|
51
|
+
$stdout.flush
|
52
|
+
end
|
53
|
+
|
54
|
+
return nil
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
{
|
7
|
+
:OutputInterface => 'DirectStream',
|
8
|
+
:Options => {
|
9
|
+
:BeginSample => [
|
10
|
+
'--begin <BeginSample>', String,
|
11
|
+
'<BeginSample>: Index of sample to begin with [default = 0]. Can be specified in float seconds (ie. 12.3s).',
|
12
|
+
'Specify the first sample to write'
|
13
|
+
],
|
14
|
+
:EndSample => [
|
15
|
+
'--end <EndSample>', String,
|
16
|
+
'<EndSample>: Index of sample to end with [default = 256]. Can be specified in float seconds (ie. 12.3s).',
|
17
|
+
'Specify the last sample to write'
|
18
|
+
]
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module Actions
|
9
|
+
|
10
|
+
class Cut
|
11
|
+
|
12
|
+
include WSK::Common
|
13
|
+
|
14
|
+
# Get the number of samples that will be written.
|
15
|
+
# This is called before execute, as it is needed to write the output file.
|
16
|
+
# It is possible to give a majoration: it will be padded with silence.
|
17
|
+
#
|
18
|
+
# Parameters::
|
19
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
20
|
+
# Return::
|
21
|
+
# * _Integer_: The number of samples to be written
|
22
|
+
def get_nbr_samples(iInputData)
|
23
|
+
@IdxBeginSample = readDuration(@BeginSample, iInputData.Header.SampleRate)
|
24
|
+
@IdxEndSample = readDuration(@EndSample, iInputData.Header.SampleRate)
|
25
|
+
|
26
|
+
return @IdxEndSample-@IdxBeginSample+1
|
27
|
+
end
|
28
|
+
|
29
|
+
# Execute
|
30
|
+
#
|
31
|
+
# Parameters::
|
32
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
33
|
+
# * *oOutputData* (_Object_): The output data to fill
|
34
|
+
# Return::
|
35
|
+
# * _Exception_: An error, or nil if success
|
36
|
+
def execute(iInputData, oOutputData)
|
37
|
+
lChannelsSampleSize = (iInputData.Header.NbrChannels*iInputData.Header.NbrBitsPerSample)/8
|
38
|
+
lIdxFirstSample = @IdxBeginSample
|
39
|
+
iInputData.each_raw_buffer(@IdxBeginSample) do |iInputRawBuffer, iNbrSamples, iNbrChannels|
|
40
|
+
# If the end sample is in this buffer, write only up to it
|
41
|
+
if (@IdxEndSample < lIdxFirstSample + iNbrSamples - 1)
|
42
|
+
oOutputData.pushRawBuffer(iInputRawBuffer[0..(@IdxEndSample-lIdxFirstSample+1)*lChannelsSampleSize-1])
|
43
|
+
else
|
44
|
+
oOutputData.pushRawBuffer(iInputRawBuffer)
|
45
|
+
end
|
46
|
+
if (@IdxEndSample < lIdxFirstSample + iNbrSamples)
|
47
|
+
# Nothing left to write
|
48
|
+
break
|
49
|
+
end
|
50
|
+
lIdxFirstSample += iNbrSamples
|
51
|
+
end
|
52
|
+
|
53
|
+
return nil
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
{
|
7
|
+
:OutputInterface => 'DirectStream',
|
8
|
+
:Options => {
|
9
|
+
:SilenceThreshold => [
|
10
|
+
'--silencethreshold <SilenceThreshold>', String,
|
11
|
+
'<SilenceThreshold>: Threshold to use to identify silent parts [default = 0]. It is possible to specify several values, for each channel, sperated with | (ie. 34|35). It is also possible to specify a range instead of a threshold with , (ie. -128,126 or -128,126|-127,132)',
|
12
|
+
'Specify the silence threshold'
|
13
|
+
],
|
14
|
+
:NoiseFFTFileName => [
|
15
|
+
'--noisefft <FFTFile>', String,
|
16
|
+
'<FFTFile>: File containing the FFT profile of the reference noise. Can be set to \'none\' if no file.',
|
17
|
+
'This is used to compare potential noise profile with the real noise profile.'
|
18
|
+
],
|
19
|
+
:SilenceMin => [
|
20
|
+
'--silencemin <SilenceDuration>', String,
|
21
|
+
'<SilenceDuration>: Silence duration in samples or in float seconds (ie. 234 or 25.3s).',
|
22
|
+
'Specify the minimum duration a silent part must have to be interpreted as a silence.'
|
23
|
+
],
|
24
|
+
}
|
25
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module Actions
|
9
|
+
|
10
|
+
class CutFirstSignal
|
11
|
+
|
12
|
+
include WSK::Common
|
13
|
+
include WSK::FFT
|
14
|
+
|
15
|
+
# Get the number of samples that will be written.
|
16
|
+
# This is called before execute, as it is needed to write the output file.
|
17
|
+
# It is possible to give a majoration: it will be padded with silence.
|
18
|
+
#
|
19
|
+
# Parameters::
|
20
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
21
|
+
# Return::
|
22
|
+
# * _Integer_: The number of samples to be written
|
23
|
+
def get_nbr_samples(iInputData)
|
24
|
+
@IdxStartSample = 0
|
25
|
+
lSilenceThresholds = readThresholds(@SilenceThreshold, iInputData.Header.NbrChannels)
|
26
|
+
# Find the first signal
|
27
|
+
lIdxSignalSample, lIdxNextAboveThresholds = getNextNonSilentSample(iInputData, 0, lSilenceThresholds, nil, nil, false)
|
28
|
+
if (lIdxSignalSample == nil)
|
29
|
+
log_warn 'No signal found. Keeping the whole file.'
|
30
|
+
else
|
31
|
+
lNoiseFFTMaxDistance, lNoiseFFTProfile = readFFTProfile(@NoiseFFTFileName)
|
32
|
+
lSilenceDuration = readDuration(@SilenceMin, iInputData.Header.SampleRate)
|
33
|
+
lIdxSilenceSample, lSilenceLength, lIdxNextAboveThresholds = getNextSilentSample(iInputData, lIdxSignalSample, lSilenceThresholds, lSilenceDuration, lNoiseFFTProfile, lNoiseFFTMaxDistance, false)
|
34
|
+
if (lIdxSilenceSample == nil)
|
35
|
+
log_warn "No silence found after the signal beginning at #{lIdxSignalSample}. Keeping the whole file."
|
36
|
+
elsif (lSilenceLength == nil)
|
37
|
+
# Find the silence length by parsing following data
|
38
|
+
lIdxNonSilentSample, lIdxNextAboveThresholds = getNextNonSilentSample(iInputData, lIdxSilenceSample+1, lSilenceThresholds, lNoiseFFTProfile, lNoiseFFTMaxDistance, false)
|
39
|
+
if (lIdxNonSilentSample == nil)
|
40
|
+
# The file should be empty
|
41
|
+
@IdxStartSample = iInputData.NbrSamples-1
|
42
|
+
else
|
43
|
+
@IdxStartSample = lIdxNonSilentSample
|
44
|
+
end
|
45
|
+
else
|
46
|
+
@IdxStartSample = lIdxSilenceSample + lSilenceLength
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
return iInputData.NbrSamples-@IdxStartSample
|
51
|
+
end
|
52
|
+
|
53
|
+
# Execute
|
54
|
+
#
|
55
|
+
# Parameters::
|
56
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
57
|
+
# * *oOutputData* (_Object_): The output data to fill
|
58
|
+
# Return::
|
59
|
+
# * _Exception_: An error, or nil if success
|
60
|
+
def execute(iInputData, oOutputData)
|
61
|
+
iInputData.each_raw_buffer(@IdxStartSample) do |iInputRawBuffer, iNbrSamples, iNbrChannels|
|
62
|
+
oOutputData.pushRawBuffer(iInputRawBuffer)
|
63
|
+
end
|
64
|
+
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
{
|
7
|
+
:OutputInterface => 'DirectStream',
|
8
|
+
:Options => {
|
9
|
+
:Offset => [
|
10
|
+
'--offset <DCOffset>', String,
|
11
|
+
'<DCOffset>: Offset to use for the shift [default = 0]. It is possible to specify several values, for each channel, sperated with | (ie. 34|35).',
|
12
|
+
'Specify the offset'
|
13
|
+
]
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module Actions
|
9
|
+
|
10
|
+
class DCShifter
|
11
|
+
|
12
|
+
include WSK::Maps
|
13
|
+
|
14
|
+
# Get the number of samples that will be written.
|
15
|
+
# This is called before execute, as it is needed to write the output file.
|
16
|
+
# It is possible to give a majoration: it will be padded with silence.
|
17
|
+
#
|
18
|
+
# Parameters::
|
19
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
20
|
+
# Return::
|
21
|
+
# * _Integer_: The number of samples to be written
|
22
|
+
def get_nbr_samples(iInputData)
|
23
|
+
return iInputData.NbrSamples
|
24
|
+
end
|
25
|
+
|
26
|
+
# Execute
|
27
|
+
#
|
28
|
+
# Parameters::
|
29
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
30
|
+
# * *oOutputData* (_Object_): The output data to fill
|
31
|
+
# Return::
|
32
|
+
# * _Exception_: An error, or nil if success
|
33
|
+
def execute(iInputData, oOutputData)
|
34
|
+
# The offset, per channel
|
35
|
+
# list< Integer >
|
36
|
+
lOffsets = nil
|
37
|
+
if (@Offset.split('|').size == 1)
|
38
|
+
lOffsets = [@Offset.to_i] * iInputData.Header.NbrChannels
|
39
|
+
else
|
40
|
+
lOffsets = @Offset.split('|').map { |iStrValue| iStrValue.to_i }
|
41
|
+
end
|
42
|
+
|
43
|
+
# List of functions to apply, per channel
|
44
|
+
lMaxValue = 2**(iInputData.Header.NbrBitsPerSample-1) - 1
|
45
|
+
lMinValue = -2**(iInputData.Header.NbrBitsPerSample-1)
|
46
|
+
lFunctions = []
|
47
|
+
lOffsets.each do |iOffset|
|
48
|
+
lFunctions << {
|
49
|
+
:FunctionType => WSK::Functions::FCTTYPE_PIECEWISE_LINEAR,
|
50
|
+
:MinValue => lMinValue,
|
51
|
+
:MaxValue => lMaxValue,
|
52
|
+
:Points => {
|
53
|
+
lMinValue => lMinValue + iOffset,
|
54
|
+
lMaxValue => lMaxValue + iOffset
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
apply_map_functions(iInputData, oOutputData, lFunctions)
|
59
|
+
|
60
|
+
return nil
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
{
|
7
|
+
:OutputInterface => 'DirectStream',
|
8
|
+
:Options => {
|
9
|
+
:FctFileName => [
|
10
|
+
'--function <FunctionFileName>', String,
|
11
|
+
'<FunctionFileName>: File containing the function definition',
|
12
|
+
'Specify the function to draw'
|
13
|
+
],
|
14
|
+
:UnitDB => [
|
15
|
+
'--unitdb <Switch>', Integer,
|
16
|
+
'<Switch>: 0 means that units used in the function are ratios. 1 means that units used in the functions are db.',
|
17
|
+
'Specify the unit used in the function'
|
18
|
+
]
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module Actions
|
9
|
+
|
10
|
+
class DrawFct
|
11
|
+
|
12
|
+
include WSK::Common
|
13
|
+
include WSK::Functions
|
14
|
+
|
15
|
+
# Get the number of samples that will be written.
|
16
|
+
# This is called before execute, as it is needed to write the output file.
|
17
|
+
# It is possible to give a majoration: it will be padded with silence.
|
18
|
+
#
|
19
|
+
# Parameters::
|
20
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
21
|
+
# Return::
|
22
|
+
# * _Integer_: The number of samples to be written
|
23
|
+
def get_nbr_samples(iInputData)
|
24
|
+
@Function = WSK::Functions::Function.new
|
25
|
+
@Function.read_from_file(@FctFileName)
|
26
|
+
lMinX, lMinY, lMaxX, lMaxY = @Function.get_bounds
|
27
|
+
@NbrSamplesOut = lMaxX.to_i-lMinX.to_i+1
|
28
|
+
|
29
|
+
return @NbrSamplesOut
|
30
|
+
end
|
31
|
+
|
32
|
+
# Execute
|
33
|
+
#
|
34
|
+
# Parameters::
|
35
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
36
|
+
# * *oOutputData* (_Object_): The output data to fill
|
37
|
+
# Return::
|
38
|
+
# * _Exception_: An error, or nil if success
|
39
|
+
def execute(iInputData, oOutputData)
|
40
|
+
rError = nil
|
41
|
+
|
42
|
+
# Then draw it
|
43
|
+
lMaxY = @Function.get_bounds[3]
|
44
|
+
if (@UnitDB == 1)
|
45
|
+
lMaxY = (2**(lMaxY.to_f/6)).to_r
|
46
|
+
end
|
47
|
+
lMedianValue = ((2**(iInputData.Header.NbrBitsPerSample-1)-1)/lMaxY).to_i
|
48
|
+
log_info "Draw function with maximal ratio #{lMaxY.to_f}, using median value #{lMedianValue}"
|
49
|
+
# Take the median value as a fraction of the maximal value
|
50
|
+
@Function.draw(iInputData, oOutputData, 0, @NbrSamplesOut-1, (@UnitDB == 1), lMedianValue)
|
51
|
+
|
52
|
+
return rError
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module Actions
|
9
|
+
|
10
|
+
class FFT
|
11
|
+
|
12
|
+
include WSK::Common
|
13
|
+
include WSK::FFT
|
14
|
+
|
15
|
+
# Get the number of samples that will be written.
|
16
|
+
# This is called before execute, as it is needed to write the output file.
|
17
|
+
# It is possible to give a majoration: it will be padded with silence.
|
18
|
+
#
|
19
|
+
# Parameters::
|
20
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
21
|
+
# Return::
|
22
|
+
# * _Integer_: The number of samples to be written
|
23
|
+
def get_nbr_samples(iInputData)
|
24
|
+
return 0
|
25
|
+
end
|
26
|
+
|
27
|
+
# Execute
|
28
|
+
#
|
29
|
+
# Parameters::
|
30
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
31
|
+
# * *oOutputData* (_Object_): The output data to fill
|
32
|
+
# Return::
|
33
|
+
# * _Exception_: An error, or nil if success
|
34
|
+
def execute(iInputData, oOutputData)
|
35
|
+
|
36
|
+
# 1. Create the whole FFT profile
|
37
|
+
log_info 'Creating FFT profile ...'
|
38
|
+
# Object that will create the FFT
|
39
|
+
lFFTComputing = FFTComputing.new(false, iInputData.Header)
|
40
|
+
# Parse the data
|
41
|
+
lIdxSample = 0
|
42
|
+
iInputData.each_raw_buffer do |iInputRawBuffer, iNbrSamples, iNbrChannels|
|
43
|
+
lFFTComputing.completeFFT(iInputRawBuffer, iNbrSamples)
|
44
|
+
lIdxSample += iNbrSamples
|
45
|
+
$stdout.write("#{(lIdxSample*100)/iInputData.NbrSamples} %\015")
|
46
|
+
$stdout.flush
|
47
|
+
end
|
48
|
+
# Compute the result
|
49
|
+
require 'WSK/FFTUtils/FFTUtils'
|
50
|
+
lFFTUtils = FFTUtils::FFTUtils.new
|
51
|
+
lFFTProfile = lFFTComputing.getFFTProfile
|
52
|
+
lFFTReferenceProfile = lFFTUtils.createCFFTProfile(lFFTProfile)
|
53
|
+
|
54
|
+
# 2. Compute the distance obtained by comparing this profile with a normal file pass
|
55
|
+
log_info 'Computing average distance ...'
|
56
|
+
lFFTComputing2 = FFTComputing.new(true, iInputData.Header)
|
57
|
+
lIdxSample = 0
|
58
|
+
lNbrTimes = 0
|
59
|
+
lSumDist = 0
|
60
|
+
while (lIdxSample < iInputData.NbrSamples)
|
61
|
+
# Compute the number of samples needed to have a valid FFT.
|
62
|
+
# Modify this number if it exceeds the range we have
|
63
|
+
lNbrSamplesFFTMax = iInputData.Header.SampleRate/FFTSAMPLE_FREQ
|
64
|
+
lIdxBeginFFTSample = lIdxSample
|
65
|
+
lIdxEndFFTSample = lIdxSample+lNbrSamplesFFTMax-1
|
66
|
+
if (lIdxEndFFTSample >= iInputData.NbrSamples)
|
67
|
+
lIdxEndFFTSample = iInputData.NbrSamples-1
|
68
|
+
end
|
69
|
+
lNbrSamplesFFT = lIdxEndFFTSample-lIdxBeginFFTSample+1
|
70
|
+
# Load an FFT buffer of this
|
71
|
+
lFFTBuffer = ''
|
72
|
+
iInputData.each_raw_buffer(lIdxBeginFFTSample, lIdxEndFFTSample, :nbr_samples_prefetch => iInputData.NbrSamples-lIdxBeginFFTSample) do |iInputRawBuffer, iNbrSamples, iNbrChannels|
|
73
|
+
lFFTBuffer.concat(iInputRawBuffer)
|
74
|
+
end
|
75
|
+
# Compute its FFT profile
|
76
|
+
lFFTComputing2.resetData
|
77
|
+
lFFTComputing2.completeFFT(lFFTBuffer, lNbrSamplesFFT)
|
78
|
+
lSumDist += lFFTUtils.distFFTProfiles(lFFTReferenceProfile, lFFTUtils.createCFFTProfile(lFFTComputing2.getFFTProfile), FFTDIST_MAX).abs
|
79
|
+
lNbrTimes += 1
|
80
|
+
lIdxSample = lIdxEndFFTSample+1
|
81
|
+
$stdout.write("#{(lIdxSample*100)/iInputData.NbrSamples} %\015")
|
82
|
+
$stdout.flush
|
83
|
+
end
|
84
|
+
lAverageDist = lSumDist/lNbrTimes
|
85
|
+
log_debug "Average distance with silence: #{lAverageDist}"
|
86
|
+
|
87
|
+
# Display results
|
88
|
+
(FREQINDEX_FIRST..FREQINDEX_LAST).each_with_index do |iIdx, iIdxFreq|
|
89
|
+
log_debug "[#{(440*(2**(iIdx/12.0))).round} Hz]: #{lFFTProfile[2][iIdxFreq].join(', ')}"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Write the result in a file
|
93
|
+
File.open('fft.result', 'wb') do |oFile|
|
94
|
+
oFile.write(Marshal.dump([lAverageDist, lFFTProfile]))
|
95
|
+
end
|
96
|
+
|
97
|
+
return nil
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module Actions
|
9
|
+
|
10
|
+
class GenAllValues
|
11
|
+
|
12
|
+
MAX_BUFFER_SAMPLES = 65536
|
13
|
+
|
14
|
+
# Get the number of samples that will be written.
|
15
|
+
# This is called before execute, as it is needed to write the output file.
|
16
|
+
# It is possible to give a majoration: it will be padded with silence.
|
17
|
+
#
|
18
|
+
# Parameters::
|
19
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
20
|
+
# Return::
|
21
|
+
# * _Integer_: The number of samples to be written
|
22
|
+
def get_nbr_samples(iInputData)
|
23
|
+
@MaxValue = 2**(iInputData.Header.NbrBitsPerSample-1)-1
|
24
|
+
@MinValue = -2**(iInputData.Header.NbrBitsPerSample-1)
|
25
|
+
|
26
|
+
return @MaxValue-@MinValue+1
|
27
|
+
end
|
28
|
+
|
29
|
+
# Execute
|
30
|
+
#
|
31
|
+
# Parameters::
|
32
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
33
|
+
# * *oOutputData* (_Object_): The output data to fill
|
34
|
+
# Return::
|
35
|
+
# * _Exception_: An error, or nil if success
|
36
|
+
def execute(iInputData, oOutputData)
|
37
|
+
# Create buffer
|
38
|
+
lNbrBuffers = ((@MaxValue-@MinValue+1) / MAX_BUFFER_SAMPLES)+1
|
39
|
+
lSizeofLastBuffer = ((@MaxValue-@MinValue+1) % MAX_BUFFER_SAMPLES)
|
40
|
+
lIdxValue = @MinValue
|
41
|
+
log_debug "Will output #{@MaxValue-@MinValue+1} samples in #{lNbrBuffers} buffers."
|
42
|
+
lNbrBuffers.times do |iIdxBuffer|
|
43
|
+
lBuffer = []
|
44
|
+
lSamplesInBuffer = nil
|
45
|
+
if (iIdxBuffer == lNbrBuffers-1)
|
46
|
+
# The last one
|
47
|
+
lSamplesInBuffer = lSizeofLastBuffer
|
48
|
+
else
|
49
|
+
lSamplesInBuffer = MAX_BUFFER_SAMPLES
|
50
|
+
end
|
51
|
+
lSamplesInBuffer.times do |iIdxSampleBuffer|
|
52
|
+
iInputData.Header.NbrChannels.times do |iIdxChannel|
|
53
|
+
lBuffer << lIdxValue
|
54
|
+
end
|
55
|
+
lIdxValue += 1
|
56
|
+
end
|
57
|
+
oOutputData.pushBuffer(lBuffer)
|
58
|
+
end
|
59
|
+
|
60
|
+
return nil
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
{
|
7
|
+
:OutputInterface => 'DirectStream',
|
8
|
+
:Options => {
|
9
|
+
:Value => [
|
10
|
+
'--value <Value>', Integer,
|
11
|
+
'<Value>: Constant value to write',
|
12
|
+
'Specify the value to write in the wave file.'
|
13
|
+
],
|
14
|
+
:NbrSamples => [
|
15
|
+
'--nbrsamples <NbrSamples>', Integer,
|
16
|
+
'<NbrSamples>: Number of samples used to write this value',
|
17
|
+
'Specify the number of samples during the value will be written.'
|
18
|
+
]
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module WSK
|
7
|
+
|
8
|
+
module Actions
|
9
|
+
|
10
|
+
class GenConstant
|
11
|
+
|
12
|
+
MAX_BUFFER_SAMPLES = 65536
|
13
|
+
|
14
|
+
# Get the number of samples that will be written.
|
15
|
+
# This is called before execute, as it is needed to write the output file.
|
16
|
+
# It is possible to give a majoration: it will be padded with silence.
|
17
|
+
#
|
18
|
+
# Parameters::
|
19
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
20
|
+
# Return::
|
21
|
+
# * _Integer_: The number of samples to be written
|
22
|
+
def get_nbr_samples(iInputData)
|
23
|
+
return @NbrSamples
|
24
|
+
end
|
25
|
+
|
26
|
+
# Execute
|
27
|
+
#
|
28
|
+
# Parameters::
|
29
|
+
# * *iInputData* (<em>WSK::Model::InputData</em>): The input data
|
30
|
+
# * *oOutputData* (_Object_): The output data to fill
|
31
|
+
# Return::
|
32
|
+
# * _Exception_: An error, or nil if success
|
33
|
+
def execute(iInputData, oOutputData)
|
34
|
+
lRawSample = iInputData.Header.getEncodedString([@Value]*iInputData.Header.NbrChannels)
|
35
|
+
# Write complete buffers
|
36
|
+
lNbrCompleteBuffers = @NbrSamples/MAX_BUFFER_SAMPLES
|
37
|
+
if (lNbrCompleteBuffers > 0)
|
38
|
+
lCompleteRawBuffer = lRawSample*MAX_BUFFER_SAMPLES
|
39
|
+
lNbrCompleteBuffers.times do |iIdx|
|
40
|
+
oOutputData.pushRawBuffer(lCompleteRawBuffer)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
# Write last buffer
|
44
|
+
lLastBufferSize = @NbrSamples % MAX_BUFFER_SAMPLES
|
45
|
+
if (lLastBufferSize > 0)
|
46
|
+
oOutputData.pushRawBuffer(lRawSample*lLastBufferSize)
|
47
|
+
end
|
48
|
+
|
49
|
+
return nil
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|