fiddle_fluidsynth 0.0.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 +7 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +138 -0
- data/Rakefile +14 -0
- data/examples/enum.rb +30 -0
- data/examples/example.sf2 +0 -0
- data/examples/ffs_arpeggio.rb +252 -0
- data/examples/ffs_example.rb +47 -0
- data/examples/ffs_fx.rb +200 -0
- data/examples/ffs_metronome.rb +260 -0
- data/examples/ffs_midiplay.rb +122 -0
- data/examples/ffs_simple.rb +45 -0
- data/examples/ffs_test1.rb +41 -0
- data/examples/ffs_test3.rb +50 -0
- data/examples/fiddle-pointer.rb +18 -0
- data/examples/presets-each.rb +66 -0
- data/examples/presets-full_scan.rb +59 -0
- data/examples/settings-each.rb +106 -0
- data/exe/ffs_midiplay.rb +122 -0
- data/lib/fiddle_fluidsynth/audio_output/driver.rb +104 -0
- data/lib/fiddle_fluidsynth/audio_output/file_renderer.rb +84 -0
- data/lib/fiddle_fluidsynth/audio_output.rb +7 -0
- data/lib/fiddle_fluidsynth/command_interface/command_interface.rb +90 -0
- data/lib/fiddle_fluidsynth/command_interface/handler.rb +95 -0
- data/lib/fiddle_fluidsynth/command_interface/server.rb +79 -0
- data/lib/fiddle_fluidsynth/command_interface/shell.rb +76 -0
- data/lib/fiddle_fluidsynth/command_interface.rb +9 -0
- data/lib/fiddle_fluidsynth/core_ext/fiddle.rb +142 -0
- data/lib/fiddle_fluidsynth/core_ext/module.rb +123 -0
- data/lib/fiddle_fluidsynth/fiddle_fluidsynth.rb +172 -0
- data/lib/fiddle_fluidsynth/logging/logging.rb +82 -0
- data/lib/fiddle_fluidsynth/logging.rb +6 -0
- data/lib/fiddle_fluidsynth/midi_input/driver.rb +77 -0
- data/lib/fiddle_fluidsynth/midi_input/events.rb +255 -0
- data/lib/fiddle_fluidsynth/midi_input/midi_input.rb +70 -0
- data/lib/fiddle_fluidsynth/midi_input/player.rb +289 -0
- data/lib/fiddle_fluidsynth/midi_input/router.rb +225 -0
- data/lib/fiddle_fluidsynth/midi_input.rb +11 -0
- data/lib/fiddle_fluidsynth/misc/misc.rb +162 -0
- data/lib/fiddle_fluidsynth/misc.rb +6 -0
- data/lib/fiddle_fluidsynth/sequencer/events.rb +679 -0
- data/lib/fiddle_fluidsynth/sequencer/sequencer.rb +384 -0
- data/lib/fiddle_fluidsynth/sequencer.rb +7 -0
- data/lib/fiddle_fluidsynth/settings/settings.rb +465 -0
- data/lib/fiddle_fluidsynth/settings.rb +6 -0
- data/lib/fiddle_fluidsynth/soundfonts/generators.rb +128 -0
- data/lib/fiddle_fluidsynth/soundfonts/loader.rb +506 -0
- data/lib/fiddle_fluidsynth/soundfonts/modulators.rb +247 -0
- data/lib/fiddle_fluidsynth/soundfonts/soundfonts.rb +64 -0
- data/lib/fiddle_fluidsynth/soundfonts/voices.rb +178 -0
- data/lib/fiddle_fluidsynth/soundfonts.rb +11 -0
- data/lib/fiddle_fluidsynth/synth/audio_rendering.rb +100 -0
- data/lib/fiddle_fluidsynth/synth/effect/chorus.rb +269 -0
- data/lib/fiddle_fluidsynth/synth/effect/iir_filter.rb +81 -0
- data/lib/fiddle_fluidsynth/synth/effect/ladspa.rb +172 -0
- data/lib/fiddle_fluidsynth/synth/effect/reverb.rb +207 -0
- data/lib/fiddle_fluidsynth/synth/effect.rb +10 -0
- data/lib/fiddle_fluidsynth/synth/midi/messages.rb +292 -0
- data/lib/fiddle_fluidsynth/synth/midi/setup.rb +235 -0
- data/lib/fiddle_fluidsynth/synth/midi/tuning.rb +128 -0
- data/lib/fiddle_fluidsynth/synth/midi.rb +9 -0
- data/lib/fiddle_fluidsynth/synth/params/params.rb +200 -0
- data/lib/fiddle_fluidsynth/synth/params.rb +8 -0
- data/lib/fiddle_fluidsynth/synth/soundfont_management.rb +210 -0
- data/lib/fiddle_fluidsynth/synth/synth.rb +114 -0
- data/lib/fiddle_fluidsynth/synth/voice_control.rb +94 -0
- data/lib/fiddle_fluidsynth/synth.rb +18 -0
- data/lib/fiddle_fluidsynth/types/types.rb +131 -0
- data/lib/fiddle_fluidsynth/types.rb +10 -0
- data/lib/fiddle_fluidsynth/util/callback.rb +585 -0
- data/lib/fiddle_fluidsynth/util/interface/settings.rb +689 -0
- data/lib/fiddle_fluidsynth/util/interface/soundfont.rb +115 -0
- data/lib/fiddle_fluidsynth/util/interface/soundfont_preset.rb +69 -0
- data/lib/fiddle_fluidsynth/util/interface/soundfont_sample.rb +61 -0
- data/lib/fiddle_fluidsynth/util/interface.rb +11 -0
- data/lib/fiddle_fluidsynth/util/module_hier.rb +403 -0
- data/lib/fiddle_fluidsynth/util/util.rb +467 -0
- data/lib/fiddle_fluidsynth/util-after.rb +12 -0
- data/lib/fiddle_fluidsynth/util.rb +37 -0
- data/lib/fiddle_fluidsynth/version.rb +10 -0
- data/lib/fiddle_fluidsynth.rb +57 -0
- data/sig/fiddle_fluidsynth.rbs +4 -0
- metadata +128 -0
data/examples/ffs_fx.rb
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
|
5
|
+
# Original comments:
|
6
|
+
# FluidSynth FX - An example of using effects with fluidsynth
|
7
|
+
#
|
8
|
+
# This code is in the public domain.
|
9
|
+
#
|
10
|
+
# To compile:
|
11
|
+
# gcc -g -O -o fluidsynth_fx fluidsynth_fx.c -lfluidsynth
|
12
|
+
#
|
13
|
+
# To run
|
14
|
+
# fluidsynth_fx soundfont gain
|
15
|
+
#
|
16
|
+
# [Peter Hanappe]
|
17
|
+
#
|
18
|
+
|
19
|
+
# fiddle_fluidsynth comments:
|
20
|
+
# `ffs_fx.rb` is fiddle_fluidsynth version of `fluidsynth_fx.c`.
|
21
|
+
# This code is also in the public domain.
|
22
|
+
#
|
23
|
+
# [YAMAMOTO, Masayuki]
|
24
|
+
|
25
|
+
#
|
26
|
+
require_relative "../lib/fiddle_fluidsynth"
|
27
|
+
#require "fiddle_fluidsynth"
|
28
|
+
|
29
|
+
|
30
|
+
#
|
31
|
+
# if ARGV.size != 2
|
32
|
+
unless (1..2).cover? ARGV.size
|
33
|
+
$stderr.puts "ARGV (#{ARGV.size}): #{ARGV}"
|
34
|
+
$stderr.puts "#{__FILE__} [SOUNDFONT] <GAIN>"
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
opt_idx = 0
|
38
|
+
$stderr.puts "ARGV (#{ARGV.size}): #{ARGV}"
|
39
|
+
if File.exist? ARGV[opt_idx]
|
40
|
+
opt_idx += 1
|
41
|
+
end
|
42
|
+
gain = ARGV[opt_idx].to_f
|
43
|
+
|
44
|
+
|
45
|
+
# Original comments:
|
46
|
+
# This function implements the callback function of the audio driver
|
47
|
+
# (see new_fluid_audio_driver2 below). The data argument is a pointer
|
48
|
+
# to your private data structure. 'len' is the number of audio frames
|
49
|
+
# in the buffers. 'nfx' and 'nout' are the number of input and output
|
50
|
+
# audio buffers. 'fx' and 'out' are arrays of float buffers containing
|
51
|
+
# the audio. The audio driver fills zero-initializes those buffers.
|
52
|
+
# You are responsible for filling up those buffers, as the result will
|
53
|
+
# be sent to the sound card. This is usually done by asking the synth
|
54
|
+
# to fill those buffers appropriately using fluid_synth_process()
|
55
|
+
#
|
56
|
+
# NOTE: The API was designed to be generic. Audio driver may fill the
|
57
|
+
# buffers with audio input from the soundcard, rather than zeros.
|
58
|
+
FFS = FiddleFluidSynth
|
59
|
+
fs = nil # define later (FFS instance).
|
60
|
+
cb_ptr = FFS.define_audio_func{|data, len, nfx, fx, nout, outbuf|
|
61
|
+
|
62
|
+
# FiddleFluidSynth comments:
|
63
|
+
# BE CAREFUL! all variables in the arguments (esp. the pointers)
|
64
|
+
# are in FFI, not in Fiddle!!!
|
65
|
+
#
|
66
|
+
|
67
|
+
usr_data = data
|
68
|
+
# $stderr.puts "gain: #{gain}"
|
69
|
+
|
70
|
+
#
|
71
|
+
$stderr.puts "len: #{len}, nfx: #{nfx}, fx: #{fx.inspect}," +
|
72
|
+
" nout: #{nout}, outbuf: #{outbuf.inspect}"
|
73
|
+
|
74
|
+
if fx.null?
|
75
|
+
# Original comments:
|
76
|
+
# Note that some audio drivers may not provide buffers for effects like
|
77
|
+
# reverb and chorus. In this case it's your decision what to do. If you
|
78
|
+
# had called fluid_synth_process() like in the else branch below, no
|
79
|
+
# effects would have been rendered. Instead, you may mix the effects
|
80
|
+
# directly into the out buffers.
|
81
|
+
|
82
|
+
$stderr.puts "fx is nil."
|
83
|
+
$stderr.puts "#audio_channels: #{fs.synth_count_audio_channels(fs.synth)}"
|
84
|
+
$stderr.puts "#audio_groups: #{fs.synth_count_audio_groups(fs.synth)}"
|
85
|
+
$stderr.puts "#effects_groups: #{fs.synth_count_effects_groups(fs.synth)}"
|
86
|
+
|
87
|
+
fx_ptr = Fiddle::Pointer.new(fx.address)
|
88
|
+
outbuf_ptr = Fiddle::Pointer.new(outbuf.address)
|
89
|
+
if fs.synth_process(fs.synth, len: len,
|
90
|
+
nfx: nfx, fx: fx_ptr, nout: nout, outbuf: outbuf_ptr) !=
|
91
|
+
FiddleFluidSynth::FLUID_OK
|
92
|
+
$stderr.puts "(1) synth_process() is failed."
|
93
|
+
return FiddleFluidSynth::FLUID_FAILED
|
94
|
+
else
|
95
|
+
$stderr.puts "(1) synth_process() is succeeded."
|
96
|
+
end
|
97
|
+
else
|
98
|
+
# Original comments:
|
99
|
+
# Call the synthesizer to fill the output buffers with its
|
100
|
+
# audio output.
|
101
|
+
|
102
|
+
# FiddleFluidSynth comments:
|
103
|
+
# FiddleFluidSynth#synth_process() is wrapped by Fiddle, so we have to
|
104
|
+
# use Fiddle::Pointer instead of FFI::Pointer...
|
105
|
+
#
|
106
|
+
|
107
|
+
#
|
108
|
+
fx_ptr = Fiddle::Pointer.new(fx.address)
|
109
|
+
outbuf_ptr = Fiddle::Pointer.new(outbuf.address)
|
110
|
+
if fs.synth_process(fs.synth, len: len,
|
111
|
+
nfx: nfx, fx: fx_ptr, nout: nout, outbuf: outbuf_ptr) !=
|
112
|
+
FiddleFluidSynth::FLUID_OK
|
113
|
+
$stderr.puts "(2) synth_process() is failed."
|
114
|
+
return FiddleFluidSynth::FLUID_FAILED
|
115
|
+
else
|
116
|
+
$stderr.puts "(2) synth_process() is succeeded."
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# $stderr.puts "effector: start."
|
122
|
+
ptr_size = FFI.type_size(:pointer)
|
123
|
+
float_size = FFI.type_size(:float)
|
124
|
+
# raise SyntaxError, "test."
|
125
|
+
|
126
|
+
out_ptr = outbuf
|
127
|
+
fx_ptr = fx
|
128
|
+
|
129
|
+
# Original comments:
|
130
|
+
# Apply your effects here. In this example, the gain is
|
131
|
+
# applied to all the dry-audio output buffers.
|
132
|
+
|
133
|
+
# for outbuf.
|
134
|
+
# $stderr.puts "effector: out."
|
135
|
+
nout.times do |_i|
|
136
|
+
ch_ptr = out_ptr.get_pointer(_i * ptr_size)
|
137
|
+
|
138
|
+
len.times do |_j|
|
139
|
+
v = ch_ptr.get_float(_j * float_size)
|
140
|
+
nv = v*gain
|
141
|
+
ch_ptr.put_float(_j*float_size, nv)
|
142
|
+
# $stderr.puts "#{_j}: #{v} =>#{nv} (gain: #{gain})"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
# Original comments:
|
148
|
+
# Apply the same effect to all available effect buffer.
|
149
|
+
#
|
150
|
+
|
151
|
+
# for fx.
|
152
|
+
# $stderr.puts "effector: fx."
|
153
|
+
nfx.times do |_i|
|
154
|
+
ch_ptr = fx_ptr.get_pointer(_i * ptr_size)
|
155
|
+
|
156
|
+
len.times do |_j|
|
157
|
+
v = ch_ptr.get_float(_j * float_size)
|
158
|
+
ch_ptr.put_float(_j*float_size, v*gain)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
#return FiddleFluidSynth::FLUID_OK # LongJumpError.
|
163
|
+
FiddleFluidSynth::FLUID_OK
|
164
|
+
}
|
165
|
+
|
166
|
+
|
167
|
+
# Original comments:
|
168
|
+
# Create the audio driver. As soon as the audio driver is
|
169
|
+
# created, the synthesizer can be played.
|
170
|
+
|
171
|
+
# FiddleFluidSynth comments:
|
172
|
+
# Create the audio driver in the initializer of FFS.
|
173
|
+
#
|
174
|
+
fs = if ARGV.size == 2
|
175
|
+
FiddleFluidSynth.new(
|
176
|
+
soundfont_full_path: ARGV[0],
|
177
|
+
player_f: false,
|
178
|
+
# audio_driver_new2_f: true,
|
179
|
+
audio_driver_callback: cb_ptr)
|
180
|
+
else
|
181
|
+
FiddleFluidSynth.new(
|
182
|
+
player_f: false,
|
183
|
+
audio_driver_callback: cb_ptr)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Original comments:
|
187
|
+
# play a note.
|
188
|
+
#
|
189
|
+
fs.noteon(0, 60, 100)
|
190
|
+
|
191
|
+
#
|
192
|
+
print 'Press "Enter" to stop: '
|
193
|
+
$stdin.getc
|
194
|
+
fs.raise_error_in_callback
|
195
|
+
puts "done."
|
196
|
+
|
197
|
+
#
|
198
|
+
fs.delete
|
199
|
+
|
200
|
+
#### end.
|
@@ -0,0 +1,260 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
|
5
|
+
# Original comments:
|
6
|
+
# FluidSynth Metronome - Sequencer API example
|
7
|
+
#
|
8
|
+
# This code is in the public domain.
|
9
|
+
#
|
10
|
+
# To compile:
|
11
|
+
# gcc -o fluidsynth_metronome -lfluidsynth fluidsynth_metronome.c
|
12
|
+
#
|
13
|
+
# To run:
|
14
|
+
# fluidsynth_metronome soundfont [beats [tempo]]
|
15
|
+
#
|
16
|
+
# [Pedro Lopez-Cabanillas <plcl@users.sf.net>]
|
17
|
+
|
18
|
+
# fiddle_fluidsynth comments:
|
19
|
+
# `ffs_metronome.rb` is FiddleFluidSynth version of `fluidsynth_metronome.c`.
|
20
|
+
# This code is also in the public domain.
|
21
|
+
#
|
22
|
+
# [YAMAMOTO, Masayuki, ]
|
23
|
+
|
24
|
+
#
|
25
|
+
require_relative '../lib/fiddle_fluidsynth'
|
26
|
+
# require 'fiddle_fluidsynth'
|
27
|
+
|
28
|
+
|
29
|
+
#
|
30
|
+
# @audiodriver = nil
|
31
|
+
@seq = nil
|
32
|
+
|
33
|
+
#
|
34
|
+
@synth_dest, @client_dest = nil, nil
|
35
|
+
@time_marker = nil
|
36
|
+
|
37
|
+
# default tempo, beats per minute.
|
38
|
+
TEMPO = 120
|
39
|
+
tempo = TEMPO
|
40
|
+
@note_duration = 60000 / TEMPO
|
41
|
+
|
42
|
+
# metronome click/bell.
|
43
|
+
@weak_note = 33 # click sound.
|
44
|
+
@strong_note = 34 # click+bell sound.
|
45
|
+
|
46
|
+
# number of notes in one pattern (beats).
|
47
|
+
@pattern_size = 4
|
48
|
+
|
49
|
+
|
50
|
+
# schedule a note on message.
|
51
|
+
#
|
52
|
+
#
|
53
|
+
FFS = FiddleFluidSynth
|
54
|
+
def schedule_noteon( ch, key, ticks )
|
55
|
+
|
56
|
+
# ev = FFS.event_new
|
57
|
+
# ev.set_type(:noteon, ch: ch, key: key, vel: 127)
|
58
|
+
# :
|
59
|
+
# FFS.event_delete(ev)
|
60
|
+
FFS.seq_event(:noteon, ch: ch, key: key, vel: 127){|ev|
|
61
|
+
ev.source = -1
|
62
|
+
ev.dest = @synth_dest
|
63
|
+
|
64
|
+
#
|
65
|
+
if @seq.send_at(event: ev, time: ticks, absolute: 1) == \
|
66
|
+
FFS::FLUID_FAILED
|
67
|
+
$stderr.puts "(**) {#{__method__}} seq. send_at() failed."
|
68
|
+
end
|
69
|
+
# if FFS::FLUID_FAILED == _tmp
|
70
|
+
# $stderr.puts "(**) {#{__method__}} seq. send_at() failed (#{_tmp})."
|
71
|
+
# else
|
72
|
+
# $stderr.puts "(**) {#{__method__}} seq. send_at() succeeded (#{_tmp})."
|
73
|
+
# end
|
74
|
+
}
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# schedule a timer event (shall trigger the callback).
|
80
|
+
#
|
81
|
+
#
|
82
|
+
def schedule_timer_event
|
83
|
+
|
84
|
+
# $stderr.puts "{#{__method__}} Scheduling timer event at #{@time_marker}"
|
85
|
+
# $stderr.puts " Current tick: #{@seq.tick}"
|
86
|
+
|
87
|
+
#ev = FFS.event_new
|
88
|
+
# FFS.event_set_src(ev, src: -1)
|
89
|
+
# FFS.event_set_dest(ev, dest: @client_dest)
|
90
|
+
# FFS.event_timer(ev, data: nil)
|
91
|
+
#ev.set_type(:timer, data: nil)
|
92
|
+
# :
|
93
|
+
#FFS.event_delete(ev)
|
94
|
+
FFS.seq_event(:timer, data: nil){|ev|
|
95
|
+
ev.source = -1
|
96
|
+
ev.dest = @client_dest
|
97
|
+
# $stderr.puts "{#{__method__}} set as a timer event for #{ev.inspect}"
|
98
|
+
|
99
|
+
if @seq.send_at(event: ev, time: @time_marker, absolute: 1) == \
|
100
|
+
FFS::FLUID_FAILED
|
101
|
+
$stderr.puts "(**) {#{__method__}} seq. send_at() failed."
|
102
|
+
end
|
103
|
+
# if FFS::FLUID_FAILED == _tmp
|
104
|
+
# $stderr.puts "(**) {#{__method__}} seq. send_at() failed (#{_tmp})."
|
105
|
+
# else
|
106
|
+
# $stderr.puts "(**) {#{__method__}} seq. send_at() succeeded (#{_tmp})."
|
107
|
+
# end
|
108
|
+
}
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# schedule the metronome pattern.
|
114
|
+
#
|
115
|
+
#
|
116
|
+
def schedule_pattern
|
117
|
+
# $stderr.puts "{#{__method__}} Scheduling pattern events at #{@time_marker}"
|
118
|
+
# $stderr.puts " Current tick: #{@seq.tick}"
|
119
|
+
|
120
|
+
#
|
121
|
+
note_time = @time_marker
|
122
|
+
|
123
|
+
#
|
124
|
+
# @pattern_size.times do |_i|
|
125
|
+
(0...@pattern_size).each do |_i|
|
126
|
+
# 0 is also true in Ruby... so we have to change the logic.
|
127
|
+
_note = !(_i.zero?) ? @weak_note : @strong_note
|
128
|
+
$stderr.puts " #{_note}, scheduled at note_time: #{note_time}" if \
|
129
|
+
ARGV.size == 4
|
130
|
+
|
131
|
+
schedule_noteon(9, _note, note_time)
|
132
|
+
note_time += @note_duration
|
133
|
+
end
|
134
|
+
|
135
|
+
@time_marker = note_time
|
136
|
+
# $stderr.puts "{#{__method__}} Next time marker: #{@time_marker}"
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
@seq_cb_ptr = FFS.define_event_callback{|time, ev, seq, data|
|
141
|
+
# $stderr.puts "{#{Time.now}} on callback."
|
142
|
+
schedule_timer_event()
|
143
|
+
schedule_pattern()
|
144
|
+
}
|
145
|
+
|
146
|
+
#
|
147
|
+
def usage( prog_name = __FILE__ )
|
148
|
+
puts "Usage: #{prog_name} [soundfont] [beats [tempo]]"
|
149
|
+
puts " or #{prog_name} -h"
|
150
|
+
puts "\tsoundfont [optional]: soundfont file name (in full path)," +
|
151
|
+
" default #{FFS.obtain_full_path_for_soundfont}."
|
152
|
+
puts "\tbeats [optional]: number of pattern beats, default #{@pattern_size}"
|
153
|
+
puts "\ttempo [optional]: BPM (Beats Per Minute), default #{TEMPO}"
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
### main.
|
158
|
+
|
159
|
+
if ARGV[0] == '-h' || ARGV[0] == '--help'
|
160
|
+
usage()
|
161
|
+
exit 1
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
opt_idx = 0
|
166
|
+
fs = if File.exist?("#{ARGV[opt_idx]}")
|
167
|
+
tmp = FiddleFluidSynth.new(
|
168
|
+
soundfont_full_path: "#{ARGV[opt_idx]}", player_f: false)
|
169
|
+
opt_idx += 1
|
170
|
+
$stderr.puts "(1) opt_idx: #{opt_idx}"
|
171
|
+
tmp
|
172
|
+
else
|
173
|
+
$stderr.puts "(2) opt_idx: #{opt_idx}"
|
174
|
+
FiddleFluidSynth.new(player_f: false)
|
175
|
+
end
|
176
|
+
$stderr.puts "opt_idx: #{opt_idx}"
|
177
|
+
|
178
|
+
#
|
179
|
+
# @seq = fs.sequencer_new2(0)
|
180
|
+
@seq = fs.sequencer_new2
|
181
|
+
if @seq.null?
|
182
|
+
raise "Cannot prepare the sequencer!"
|
183
|
+
end
|
184
|
+
puts "seq. clients: #{@seq.count_clients}"
|
185
|
+
|
186
|
+
|
187
|
+
# register the synthesizer (automatically destination)
|
188
|
+
# to the sequencer.
|
189
|
+
#
|
190
|
+
@synth_dest = @seq.register_fluidsynth(fs.synth)
|
191
|
+
if FFS::FLUID_FAILED == @synth_dest
|
192
|
+
raise "Client (synth) registsteration failed."
|
193
|
+
end
|
194
|
+
puts "seq_id: #{@synth_dest}, seq. clients: #{@seq.count_clients}"
|
195
|
+
|
196
|
+
|
197
|
+
# register the sequencer client.
|
198
|
+
#
|
199
|
+
#
|
200
|
+
@client_dest = @seq.register_client(
|
201
|
+
name: 'ffs_metronome',
|
202
|
+
event_callback: @seq_cb_ptr, data: nil)
|
203
|
+
if FFS::FLUID_FAILED == @client_dest
|
204
|
+
raise "Client registsteration failed."
|
205
|
+
end
|
206
|
+
puts "seq_id: #{@client_dest}, seq. clients: #{@seq.count_clients}"
|
207
|
+
|
208
|
+
|
209
|
+
# If we prepare the audio driver twice, note_duration become half.
|
210
|
+
# I dont know why...
|
211
|
+
#
|
212
|
+
# @audiodriver = fs.audio_driver_prepare
|
213
|
+
|
214
|
+
#
|
215
|
+
#if ARGV.size >= 2 && ARGV[opt_idx]
|
216
|
+
if ARGV.size >= 1 && ARGV[opt_idx]
|
217
|
+
$stderr.puts "(**) beats setting (#ARGV: #{ARGV.size}, opt_idx: #{opt_idx})."
|
218
|
+
beats = ARGV[opt_idx].to_i
|
219
|
+
opt_idx += 1
|
220
|
+
$stderr.puts "(**) beats is set to: #{beats}."
|
221
|
+
@pattern_size = beats if beats > 0
|
222
|
+
end
|
223
|
+
|
224
|
+
#
|
225
|
+
if ARGV.size >= 2 && ARGV[opt_idx]
|
226
|
+
$stderr.puts "(**) tempo setting (#ARGV: #{ARGV.size}, opt_idx: #{opt_idx})."
|
227
|
+
tempo = ARGV[opt_idx].to_i
|
228
|
+
opt_idx += 1
|
229
|
+
@note_duration = 60000/tempo if tempo > 0
|
230
|
+
$stderr.puts "(**) tempo is set to #{tempo}."
|
231
|
+
end
|
232
|
+
|
233
|
+
# get the current time in ticks.
|
234
|
+
#
|
235
|
+
#
|
236
|
+
# @time_marker = fs.sequencer_get_tick(@seq)
|
237
|
+
@time_marker = @seq.tick
|
238
|
+
|
239
|
+
# schedule patterns.
|
240
|
+
schedule_pattern()
|
241
|
+
schedule_timer_event()
|
242
|
+
schedule_pattern()
|
243
|
+
|
244
|
+
# wait for user input.
|
245
|
+
#
|
246
|
+
#
|
247
|
+
puts "beats: #{@pattern_size}/tempo: #{tempo}" +
|
248
|
+
" =>note_duration: #{@note_duration} [ms]"
|
249
|
+
print 'Press "Enter" to stop: '
|
250
|
+
$stdin.getc
|
251
|
+
fs.raise_error_in_callback
|
252
|
+
puts "done."
|
253
|
+
|
254
|
+
#
|
255
|
+
puts "Cleaning up..."
|
256
|
+
fs.delete
|
257
|
+
puts "fs.deleted."
|
258
|
+
|
259
|
+
puts "Done. Exiting program."
|
260
|
+
#### end.
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
|
6
|
+
# ffs_midiplay.rb - fiddle_fluidsynth MIDI file player (tick callback
|
7
|
+
# example).
|
8
|
+
# This code is in the public domain.
|
9
|
+
#
|
10
|
+
# [YAMAMOTO, Masayuki]
|
11
|
+
#
|
12
|
+
|
13
|
+
#
|
14
|
+
require_relative '../lib/fiddle_fluidsynth'
|
15
|
+
#require 'fiddle_fluidsynth'
|
16
|
+
|
17
|
+
|
18
|
+
#
|
19
|
+
DEFAULT_SF2_NAME = "default.sf2"
|
20
|
+
f_1 = ARGV[0]
|
21
|
+
f_2 = ARGV[1]
|
22
|
+
|
23
|
+
f_midi = f_2 || f_1
|
24
|
+
f_sf2 = (f_2.nil?)? DEFAULT_SF2_NAME : f_1
|
25
|
+
puts "SoundFont: #{f_sf2}, MIDI file #{f_midi}"
|
26
|
+
|
27
|
+
if f_midi.nil?
|
28
|
+
$stderr.puts "Help: #{File.basename(__FILE__)} [SoundFont] MIDI-file"
|
29
|
+
raise "Specify a MIDI file you want to play at least."
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
#
|
34
|
+
#
|
35
|
+
fs = if File.exist?(f_sf2)
|
36
|
+
FiddleFluidSynth.new(soundfont_full_path: f_sf2)
|
37
|
+
else
|
38
|
+
FiddleFluidSynth.new(soundfont_name: f_sf2)
|
39
|
+
end
|
40
|
+
fs.start
|
41
|
+
|
42
|
+
#
|
43
|
+
#
|
44
|
+
#
|
45
|
+
is_midi = fs.is_midifile(f_midi)
|
46
|
+
raise "MIDI file is strange (#{is_midi}): #{f_midi}" \
|
47
|
+
unless fs.is_midifile?(f_midi)
|
48
|
+
|
49
|
+
ver_s = fs.fluidsynth_version_str
|
50
|
+
ver_ary = fs.fluidsynth_version
|
51
|
+
|
52
|
+
puts "MIDI file (#{is_midi}): #{f_midi}"
|
53
|
+
puts "fluidsynth version_str: #{ver_s} (by version: #{ver_ary})"
|
54
|
+
puts
|
55
|
+
|
56
|
+
#
|
57
|
+
#
|
58
|
+
#
|
59
|
+
fs.player_file(f_midi)
|
60
|
+
time_start = Time.now
|
61
|
+
puts "#{time_start}: Playing #{f_midi}"
|
62
|
+
|
63
|
+
|
64
|
+
#
|
65
|
+
# we can pass user_data via handler_data as follows, but this is completely
|
66
|
+
# meaningless in FiddleFluidSynth.
|
67
|
+
#
|
68
|
+
# because we use the closure to define the callback function, i.e.,
|
69
|
+
# we can use any variables in the callback freely.
|
70
|
+
#
|
71
|
+
# ```
|
72
|
+
# str_ptr = FFI::MemoryPointer.from_string("this is a test.")
|
73
|
+
# fdl_ptr = Fiddle::Pointer.new(str_ptr.address)
|
74
|
+
#
|
75
|
+
# fs.player_set_tick_callback(handler_data: fdl_ptr_ary){|user_data, cur_tick|
|
76
|
+
# :
|
77
|
+
# puts "#{user_data}/#{user_data.read_string}" # user_data is FFI::Pointer.
|
78
|
+
# :
|
79
|
+
# }
|
80
|
+
# ```
|
81
|
+
#
|
82
|
+
fs.player_set_tick_callback{|user_data, cur_tick|
|
83
|
+
#
|
84
|
+
total_ticks = fs.player_get_total_ticks
|
85
|
+
|
86
|
+
#
|
87
|
+
status = fs.player_status
|
88
|
+
bpm = fs.player_bpm
|
89
|
+
|
90
|
+
#
|
91
|
+
# puts "#{user_data}/#{user_data.address}"
|
92
|
+
# puts "#{user_data}/#{user_data.read_string}"
|
93
|
+
puts "#{Time.now}: player status: #{status}/bpm: #{bpm}"
|
94
|
+
|
95
|
+
#
|
96
|
+
if cur_tick <= total_ticks
|
97
|
+
puts "Tick: %4d / %4d" % [cur_tick, total_ticks]
|
98
|
+
else
|
99
|
+
puts "(**) All events in the MIDI file are executed" +
|
100
|
+
" (Tick: %4d / %4d)" % [cur_tick, total_ticks]
|
101
|
+
end
|
102
|
+
}
|
103
|
+
|
104
|
+
|
105
|
+
#
|
106
|
+
#
|
107
|
+
#
|
108
|
+
until fs.player_is_done?
|
109
|
+
sleep(1.0)
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
#
|
114
|
+
#
|
115
|
+
#
|
116
|
+
fs.raise_error_in_callback
|
117
|
+
fs.delete
|
118
|
+
time_end = Time.now
|
119
|
+
puts "#{time_end}: Finished (in #{time_end-time_start} [sec])."
|
120
|
+
|
121
|
+
|
122
|
+
#### end.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
|
6
|
+
# Original comments:
|
7
|
+
# FluidSynth Simple - An example of using fluidsynth
|
8
|
+
#
|
9
|
+
# This code is in the public domain.
|
10
|
+
#
|
11
|
+
# To compile:
|
12
|
+
# gcc -g -O -o fluidsynth_simple fluidsynth_simple.c -lfluidsynth
|
13
|
+
#
|
14
|
+
# To run
|
15
|
+
# fluidsynth_simple soundfont
|
16
|
+
#
|
17
|
+
# [Peter Hanappe]
|
18
|
+
#
|
19
|
+
#
|
20
|
+
|
21
|
+
|
22
|
+
# `ffs_simple.rb` is the fiddle_fluidsynth version of `fluidsynth_simple.c`
|
23
|
+
# This code is in the public domain.
|
24
|
+
#
|
25
|
+
# [YAMAMOTO, Masayuki]
|
26
|
+
|
27
|
+
#
|
28
|
+
require_relative '../lib/fiddle_fluidsynth'
|
29
|
+
#require 'fiddle_fluidsynth'
|
30
|
+
|
31
|
+
#
|
32
|
+
fs = FiddleFluidSynth.new(player_f: false)
|
33
|
+
|
34
|
+
#
|
35
|
+
fs.noteon(0, 60, 100)
|
36
|
+
print 'Press "Enter" to stop: '
|
37
|
+
$stdin.getc
|
38
|
+
puts "done."
|
39
|
+
|
40
|
+
|
41
|
+
fs.raise_error_in_callback
|
42
|
+
fs.delete
|
43
|
+
|
44
|
+
|
45
|
+
#### end.
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
|
5
|
+
# `ffs_test1.rb` is the fiddle_fluidsynth version of `test1.rb` in
|
6
|
+
# ruby-fluidsynth.gem.
|
7
|
+
#
|
8
|
+
# This is from `ruby-fluidsynth.gem` by Daniel W. Steinbrook (2011).
|
9
|
+
# (https://github.com/steinbro/ruby-fluidsynth)
|
10
|
+
#
|
11
|
+
|
12
|
+
require_relative '../lib/fiddle_fluidsynth'
|
13
|
+
#require 'fiddle_fluidsynth'
|
14
|
+
|
15
|
+
|
16
|
+
# fs = FiddleFluidSynth.new(soundfont_name: nil)
|
17
|
+
fs = FiddleFluidSynth.new
|
18
|
+
fs.start
|
19
|
+
|
20
|
+
sfid = fs.synth_sfload(filename: "#{__dir__}/example.sf2", reset_presets: 0,
|
21
|
+
verbose_f: true)
|
22
|
+
fs.program_select(ch: 0, sfid: sfid, bknum: 0, prenum: 0)
|
23
|
+
|
24
|
+
fs.noteon(0, 60, 30)
|
25
|
+
fs.noteon(0, 67, 30)
|
26
|
+
fs.noteon(0, 76, 30)
|
27
|
+
|
28
|
+
sleep(1.0)
|
29
|
+
|
30
|
+
fs.noteoff(0, 60)
|
31
|
+
fs.noteoff(0, 67)
|
32
|
+
fs.noteoff(0, 76)
|
33
|
+
|
34
|
+
sleep(1.0)
|
35
|
+
|
36
|
+
|
37
|
+
fs.raise_error_in_callback
|
38
|
+
fs.delete
|
39
|
+
|
40
|
+
|
41
|
+
#### end.
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
|
6
|
+
# `ffs_test3.rb` is the fiddle_fluidsynth version of `test3.rb` in
|
7
|
+
# ruby-fluidsynth.gem.
|
8
|
+
#
|
9
|
+
# This is from `ruby-fluidsynth.gem` by Daniel W.Steinbrook (2011).
|
10
|
+
# (https://github.com/steinbro/ruby-fluidsynth)
|
11
|
+
#
|
12
|
+
|
13
|
+
#
|
14
|
+
require_relative '../lib/fiddle_fluidsynth'
|
15
|
+
#require 'fiddle_fluidsynth'
|
16
|
+
|
17
|
+
|
18
|
+
#
|
19
|
+
fs = FiddleFluidSynth.new(soundfont_name: nil)
|
20
|
+
fs.start
|
21
|
+
|
22
|
+
sfid = fs.synth_sfload(filename: "#{__dir__}/example.sf2", reset_presets: 0,
|
23
|
+
verbose_f: true)
|
24
|
+
sfont = fs.synth_get_sfont_by_id(id: sfid)
|
25
|
+
sfont_name = fs.sfont_get_name(sfont)
|
26
|
+
|
27
|
+
puts "sfont_name: #{sfont_name}"
|
28
|
+
|
29
|
+
fs.program_select(ch: 0, sfid: sfid, bknum: 0, prenum: 0)
|
30
|
+
|
31
|
+
fs.noteon(0, 60, 30)
|
32
|
+
sleep(0.3)
|
33
|
+
|
34
|
+
10.times do |i|
|
35
|
+
fs.cc(0, 93, 127)
|
36
|
+
fs.pitch_bend(0, i * 512)
|
37
|
+
sleep(0.1)
|
38
|
+
end
|
39
|
+
|
40
|
+
fs.noteoff(0, 60)
|
41
|
+
|
42
|
+
sleep(1.0)
|
43
|
+
|
44
|
+
|
45
|
+
#
|
46
|
+
fs.raise_error_in_callback
|
47
|
+
fs.delete
|
48
|
+
|
49
|
+
|
50
|
+
#### end.
|