aubio 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +674 -0
- data/README.md +111 -0
- data/Rakefile +10 -0
- data/aubio.gemspec +27 -0
- data/aubio.rb +467 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/aubio.rb +29 -0
- data/lib/aubio/api.rb +104 -0
- data/lib/aubio/onsets.rb +60 -0
- data/lib/aubio/version.rb +3 -0
- metadata +119 -0
data/README.md
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# Aubio
|
2
|
+
## warning: pre-alpha subject to change
|
3
|
+
|
4
|
+
A Ruby binding for the `aubio` library.
|
5
|
+
|
6
|
+
# What is aubio?
|
7
|
+
|
8
|
+
In their own words...
|
9
|
+
|
10
|
+
> aubio is a tool designed for the extraction of annotations from audio signals. Its features include segmenting a sound file before each of its attacks, performing pitch detection, tapping the beat and producing midi streams from live audio.
|
11
|
+
- http://aubio.org/
|
12
|
+
|
13
|
+
## Prerequisites
|
14
|
+
|
15
|
+
`brew install aubio --with-libsndfile --with-fftw --with-libsamplerate`
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'aubio'
|
23
|
+
```
|
24
|
+
|
25
|
+
And then execute:
|
26
|
+
|
27
|
+
$ bundle
|
28
|
+
|
29
|
+
Or install it yourself as:
|
30
|
+
|
31
|
+
$ gem install aubio
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
`Aubio` just needs a path to a sound file:
|
36
|
+
|
37
|
+
```
|
38
|
+
my_file = Aubio.open("/path/to/file")
|
39
|
+
```
|
40
|
+
|
41
|
+
From there you can access the following:
|
42
|
+
|
43
|
+
```
|
44
|
+
my_file.onsets # list of extracted onsets
|
45
|
+
# NOT YET IMPLEMENTED # my_file.pitches # list of extracted pitches
|
46
|
+
# NOT YET IMPLEMENTED # my_file.beats # where one would tap their foot
|
47
|
+
# NOT YET IMPLEMENTED # my_file.notes # list of onsets with pitches
|
48
|
+
# NOT YET IMPLEMENTED # my_file.silences # list of silent regions
|
49
|
+
# NOT YET IMPLEMENTED # my_file.mel_frequency_cepstral_coefficients # list of mfccs
|
50
|
+
```
|
51
|
+
|
52
|
+
All of these are Ruby `Enumerator`s which means they'll respond to `.next`, and so on. If you want the whole list all at once call `.to_a` on it.
|
53
|
+
|
54
|
+
## Data format
|
55
|
+
|
56
|
+
Each "event" that `aubio` describes is represented as a `Hash` like so:
|
57
|
+
|
58
|
+
```
|
59
|
+
my_file.onsets.first #=> {s: 0.0, ms: 0.0}
|
60
|
+
```
|
61
|
+
|
62
|
+
`s` and `ms` refer to seconds and milliseconds respectively.
|
63
|
+
|
64
|
+
### Still to implement
|
65
|
+
|
66
|
+
`relative` is the point at which the event occurs relative to the overall length of the original sound file, scaled between `0` and `1` (i.e. `relative: 0.5` is exactly halfway through).
|
67
|
+
|
68
|
+
`confidence` is a score returned from `aubio` which may be useful for threshold type operations.
|
69
|
+
|
70
|
+
## Optional params
|
71
|
+
|
72
|
+
The `Aubio#open` method can take a list of optional params like so:
|
73
|
+
|
74
|
+
```
|
75
|
+
:sample_rate
|
76
|
+
# Fetch the input source, resampled at the given sampling rate. The rate should be specified in Hertz as an integer. If 0, the sampling rate of the original source will be used. Defaults to 0.
|
77
|
+
:bufsize
|
78
|
+
The size of the buffer to analyze, that is the length of the window used for spectral and temporal computations. Defaults to 512.
|
79
|
+
:hopsize
|
80
|
+
```
|
81
|
+
|
82
|
+
e.g.
|
83
|
+
|
84
|
+
```
|
85
|
+
Aubio.open("/path/to/audio/file", sample_rate: 44100)
|
86
|
+
```
|
87
|
+
|
88
|
+
## Bugs / Still to do
|
89
|
+
|
90
|
+
* better tests
|
91
|
+
* add end of file as optional onset for slicing purposes
|
92
|
+
* implement relative timing in offset
|
93
|
+
* use `Offsets` class as a basis to implement the other functions
|
94
|
+
* implement class level methods for "bpm"
|
95
|
+
* look into streaming results for live inputs
|
96
|
+
|
97
|
+
## Development
|
98
|
+
|
99
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
100
|
+
|
101
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
102
|
+
|
103
|
+
## Contributing
|
104
|
+
|
105
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/xavriley/aubio. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
106
|
+
|
107
|
+
|
108
|
+
## License
|
109
|
+
|
110
|
+
The gem is available as open source under the terms of the [GNU General Public License, version 3 (GPL-3.0)](http://opensource.org/licenses/GPL-3.0).
|
111
|
+
|
data/Rakefile
ADDED
data/aubio.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'aubio/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "aubio"
|
8
|
+
spec.version = Aubio::VERSION
|
9
|
+
spec.authors = ["Xavier Riley"]
|
10
|
+
spec.email = ["xavriley@hotmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Ruby bindings for the aubio audio library}
|
13
|
+
spec.description = %q{Aubio is a tool designed for the extraction of annotations from audio signals. Its features include segmenting a sound file before each of its attacks, performing pitch detection, tapping the beat and producing midi streams from live audio.}
|
14
|
+
spec.homepage = "https://github.com/xavriley/ruby-aubio"
|
15
|
+
spec.license = "GNU GPL v3.0"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "ffi", "~> 1.9"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
27
|
+
end
|
data/aubio.rb
ADDED
@@ -0,0 +1,467 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Aubio
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib '/usr/local/Cellar/aubio/0.4.2/lib/libaubio.4.2.2.dylib'
|
6
|
+
|
7
|
+
# tempo
|
8
|
+
attach_function :new_aubio_tempo, [ :string, :int, :int, :int ], :pointer
|
9
|
+
attach_function :aubio_tempo_do, [:pointer, :pointer, :pointer], :void
|
10
|
+
attach_function :aubio_tempo_get_last, [:pointer], :int
|
11
|
+
attach_function :aubio_tempo_get_last_s, [:pointer], :float
|
12
|
+
attach_function :aubio_tempo_get_last_ms, [:pointer], :float
|
13
|
+
attach_function :aubio_tempo_set_silence, [:pointer, :float], :int
|
14
|
+
attach_function :aubio_tempo_get_silence, [:pointer], :float
|
15
|
+
attach_function :aubio_tempo_set_threshold, [:pointer, :float], :int
|
16
|
+
attach_function :aubio_tempo_get_threshold, [:pointer], :float
|
17
|
+
attach_function :aubio_tempo_get_bpm, [:pointer], :float
|
18
|
+
attach_function :aubio_tempo_get_confidence, [:pointer], :float
|
19
|
+
attach_function :del_aubio_tempo, [:pointer], :void
|
20
|
+
|
21
|
+
# beattracking / misc
|
22
|
+
attach_function :new_aubio_beattracking, [:int, :int, :int], :pointer
|
23
|
+
attach_function :aubio_beattracking_do, [:pointer, :pointer, :pointer], :void
|
24
|
+
attach_function :aubio_beattracking_get_bpm, [:pointer], :float
|
25
|
+
attach_function :aubio_filter_do, [:pointer, :pointer], :void
|
26
|
+
attach_function :new_aubio_filter_a_weighting, [:int], :pointer
|
27
|
+
|
28
|
+
# source
|
29
|
+
attach_function :new_aubio_source, [:string, :int, :int], :pointer
|
30
|
+
attach_function :aubio_source_do, [:pointer, :pointer, :pointer], :void
|
31
|
+
attach_function :aubio_source_do_multi, [:pointer, :pointer, :pointer], :void
|
32
|
+
attach_function :aubio_source_get_samplerate, [:pointer], :int
|
33
|
+
attach_function :aubio_source_get_channels, [:pointer], :int
|
34
|
+
attach_function :aubio_source_seek, [:pointer, :int], :int
|
35
|
+
attach_function :aubio_source_close, [:pointer], :int
|
36
|
+
attach_function :del_aubio_source, [:pointer], :void
|
37
|
+
|
38
|
+
# sink
|
39
|
+
attach_function :new_aubio_sink, [:string, :int], :pointer
|
40
|
+
attach_function :aubio_sink_preset_samplerate, [:pointer, :int], :void
|
41
|
+
attach_function :aubio_sink_preset_channels, [:pointer, :int], :void
|
42
|
+
attach_function :aubio_sink_get_samplerate, [:pointer], :int
|
43
|
+
attach_function :aubio_sink_get_channels, [:pointer], :int
|
44
|
+
attach_function :aubio_sink_do, [:pointer, :pointer, :int], :void
|
45
|
+
attach_function :aubio_sink_do_multi, [:pointer, :pointer, :int], :void
|
46
|
+
attach_function :aubio_sink_close, [:pointer], :int
|
47
|
+
attach_function :del_aubio_sink, [:pointer], :void
|
48
|
+
|
49
|
+
# onset
|
50
|
+
attach_function :new_aubio_onset, [:string, :int, :int, :int], :pointer
|
51
|
+
attach_function :aubio_onset_do, [:pointer, :pointer, :pointer], :void
|
52
|
+
attach_function :aubio_onset_get_last, [:pointer], :int
|
53
|
+
attach_function :aubio_onset_get_last_s, [:pointer], :float
|
54
|
+
attach_function :aubio_onset_get_last_ms, [:pointer], :float
|
55
|
+
attach_function :aubio_onset_set_silence, [:pointer, :float], :int
|
56
|
+
attach_function :aubio_onset_get_silence, [:pointer], :float
|
57
|
+
attach_function :aubio_onset_get_descriptor, [:pointer], :float
|
58
|
+
attach_function :aubio_onset_get_thresholded_descriptor, [:pointer], :float
|
59
|
+
attach_function :aubio_onset_set_threshold, [:pointer, :float], :int
|
60
|
+
attach_function :aubio_onset_set_minioi, [:pointer, :int], :int
|
61
|
+
attach_function :aubio_onset_set_minioi_s, [:pointer, :int], :int
|
62
|
+
attach_function :aubio_onset_set_minioi_ms, [:pointer, :float], :int
|
63
|
+
attach_function :aubio_onset_set_delay, [:pointer, :int], :int
|
64
|
+
attach_function :aubio_onset_set_delay_s, [:pointer, :int], :int
|
65
|
+
attach_function :aubio_onset_set_delay_ms, [:pointer, :float], :int
|
66
|
+
attach_function :aubio_onset_get_minioi, [:pointer], :int
|
67
|
+
attach_function :aubio_onset_get_minioi_s, [:pointer], :float
|
68
|
+
attach_function :aubio_onset_get_minioi_ms, [:pointer], :float
|
69
|
+
attach_function :aubio_onset_get_delay, [:pointer], :int
|
70
|
+
attach_function :aubio_onset_get_delay_s, [:pointer], :float
|
71
|
+
attach_function :aubio_onset_get_delay_ms, [:pointer], :float
|
72
|
+
attach_function :aubio_onset_get_threshold, [:pointer], :float
|
73
|
+
attach_function :del_aubio_onset, [:pointer], :void
|
74
|
+
|
75
|
+
# pitch
|
76
|
+
attach_function :new_aubio_pitch, [:string, :int, :int, :int], :pointer
|
77
|
+
attach_function :aubio_pitch_do, [:pointer, :pointer, :pointer], :void
|
78
|
+
attach_function :aubio_pitch_set_tolerance, [:pointer, :int], :int
|
79
|
+
attach_function :aubio_pitch_set_unit, [:pointer, :string], :int
|
80
|
+
attach_function :aubio_pitch_set_silence, [:pointer, :float], :int
|
81
|
+
attach_function :aubio_pitch_get_silence, [:pointer], :float
|
82
|
+
attach_function :aubio_pitch_get_confidence, [:pointer], :float
|
83
|
+
attach_function :del_aubio_pitch, [:pointer], :void
|
84
|
+
|
85
|
+
# new fvec
|
86
|
+
attach_function :new_fvec, [:int], :pointer
|
87
|
+
attach_function :del_fvec, [:pointer], :void
|
88
|
+
attach_function :fvec_get_sample, [:pointer, :int], :float
|
89
|
+
attach_function :fvec_set_sample, [:pointer, :float, :int], :void
|
90
|
+
attach_function :fvec_get_data, [:pointer], :float
|
91
|
+
attach_function :fvec_print, [:pointer], :void
|
92
|
+
attach_function :fvec_set_all, [:pointer, :float], :void
|
93
|
+
attach_function :fvec_zeros, [:pointer], :void
|
94
|
+
attach_function :fvec_rev, [:pointer], :void
|
95
|
+
attach_function :fvec_weight, [:pointer, :pointer], :void
|
96
|
+
attach_function :fvec_copy, [:pointer, :pointer], :void
|
97
|
+
attach_function :fvec_ones, [:pointer], :void
|
98
|
+
|
99
|
+
def self.onsets(path, params={})
|
100
|
+
sample_rate = params[:sample_rate] || 44100
|
101
|
+
window_size = params[:window_size] || 1024
|
102
|
+
hop_size = params[:hop_size] || 512
|
103
|
+
|
104
|
+
# parser.add_option("-O","--onset-method",
|
105
|
+
# action="store", dest="onset_method", default='default',
|
106
|
+
# metavar = "<onset_method>",
|
107
|
+
# help="onset detection method [default=default] \
|
108
|
+
# complexdomain|hfc|phase|specdiff|energy|kl|mkl")
|
109
|
+
onset_method = params[:onset_method] || "default"
|
110
|
+
|
111
|
+
# # cutting methods
|
112
|
+
# parser.add_option("-b","--beat",
|
113
|
+
# action="store_true", dest="beat", default=False,
|
114
|
+
# help="use beat locations")
|
115
|
+
beat = params[:beat] || false
|
116
|
+
# """
|
117
|
+
# parser.add_option("-S","--silencecut",
|
118
|
+
# action="store_true", dest="silencecut", default=False,
|
119
|
+
# help="use silence locations")
|
120
|
+
silencecut = params[:silencecut] || false
|
121
|
+
|
122
|
+
# parser.add_option("-s","--silence",
|
123
|
+
# metavar = "<value>",
|
124
|
+
# action="store", dest="silence", default=-70,
|
125
|
+
# help="silence threshold [default=-70]")
|
126
|
+
silence = params[:silence] || -70
|
127
|
+
|
128
|
+
# """
|
129
|
+
# # algorithm parameters
|
130
|
+
# parser.add_option("-r", "--samplerate",
|
131
|
+
# metavar = "<freq>", type='int',
|
132
|
+
# action="store", dest="samplerate", default=0,
|
133
|
+
# help="samplerate at which the file should be represented")
|
134
|
+
# parser.add_option("-B","--bufsize",
|
135
|
+
# action="store", dest="bufsize", default=512,
|
136
|
+
# metavar = "<size>", type='int',
|
137
|
+
# help="buffer size [default=512]")
|
138
|
+
# parser.add_option("-H","--hopsize",
|
139
|
+
# metavar = "<size>", type='int',
|
140
|
+
# action="store", dest="hopsize", default=256,
|
141
|
+
# help="overlap size [default=256]")
|
142
|
+
# parser.add_option("-t","--onset-threshold",
|
143
|
+
# metavar = "<value>", type="float",
|
144
|
+
# action="store", dest="threshold", default=0.3,
|
145
|
+
# help="onset peak picking threshold [default=0.3]")
|
146
|
+
# parser.add_option("-c","--cut",
|
147
|
+
# action="store_true", dest="cut", default=False,
|
148
|
+
# help="cut input sound file at detected labels \
|
149
|
+
# best used with option -L")
|
150
|
+
|
151
|
+
# # minioi
|
152
|
+
# parser.add_option("-M","--minioi",
|
153
|
+
# metavar = "<value>", type='string',
|
154
|
+
# action="store", dest="minioi", default="12ms",
|
155
|
+
# help="minimum inter onset interval [default=12ms]")
|
156
|
+
|
157
|
+
# """
|
158
|
+
# parser.add_option("-D","--delay",
|
159
|
+
# action = "store", dest = "delay", type = "float",
|
160
|
+
# metavar = "<seconds>", default=0,
|
161
|
+
# help="number of seconds to take back [default=system]\
|
162
|
+
# default system delay is 3*hopsize/samplerate")
|
163
|
+
# parser.add_option("-C","--dcthreshold",
|
164
|
+
# metavar = "<value>",
|
165
|
+
# action="store", dest="dcthreshold", default=1.,
|
166
|
+
# help="onset peak picking DC component [default=1.]")
|
167
|
+
# parser.add_option("-L","--localmin",
|
168
|
+
# action="store_true", dest="localmin", default=False,
|
169
|
+
# help="use local minima after peak detection")
|
170
|
+
# parser.add_option("-d","--derivate",
|
171
|
+
# action="store_true", dest="derivate", default=False,
|
172
|
+
# help="derivate onset detection function")
|
173
|
+
# parser.add_option("-z","--zerocross",
|
174
|
+
# metavar = "<value>",
|
175
|
+
# action="store", dest="zerothres", default=0.008,
|
176
|
+
# help="zero-crossing threshold for slicing [default=0.00008]")
|
177
|
+
# """
|
178
|
+
# # plotting functions
|
179
|
+
# """
|
180
|
+
# parser.add_option("-p","--plot",
|
181
|
+
# action="store_true", dest="plot", default=False,
|
182
|
+
# help="draw plot")
|
183
|
+
# parser.add_option("-x","--xsize",
|
184
|
+
# metavar = "<size>",
|
185
|
+
# action="store", dest="xsize", default=1.,
|
186
|
+
# type='float', help="define xsize for plot")
|
187
|
+
# parser.add_option("-y","--ysize",
|
188
|
+
# metavar = "<size>",
|
189
|
+
# action="store", dest="ysize", default=1.,
|
190
|
+
# type='float', help="define ysize for plot")
|
191
|
+
# parser.add_option("-f","--function",
|
192
|
+
# action="store_true", dest="func", default=False,
|
193
|
+
# help="print detection function")
|
194
|
+
# parser.add_option("-n","--no-onsets",
|
195
|
+
# action="store_true", dest="nplot", default=False,
|
196
|
+
# help="do not plot detected onsets")
|
197
|
+
# parser.add_option("-O","--outplot",
|
198
|
+
# metavar = "<output_image>",
|
199
|
+
# action="store", dest="outplot", default=None,
|
200
|
+
# help="save plot to output.{ps,png}")
|
201
|
+
# parser.add_option("-F","--spectrogram",
|
202
|
+
# action="store_true", dest="spectro", default=False,
|
203
|
+
# help="add spectrogram to the plot")
|
204
|
+
# """
|
205
|
+
# parser.add_option("-o","--output", type = str,
|
206
|
+
# metavar = "<outputdir>",
|
207
|
+
# action="store", dest="output_directory", default=None,
|
208
|
+
# help="specify path where slices of the original file should be created")
|
209
|
+
# parser.add_option("--cut-until-nsamples", type = int,
|
210
|
+
# metavar = "<samples>",
|
211
|
+
# action = "store", dest = "cut_until_nsamples", default = None,
|
212
|
+
# help="how many extra samples should be added at the end of each slice")
|
213
|
+
# parser.add_option("--cut-until-nslices", type = int,
|
214
|
+
# metavar = "<slices>",
|
215
|
+
# action = "store", dest = "cut_until_nslices", default = None,
|
216
|
+
# help="how many extra slices should be added at the end of each slice")
|
217
|
+
|
218
|
+
# parser.add_option("-v","--verbose",
|
219
|
+
# action="store_true", dest="verbose", default=True,
|
220
|
+
# help="make lots of noise [default]")
|
221
|
+
# parser.add_option("-q","--quiet",
|
222
|
+
# action="store_false", dest="verbose", default=True,
|
223
|
+
# help="be quiet")
|
224
|
+
# (options, args) = parser.parse_args()
|
225
|
+
# if not options.source_file:
|
226
|
+
# import os.path
|
227
|
+
# if len(args) == 1:
|
228
|
+
# options.source_file = args[0]
|
229
|
+
# else:
|
230
|
+
# print "no file name given\n", usage
|
231
|
+
# sys.exit(1)
|
232
|
+
# return options, args
|
233
|
+
|
234
|
+
source = new_aubio_source(path, sample_rate, hop_size)
|
235
|
+
onset = new_aubio_onset("default", 512, hop_size)
|
236
|
+
aubio_onset_set_minioi_ms(onset, 12.0)
|
237
|
+
aubio_onset_set_threshold(onset, 0.3)
|
238
|
+
|
239
|
+
timestamps = []
|
240
|
+
total_frames = 0
|
241
|
+
# create output for source
|
242
|
+
samples = new_fvec(hop_size)
|
243
|
+
total_frames_counter = 0
|
244
|
+
tmp_read = FFI::MemoryPointer.new(:int)
|
245
|
+
|
246
|
+
loop do
|
247
|
+
aubio_source_do(source, samples, tmp_read)
|
248
|
+
|
249
|
+
end
|
250
|
+
# if options.beat:
|
251
|
+
# o = tempo(options.onset_method, bufsize, hopsize)
|
252
|
+
# else:
|
253
|
+
# o = onset(options.onset_method, bufsize, hopsize)
|
254
|
+
# if options.minioi:
|
255
|
+
# if options.minioi.endswith('ms'):
|
256
|
+
# o.set_minioi_ms(int(options.minioi[:-2]))
|
257
|
+
# elif options.minioi.endswith('s'):
|
258
|
+
# o.set_minioi_s(int(options.minioi[:-1]))
|
259
|
+
# else:
|
260
|
+
# o.set_minioi(int(options.minioi))
|
261
|
+
# o.set_threshold(options.threshold)
|
262
|
+
|
263
|
+
# timestamps = []
|
264
|
+
# total_frames = 0
|
265
|
+
# # analyze pass
|
266
|
+
# while True:
|
267
|
+
# samples, read = s()
|
268
|
+
# if o(samples):
|
269
|
+
# timestamps.append (o.get_last())
|
270
|
+
# if options.verbose: print "%.4f" % o.get_last_s()
|
271
|
+
# total_frames += read
|
272
|
+
# if read < hopsize: break
|
273
|
+
# del s
|
274
|
+
# # print some info
|
275
|
+
# nstamps = len(timestamps)
|
276
|
+
# duration = float (total_frames) / float(samplerate)
|
277
|
+
# info = 'found %(nstamps)d timestamps in %(source_file)s' % locals()
|
278
|
+
# info += ' (total %(duration).2fs at %(samplerate)dHz)\n' % locals()
|
279
|
+
# sys.stderr.write(info)
|
280
|
+
|
281
|
+
# # cutting pass
|
282
|
+
# if options.cut and nstamps > 0:
|
283
|
+
# # generate output files
|
284
|
+
# from aubio.slicing import slice_source_at_stamps
|
285
|
+
# timestamps_end = None
|
286
|
+
# if options.cut_until_nslices and options.cut_until_nsamples:
|
287
|
+
# print "warning: using cut_until_nslices, but cut_until_nsamples is set"
|
288
|
+
# if options.cut_until_nsamples:
|
289
|
+
# timestamps_end = [t + options.cut_until_nsamples for t in timestamps[1:]]
|
290
|
+
# timestamps_end += [ 1e120 ]
|
291
|
+
# if options.cut_until_nslices:
|
292
|
+
# timestamps_end = [t for t in timestamps[1 + options.cut_until_nslices:]]
|
293
|
+
# timestamps_end += [ 1e120 ] * (options.cut_until_nslices + 1)
|
294
|
+
# slice_source_at_stamps(source_file, timestamps, timestamps_end = timestamps_end,
|
295
|
+
# output_dir = options.output_directory,
|
296
|
+
# samplerate = samplerate)
|
297
|
+
|
298
|
+
# # print some info
|
299
|
+
# duration = float (total_frames) / float(samplerate)
|
300
|
+
# info = 'created %(nstamps)d slices from %(source_file)s' % locals()
|
301
|
+
# info += ' (total %(duration).2fs at %(samplerate)dHz)\n' % locals()
|
302
|
+
# sys.stderr.write(info)
|
303
|
+
end
|
304
|
+
|
305
|
+
def self.get_features(path, params={})
|
306
|
+
sample_rate = params[:sample_rate] || 44100
|
307
|
+
window_size = params[:window_size] || 1024
|
308
|
+
hop_size = params[:hop_size] || 512
|
309
|
+
|
310
|
+
source = new_aubio_source(path, sample_rate, hop_size)
|
311
|
+
calculated_sample_rate = aubio_source_get_samplerate(source)
|
312
|
+
puts "samplerate: #{calculated_sample_rate}"
|
313
|
+
|
314
|
+
onset = new_aubio_onset('default', window_size, hop_size, sample_rate)
|
315
|
+
aubio_onset_set_minioi_ms(onset, 12.0)
|
316
|
+
aubio_onset_set_threshold(onset, 0.3)
|
317
|
+
onsets = []
|
318
|
+
|
319
|
+
pitch = new_aubio_pitch('default', window_size, hop_size, sample_rate)
|
320
|
+
aubio_pitch_set_unit(pitch, 'Hz')
|
321
|
+
|
322
|
+
# create output for source
|
323
|
+
samples = new_fvec(hop_size)
|
324
|
+
# create output for pitch and beat
|
325
|
+
out_fvec = new_fvec(1)
|
326
|
+
total_frames_counter = 0
|
327
|
+
tmp_read = FFI::MemoryPointer.new(:int)
|
328
|
+
|
329
|
+
loop do
|
330
|
+
aubio_source_do(source, samples, tmp_read)
|
331
|
+
|
332
|
+
aubio_pitch_do(pitch, samples, out_fvec)
|
333
|
+
|
334
|
+
cur_time = total_frames_counter / sample_rate
|
335
|
+
last_pitch = fvec_get_sample(out_fvec, 0);
|
336
|
+
|
337
|
+
#puts "pitch at #{cur_time} seconds: #{last_pitch} Hz"
|
338
|
+
|
339
|
+
aubio_onset_do(onset, samples, out_fvec)
|
340
|
+
is_onset = fvec_get_sample(out_fvec, 0)
|
341
|
+
|
342
|
+
if is_onset > 0.0
|
343
|
+
last_onset = aubio_onset_get_last_s(onset)
|
344
|
+
onsets << last_onset
|
345
|
+
puts "onset at #{last_onset}"
|
346
|
+
end
|
347
|
+
|
348
|
+
read = tmp_read.read_int
|
349
|
+
total_frames_counter += read
|
350
|
+
if(read != hop_size) then
|
351
|
+
break
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
cur_time = total_frames_counter.to_f / sample_rate;
|
356
|
+
puts "total time : #{cur_time} seconds (#{total_frames_counter} frames)"
|
357
|
+
puts "found #{onsets.length} onsets total"
|
358
|
+
|
359
|
+
# cleanup
|
360
|
+
del_aubio_source(source);
|
361
|
+
del_aubio_onset(onset);
|
362
|
+
del_aubio_pitch(pitch);
|
363
|
+
|
364
|
+
onsets
|
365
|
+
end
|
366
|
+
|
367
|
+
# # change comments, swap args, convert to sym
|
368
|
+
|
369
|
+
# intPtr = 'int'
|
370
|
+
# stringPtr = "string" #ref.refType(ref.types.CString);
|
371
|
+
|
372
|
+
# {
|
373
|
+
# "aubio_tempo_do": [ "void", [ "pointer", "pointer", "pointer"]],
|
374
|
+
# "aubio_tempo_get_last": [ "int", ["pointer"]],
|
375
|
+
# "aubio_tempo_get_last_s": [ "float", ["pointer"]],
|
376
|
+
# "aubio_tempo_get_last_ms": [ "float", ["pointer"]],
|
377
|
+
# "aubio_tempo_set_silence": [ "int", ["pointer", "float"]],
|
378
|
+
# "aubio_tempo_get_silence": [ "float", ["pointer"]],
|
379
|
+
# "aubio_tempo_set_threshold": [ "int", ["pointer", "float"]],
|
380
|
+
# "aubio_tempo_get_threshold": [ "float", ["pointer"]],
|
381
|
+
# "aubio_tempo_get_bpm": [ "float", ["pointer"]],
|
382
|
+
# "aubio_tempo_get_confidence": [ "float", ["pointer"]],
|
383
|
+
# "del_aubio_tempo": [ "void", ["pointer"]],
|
384
|
+
|
385
|
+
# # beattracking / misc
|
386
|
+
# "new_aubio_beattracking": [ "pointer", [ "int", "int", "int"]],
|
387
|
+
# "aubio_beattracking_do": [ "void", [ "pointer", "pointer", "pointer"]],
|
388
|
+
# "aubio_beattracking_get_bpm": [ "float", ["pointer"]],
|
389
|
+
# "aubio_filter_do": [ "void", [ "pointer", "pointer" ]],
|
390
|
+
# "new_aubio_filter_a_weighting": [ "pointer", [ "int" ]],
|
391
|
+
|
392
|
+
# # source
|
393
|
+
# "new_aubio_source": [ "pointer", [ "string", "int", "int" ]],
|
394
|
+
# "aubio_source_do": [ "void", [ "pointer", "pointer", intPtr ]],
|
395
|
+
# "aubio_source_do_multi": [ "void", [ "pointer", "pointer", intPtr ]],
|
396
|
+
# "aubio_source_get_samplerate": [ "int", [ "pointer" ]],
|
397
|
+
# "aubio_source_get_channels": [ "int", [ "pointer" ]],
|
398
|
+
# "aubio_source_seek": [ "int", [ "pointer", "int" ]],
|
399
|
+
# "aubio_source_close": [ "int", [ "pointer" ]],
|
400
|
+
# "del_aubio_source": [ "void", [ "pointer" ]],
|
401
|
+
|
402
|
+
# # sink
|
403
|
+
# "new_aubio_sink": [ "pointer", [ "string", "int" ]],
|
404
|
+
# "aubio_sink_preset_samplerate": [ "void", [ "pointer", "int" ]],
|
405
|
+
# "aubio_sink_preset_channels": [ "void", [ "pointer", "int" ]],
|
406
|
+
# "aubio_sink_get_samplerate": [ "int", [ "pointer" ]],
|
407
|
+
# "aubio_sink_get_channels": [ "int", [ "pointer" ]],
|
408
|
+
# "aubio_sink_do": ["void", ["pointer", "pointer", "int"]],
|
409
|
+
# "aubio_sink_do_multi": ["void", ["pointer", "pointer", "int"]],
|
410
|
+
# "aubio_sink_close": [ "int", [ "pointer" ]],
|
411
|
+
# "del_aubio_sink": [ "void", [ "pointer" ]],
|
412
|
+
|
413
|
+
# # onset
|
414
|
+
# "new_aubio_onset": [ "pointer", [ "string", "int", "int", "int"]],
|
415
|
+
# "aubio_onset_do": [ "void", [ "pointer", "pointer", "pointer"]],
|
416
|
+
# "aubio_onset_get_last": [ "int", ["pointer"]],
|
417
|
+
# "aubio_onset_get_last_s": [ "float", ["pointer"]],
|
418
|
+
# "aubio_onset_get_last_ms": [ "float", ["pointer"]],
|
419
|
+
# "aubio_onset_set_silence": [ "int", ["pointer", "float"]],
|
420
|
+
# "aubio_onset_get_silence": [ "float", ["pointer"]],
|
421
|
+
# "aubio_onset_get_descriptor": [ "float", ["pointer"]],
|
422
|
+
# "aubio_onset_get_thresholded_descriptor": [ "float", ["pointer"]],
|
423
|
+
# "aubio_onset_set_threshold": [ "int", ["pointer", "float"]],
|
424
|
+
# "aubio_onset_set_minioi": [ "int", ["pointer", "int"]],
|
425
|
+
# "aubio_onset_set_minioi_s": [ "int", ["pointer", "int"]],
|
426
|
+
# "aubio_onset_set_minioi_ms": [ "int", ["pointer", "float"]],
|
427
|
+
# "aubio_onset_set_delay": [ "int", ["pointer", "int"]],
|
428
|
+
# "aubio_onset_set_delay_s": [ "int", ["pointer", "int"]],
|
429
|
+
# "aubio_onset_set_delay_ms": [ "int", ["pointer", "float"]],
|
430
|
+
# "aubio_onset_get_minioi": [ "int", ["pointer"]],
|
431
|
+
# "aubio_onset_get_minioi_s": [ "float", ["pointer"]],
|
432
|
+
# "aubio_onset_get_minioi_ms": [ "float", ["pointer"]],
|
433
|
+
# "aubio_onset_get_delay": [ "int", ["pointer"]],
|
434
|
+
# "aubio_onset_get_delay_s": [ "float", ["pointer"]],
|
435
|
+
# "aubio_onset_get_delay_ms": [ "float", ["pointer"]],
|
436
|
+
# "aubio_onset_get_threshold": [ "float", ["pointer"]],
|
437
|
+
# "del_aubio_onset": [ "void", ["pointer"]],
|
438
|
+
|
439
|
+
# # pitch
|
440
|
+
# "new_aubio_pitch": [ "pointer", [ "string", "int", "int", "int"]],
|
441
|
+
# "aubio_pitch_do": ["void", ["pointer", "pointer", "pointer"]],
|
442
|
+
# "aubio_pitch_set_tolerance": [ "int", ["pointer", "int"]],
|
443
|
+
# "aubio_pitch_set_unit": ["int", ["pointer", "string"]],
|
444
|
+
# "aubio_pitch_set_silence": ["int", ["pointer", "float"]],
|
445
|
+
# "aubio_pitch_get_silence": ["float", ["pointer"]],
|
446
|
+
# "aubio_pitch_get_confidence": ["float", ["pointer"]],
|
447
|
+
# "del_aubio_pitch": [ "void", ["pointer"]],
|
448
|
+
|
449
|
+
# # fvec
|
450
|
+
# "new_fvec": [ "pointer", [ "int" ]],
|
451
|
+
# "del_fvec": [ "void", [ "pointer" ]],
|
452
|
+
# "fvec_get_sample": [ "float", [ "pointer", "int" ]],
|
453
|
+
# "fvec_set_sample": [ "void", [ "pointer", "float", "int" ]],
|
454
|
+
# "fvec_get_data": [ "float", [ "pointer" ]],
|
455
|
+
# "fvec_print": [ "void", [ "pointer" ]],
|
456
|
+
# "fvec_set_all": [ "void", [ "pointer", "float" ]],
|
457
|
+
# "fvec_zeros": [ "void", [ "pointer" ]],
|
458
|
+
# "fvec_rev": [ "void", [ "pointer" ]],
|
459
|
+
# "fvec_weight": [ "void", [ "pointer", "pointer" ]],
|
460
|
+
# "fvec_copy": [ "void", [ "pointer", "pointer" ]],
|
461
|
+
# "fvec_ones": [ "void", [ "pointer" ]],
|
462
|
+
# }.each do |k,v|
|
463
|
+
# puts "attach_function :#{k.to_sym}, #{v.last.map(&:to_sym)}, :#{v.first.to_sym}"
|
464
|
+
# end
|
465
|
+
end
|
466
|
+
|
467
|
+
puts Aubio.get_features("/Applications/Sonic Pi.app/etc/samples/loop_amen.flac", hop_size: 256, sample_rate: 44100).inspect
|