JOCLoudness 1.0.2 → 1.0.3
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.
- checksums.yaml +4 -4
- data/lib/WavReader/wavfile.rb +173 -0
- data/lib/WavReader/wavheader.rb +47 -0
- data/lib/WavReader/wavsamples.rb +46 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cd5d2552d8fb90f3fbc2eadfaa80d37285c3120
|
4
|
+
data.tar.gz: dc05cf8feb070410238e93fcb6a08899a96efccd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44d689ed177c7115f5a94b6fa7dbb0222fd1032070b8a677e61f478e33a2cf33dfefa6019b4a96e092c061e17d565763870367d69c85b3062f918a3b34946fd9
|
7
|
+
data.tar.gz: 3bf8dc5ea09ce4ecd48d0762200b41a13fd5f7a16ff17dbfb5ad45604b9265086a8ab96e28fc695f49642e1b38f65e31661cfb30e4ec0e5a9145c2a5ae86011e
|
@@ -0,0 +1,173 @@
|
|
1
|
+
#file: wavfile.rb
|
2
|
+
require_relative './wavheader'
|
3
|
+
require_relative './wavsamples'
|
4
|
+
|
5
|
+
#Wavfile class, used to read an audio wav file
|
6
|
+
#It is able to read wav files with:
|
7
|
+
#* Any sampling frequency
|
8
|
+
#* Any number of channels
|
9
|
+
#* PCM 8,16,24 bits per sample
|
10
|
+
#* FLOAT 36 bits per sample
|
11
|
+
#*Headers of 16, 18, 40 bytes
|
12
|
+
class Wavfile
|
13
|
+
|
14
|
+
#Initialize wavreader
|
15
|
+
# @param filename [String] sets the path audio file to read. Example "c:\audio\test.wav"
|
16
|
+
def initialize(filename)
|
17
|
+
@filename = filename
|
18
|
+
@mainheader = nil
|
19
|
+
@logger = nil
|
20
|
+
@wavfile = nil
|
21
|
+
|
22
|
+
@lHeaderOffsetbytes = 0;
|
23
|
+
end
|
24
|
+
|
25
|
+
# Set logger (optional)
|
26
|
+
# @param logger [Logger] a referce to Logger class
|
27
|
+
def Setlogger(logger)
|
28
|
+
@logger = logger
|
29
|
+
end
|
30
|
+
|
31
|
+
# Reads the wav header file
|
32
|
+
def ReadHeader
|
33
|
+
Log(Logger::DEBUG,"Start reading wav header of #{@filename}")
|
34
|
+
|
35
|
+
begin
|
36
|
+
#Read wav header
|
37
|
+
@mainheader = nil
|
38
|
+
@mainheader = Wavheader.new
|
39
|
+
|
40
|
+
@wavfile = File.open(@filename, 'r')
|
41
|
+
@mainheader.read(@wavfile)
|
42
|
+
|
43
|
+
@lHeaderOffsetbytes = @mainheader.cfirstdatabyte.abs_offset;
|
44
|
+
|
45
|
+
Log(Logger::DEBUG,"lHeaderOffsetbytes: #{@lHeaderOffsetbytes}")
|
46
|
+
|
47
|
+
rescue Exception => e
|
48
|
+
Log(Logger::ERROR,"Error reading wav header of #{e.message}, Trace: #{e.backtrace.inspect}")
|
49
|
+
end
|
50
|
+
|
51
|
+
Log(Logger::DEBUG,@mainheader)
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns audio file information
|
56
|
+
# @return [Array] with sampling frecuency and number of channels [fs nch]
|
57
|
+
def GetFileInfo
|
58
|
+
return [@mainheader.ulSampleRate,@mainheader.nchannels]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns audio samples array
|
62
|
+
# @param n [int] sample index (starts in n = 0)
|
63
|
+
# @param bNormalize [Bollean] if normalize == true the returned samples are normalized (max value = 1.0), if not the original readed value us returned
|
64
|
+
# @return [Array] with audio samples (1 sample per channel). Example [0.323 0.322]
|
65
|
+
def GetAudioSamples (sampleindex, bNormalize = true)
|
66
|
+
if (@wavfile == nil)
|
67
|
+
Log(Logger::WARN, "The file is not opened")
|
68
|
+
else
|
69
|
+
begin
|
70
|
+
Log(Logger::DEBUG,"Start reading sample pos #{@sampleindex}")
|
71
|
+
|
72
|
+
#Seek to sample position channel 0
|
73
|
+
lsamplesizebytes = (@mainheader.sBitsPerSample / 8)
|
74
|
+
loffsetbytes = @lHeaderOffsetbytes + sampleindex * (@mainheader.nchannels * lsamplesizebytes)
|
75
|
+
|
76
|
+
Log(Logger::DEBUG,"loffsetbytes: #{loffsetbytes} of #{@wavfile.size}")
|
77
|
+
|
78
|
+
if (loffsetbytes >= @wavfile.size)
|
79
|
+
Log(Logger::DEBUG,"EOF reached!")
|
80
|
+
nil
|
81
|
+
else
|
82
|
+
@wavfile.seek(loffsetbytes)
|
83
|
+
|
84
|
+
#Create PCM samples
|
85
|
+
samples = nil
|
86
|
+
nmax = 1;
|
87
|
+
|
88
|
+
if (@mainheader.nformattag == Wavheader::PCM)
|
89
|
+
#Read PCM sample 8 bits/sample (-128 ... 0 ... +127)
|
90
|
+
if (@mainheader.sBitsPerSample == 8)
|
91
|
+
samples = Wavsample8b.new(:num_channels => @mainheader.nchannels)
|
92
|
+
nmax = 128
|
93
|
+
end
|
94
|
+
#Read PCM sample 16 bits/sample (-32768 ... 0 ... +32767)
|
95
|
+
if (@mainheader.sBitsPerSample == 16)
|
96
|
+
samples = Wavsample16b.new(:num_channels => @mainheader.nchannels)
|
97
|
+
nmax = 32768
|
98
|
+
end
|
99
|
+
#Read PCM sample 24 bits/sample (-8388608 ... 0 ... +8388607)
|
100
|
+
if (@mainheader.sBitsPerSample == 24)
|
101
|
+
samples = Wavsample24b.new(:num_channels => @mainheader.nchannels)
|
102
|
+
nmax = 8388608
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#Create FLOAT samples
|
107
|
+
if (@mainheader.nformattag == Wavheader::FLOAT)
|
108
|
+
samples = WavsampleFloat.new(:num_channels => @mainheader.nchannels)
|
109
|
+
end
|
110
|
+
|
111
|
+
if (samples != nil)
|
112
|
+
#Read sample from file
|
113
|
+
samples.read(@wavfile)
|
114
|
+
else
|
115
|
+
raise 'Sample not compatible (Is not PCM neither FLOAT)'
|
116
|
+
end
|
117
|
+
|
118
|
+
Log(Logger::DEBUG,samples)
|
119
|
+
|
120
|
+
samplesRetArray = samples.samples
|
121
|
+
|
122
|
+
if (samplesRetArray != nil) and (@mainheader.nformattag == Wavheader::PCM) and (bNormalize == true)
|
123
|
+
samplesRetArray = samplesRetArray.collect {|x| x.to_f / nmax.to_f}
|
124
|
+
end
|
125
|
+
|
126
|
+
Log(Logger::DEBUG,"Samples normalized = #{samplesRetArray.to_s}")
|
127
|
+
|
128
|
+
samplesRetArray
|
129
|
+
|
130
|
+
end
|
131
|
+
rescue Exception => e
|
132
|
+
Log(Logger::ERROR,"Error reading wav sample in pos #{sampleindex}. Error: #{e.message}, Trace: #{e.backtrace.inspect}")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Close the audio opened file
|
138
|
+
def Close
|
139
|
+
Log(Logger::DEBUG,"Start closing #{@filename}")
|
140
|
+
|
141
|
+
if (@wavfile != nil)
|
142
|
+
@wavfile.close
|
143
|
+
@wavfile = nil
|
144
|
+
end
|
145
|
+
|
146
|
+
Log(Logger::DEBUG,"Closed: #{@filename}")
|
147
|
+
|
148
|
+
@filename = nil
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def Log (type, message)
|
154
|
+
|
155
|
+
if (@logger != nil)
|
156
|
+
if (type == Logger::FATAL)
|
157
|
+
@logger.fatal(message)
|
158
|
+
end
|
159
|
+
if (type == Logger::ERROR)
|
160
|
+
@logger.error(message)
|
161
|
+
end
|
162
|
+
if (type == Logger::WARN)
|
163
|
+
@logger.warn(message)
|
164
|
+
end
|
165
|
+
if (type == Logger::INFO)
|
166
|
+
@logger.info(message)
|
167
|
+
end
|
168
|
+
if (type == Logger::DEBUG)
|
169
|
+
@logger.debug(message)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#file: wavheader.rb
|
2
|
+
require 'bindata'
|
3
|
+
|
4
|
+
# define main wav header
|
5
|
+
class Wavheader < BinData::Record
|
6
|
+
hide :cfirstdatabyte
|
7
|
+
|
8
|
+
PCM = 1
|
9
|
+
FLOAT = 3
|
10
|
+
|
11
|
+
#WAV header
|
12
|
+
endian :little
|
13
|
+
|
14
|
+
string :cid, :read_length => 4, :asserted_value => 'RIFF'
|
15
|
+
uint32 :ulChunksSizeTotal
|
16
|
+
string :cidwave, :read_length => 4, :asserted_value => 'WAVE'
|
17
|
+
string :cidfmt, :read_length => 4, :asserted_value => 'fmt '
|
18
|
+
uint32 :ulChunkSize
|
19
|
+
|
20
|
+
uint16 :nformattag #1 = PCM, 2 = FLOAT
|
21
|
+
uint16 :nchannels #Number of channels
|
22
|
+
uint32 :ulSampleRate #Sample rate
|
23
|
+
uint32 :ulAvgBytesSec #Bytes per sec avg
|
24
|
+
uint16 :sBlockAlign #Bytes x sample * num channels
|
25
|
+
uint16 :sBitsPerSample #bits per sample
|
26
|
+
|
27
|
+
# The following fields are optional depending on ulChunkSize
|
28
|
+
|
29
|
+
struct :subheader18, :onlyif => lambda {ulChunkSize == 18} do
|
30
|
+
uint16 :sSizeofExtension #Must be 2 end
|
31
|
+
end
|
32
|
+
|
33
|
+
struct :subheader40, :onlyif => lambda {ulChunkSize == 40} do
|
34
|
+
uint16 :sSizeofExtension, :asserted_value => 22
|
35
|
+
uint16 :sValidbitspersample #Valid bits per sample
|
36
|
+
uint32 :ulChannelmask #Speaker position mask (Use to be 0)
|
37
|
+
string :cGuidSubFormat, :read_length => 16 #GUID data format code
|
38
|
+
string :cfact, :read_length => 4, :asserted_value => 'fact'
|
39
|
+
uint32 :lChunkFactSize, :read_length => 4, :asserted_value => 4
|
40
|
+
uint32 :lSampleLength, :read_length => 4 #Number of samples (per channel)
|
41
|
+
end
|
42
|
+
|
43
|
+
string :cdata, :read_length => 4, :asserted_value => 'data'
|
44
|
+
uint32 :uDataChunkSize
|
45
|
+
|
46
|
+
uint8 :cfirstdatabyte
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#file: wavsamples.rb
|
2
|
+
require 'bindata'
|
3
|
+
|
4
|
+
# define wav 8b per sample
|
5
|
+
class Wavsample8b < BinData::Record
|
6
|
+
#WAV sample 8bits per sample
|
7
|
+
mandatory_parameter :num_channels
|
8
|
+
endian :little
|
9
|
+
|
10
|
+
array :samples, :initial_length => :num_channels do
|
11
|
+
int8 :s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# define wav 16b per sample
|
16
|
+
class Wavsample16b < BinData::Record
|
17
|
+
#WAV sample 16bits per sample
|
18
|
+
mandatory_parameter :num_channels
|
19
|
+
endian :little
|
20
|
+
|
21
|
+
array :samples, :initial_length => :num_channels do
|
22
|
+
int16 :s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# define wav 24b per sample
|
27
|
+
class Wavsample24b < BinData::Record
|
28
|
+
#WAV sample 24bits per sample
|
29
|
+
mandatory_parameter :num_channels
|
30
|
+
endian :little
|
31
|
+
|
32
|
+
array :samples, :initial_length => :num_channels do
|
33
|
+
int24 :s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# define wav IEEE FLOAT per sample
|
38
|
+
class WavsampleFloat < BinData::Record
|
39
|
+
#WAV sample FLOAT
|
40
|
+
mandatory_parameter :num_channels
|
41
|
+
endian :little
|
42
|
+
|
43
|
+
array :samples, :initial_length => :num_channels do
|
44
|
+
float :s
|
45
|
+
end
|
46
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: JOCLoudness
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordi Cenzano
|
@@ -44,6 +44,9 @@ files:
|
|
44
44
|
- lib/Loudness/Mean/MeanFast.rb
|
45
45
|
- lib/Loudness/PreFilter/PREFilter.rb
|
46
46
|
- lib/Loudness/RlbFilter/RLBFilter.rb
|
47
|
+
- lib/WavReader/wavfile.rb
|
48
|
+
- lib/WavReader/wavheader.rb
|
49
|
+
- lib/WavReader/wavsamples.rb
|
47
50
|
homepage: http://rubygems.org/gems/JOCLoudness
|
48
51
|
licenses:
|
49
52
|
- MIT
|