aubio 0.3.0 → 0.3.1
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/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