aubio 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/aubio.rb +41 -2
- data/lib/aubio/beats.rb +35 -32
- data/lib/aubio/pitches.rb +40 -32
- data/lib/aubio/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4449b468192ecfde756ebcba885104de2b1e2204
|
4
|
+
data.tar.gz: fac1a109e7dbd00a1c42eec07a708bafc489c0d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1be5f9f1f403087ba3719ea5d9789b870df6349706efcbfef790a0ae5c11876ca86159914d3f3326e7666357b198a0cd07ba3803f6dd97d8a0c59431cfac764a
|
7
|
+
data.tar.gz: 94e78233234035ce70d20d8022198f30136f380bf0d3506d8cd10e6e789aec00ff29cc9154af2fd11aae1bbfc6d47ee62147a6f7170f508ff80582765459099a
|
data/lib/aubio.rb
CHANGED
@@ -40,16 +40,55 @@ module Aubio
|
|
40
40
|
Pitches.new(@source, @params).each
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
43
|
+
def enum_beats
|
44
44
|
check_for_closed
|
45
45
|
|
46
46
|
Beats.new(@source, @params).each
|
47
47
|
end
|
48
48
|
|
49
|
+
def beats
|
50
|
+
check_for_closed
|
51
|
+
|
52
|
+
beats = Beats.new(@source, @params).each.to_a
|
53
|
+
|
54
|
+
# fill in the zero beat
|
55
|
+
beats = beats.unshift(
|
56
|
+
beats.first.merge({
|
57
|
+
confidence: 1,
|
58
|
+
s: 0.0,
|
59
|
+
ms: 0.0,
|
60
|
+
sample_no: 0,
|
61
|
+
rel_start: 0.0
|
62
|
+
})
|
63
|
+
)
|
64
|
+
|
65
|
+
# fetch the rel_end from the next beat
|
66
|
+
# using 1.0 for the last beat
|
67
|
+
beats = beats.each_cons(2).map {|a,b|
|
68
|
+
a.merge({
|
69
|
+
rel_end: (b[:rel_start] || 1.0)
|
70
|
+
})
|
71
|
+
}
|
72
|
+
|
73
|
+
# set minimum inter-onset interval in seconds
|
74
|
+
# allows for 4/4 at 400bpm (faster than most music)
|
75
|
+
# filters beats detected too closely together
|
76
|
+
minioi = @params[:minioi] || 0.15
|
77
|
+
filtered_beats = [beats.first]
|
78
|
+
beats.each do |b|
|
79
|
+
if (b[:s] - filtered_beats.last[:s]) > minioi
|
80
|
+
filtered_beats << b
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# TODO: are there other smoothing methods that would be useful here?
|
85
|
+
filtered_beats
|
86
|
+
end
|
87
|
+
|
49
88
|
def bpm
|
50
89
|
check_for_closed
|
51
90
|
|
52
|
-
beat_locations =
|
91
|
+
beat_locations = self.beats
|
53
92
|
beat_periods = beat_locations.each_cons(2).map {|a,b| b[:s] - a[:s] }
|
54
93
|
|
55
94
|
return 60.0 if beat_locations.length == 1
|
data/lib/aubio/beats.rb
CHANGED
@@ -1,51 +1,54 @@
|
|
1
1
|
module Aubio
|
2
|
-
|
2
|
+
class Beats
|
3
3
|
|
4
|
-
|
4
|
+
def initialize(aubio_source, params)
|
5
5
|
# TODO: cleanup param dups
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
@sample_rate = params[:sample_rate] || 44100
|
7
|
+
@window_size = params[:window_size] || 1024
|
8
|
+
@hop_size = params[:hop_size] || 512
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
@source = aubio_source
|
11
|
+
@tempo = Api.new_aubio_tempo('specdiff', @window_size, @hop_size, @sample_rate)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
# create output for source
|
14
|
+
@sample_buffer = Api.new_fvec(@hop_size)
|
15
|
+
# create output for beat
|
16
|
+
@out_fvec = Api.new_fvec(1)
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
def each
|
20
|
+
return enum_for(:each) unless block_given?
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
total_frames_counter = 0
|
23
|
+
read_buffer = FFI::MemoryPointer.new(:int)
|
24
|
+
total_samples = Api.aubio_source_get_duration(@source).to_f
|
24
25
|
|
25
|
-
|
26
|
-
|
26
|
+
loop do
|
27
|
+
# Perform tempo calculation
|
27
28
|
Api.aubio_source_do(@source, @sample_buffer, read_buffer)
|
28
|
-
|
29
|
+
Api.aubio_tempo_do(@tempo, @sample_buffer, @out_fvec)
|
29
30
|
|
30
31
|
# Retrieve result
|
31
|
-
|
32
|
+
is_beat = Api.fvec_get_sample(@out_fvec, 0)
|
32
33
|
no_of_bytes_read = read_buffer.read_int
|
33
34
|
total_frames_counter += no_of_bytes_read
|
34
35
|
|
35
36
|
if is_beat > 0.0
|
36
|
-
|
37
|
-
|
37
|
+
tempo_samples = Api.aubio_tempo_get_last(@tempo)
|
38
|
+
tempo_seconds = Api.aubio_tempo_get_last_s(@tempo)
|
39
|
+
tempo_milliseconds = Api.aubio_tempo_get_last_ms(@tempo)
|
38
40
|
tempo_confidence = Api.aubio_tempo_get_confidence(@tempo)
|
39
41
|
|
40
|
-
|
42
|
+
output = {
|
41
43
|
:confidence => tempo_confidence,
|
42
44
|
:s => tempo_seconds,
|
43
45
|
:ms => tempo_milliseconds,
|
44
|
-
:
|
45
|
-
:
|
46
|
-
|
46
|
+
:sample_no => tempo_samples,
|
47
|
+
:total_samples => total_samples,
|
48
|
+
:rel_start => tempo_samples/total_samples
|
49
|
+
}
|
47
50
|
yield output
|
48
|
-
|
51
|
+
end
|
49
52
|
|
50
53
|
if no_of_bytes_read != @hop_size
|
51
54
|
# there's no more audio to look at
|
@@ -56,8 +59,8 @@ module Aubio
|
|
56
59
|
:confidence => 1.0,
|
57
60
|
:s => total_time,
|
58
61
|
:ms => total_time/1000.0,
|
59
|
-
:
|
60
|
-
:
|
62
|
+
:sample_no => total_samples,
|
63
|
+
:total_samples => total_samples
|
61
64
|
}
|
62
65
|
yield output
|
63
66
|
|
@@ -68,8 +71,8 @@ module Aubio
|
|
68
71
|
|
69
72
|
break
|
70
73
|
end
|
71
|
-
|
72
|
-
|
74
|
+
end
|
75
|
+
end
|
73
76
|
|
74
|
-
|
77
|
+
end
|
75
78
|
end
|
data/lib/aubio/pitches.rb
CHANGED
@@ -1,34 +1,42 @@
|
|
1
1
|
module Aubio
|
2
|
-
|
2
|
+
class Pitches
|
3
3
|
|
4
|
-
|
4
|
+
def initialize(aubio_source, params)
|
5
5
|
# TODO: cleanup param dups
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
6
|
+
@sample_rate = params[:sample_rate] || 44100
|
7
|
+
@window_size = params[:window_size] || 1024
|
8
|
+
@hop_size = params[:hop_size] || 512
|
9
|
+
|
10
|
+
# Set the tolerance for the pitch detection algorithm.
|
11
|
+
# Typical values range between 0.2 and 0.9.
|
12
|
+
# Pitch candidates found with a confidence less than this threshold will not be selected.
|
13
|
+
# The higher the threshold, the more confidence in the candidates.
|
14
|
+
@confidence_thresh = params[:confidence_thresh] || 0.9
|
15
|
+
|
16
|
+
@pitch_method = params[:pitch_method] || "yinfft"
|
17
|
+
|
18
|
+
@source = aubio_source
|
19
|
+
@pitch = Api.new_aubio_pitch(@pitch_method, @window_size, @hop_size, @sample_rate)
|
20
|
+
Api.aubio_pitch_set_unit(@pitch, 'midi')
|
21
|
+
Api.aubio_pitch_set_tolerance(@pitch, @confidence_thresh)
|
22
|
+
|
23
|
+
# create output for source
|
24
|
+
@sample_buffer = Api.new_fvec(@hop_size)
|
25
|
+
# create output for pitch and beat
|
26
|
+
@out_fvec = Api.new_fvec(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
def each
|
30
|
+
return enum_for(:each) unless block_given?
|
31
|
+
|
32
|
+
total_frames_counter = 0
|
33
|
+
read_buffer = FFI::MemoryPointer.new(:int)
|
26
34
|
last_pitch = 0
|
27
35
|
|
28
|
-
|
29
|
-
|
36
|
+
loop do
|
37
|
+
# Perform pitch calculation
|
30
38
|
Api.aubio_source_do(@source, @sample_buffer, read_buffer)
|
31
|
-
|
39
|
+
Api.aubio_pitch_do(@pitch, @sample_buffer, @out_fvec)
|
32
40
|
|
33
41
|
# Retrieve result
|
34
42
|
pitch = Api.fvec_get_sample(@out_fvec, 0)
|
@@ -36,15 +44,15 @@ module Aubio
|
|
36
44
|
no_of_bytes_read = read_buffer.read_int
|
37
45
|
total_frames_counter += no_of_bytes_read
|
38
46
|
|
39
|
-
if (last_pitch - pitch).abs >= 1 and confidence >
|
40
|
-
|
47
|
+
if (last_pitch - pitch).abs >= 1 and confidence > @confidence_thresh
|
48
|
+
output = {
|
41
49
|
:pitch => pitch,
|
42
50
|
:confidence => confidence,
|
43
51
|
:start => (total_frames_counter == 0 ? 1 : 0),
|
44
52
|
:end => 0
|
45
|
-
|
53
|
+
}
|
46
54
|
yield output
|
47
|
-
|
55
|
+
end
|
48
56
|
|
49
57
|
last_pitch = pitch
|
50
58
|
|
@@ -68,8 +76,8 @@ module Aubio
|
|
68
76
|
|
69
77
|
break
|
70
78
|
end
|
71
|
-
|
72
|
-
|
79
|
+
end
|
80
|
+
end
|
73
81
|
|
74
|
-
|
82
|
+
end
|
75
83
|
end
|
data/lib/aubio/version.rb
CHANGED