2 from gui_tools
import *
4 class StreamWindow(Gtk
.VBox
):
5 def __init__(self
, instrument
, iobj
):
6 Gtk
.Widget
.__init
__(self
)
7 self
.engine
= iobj
.engine
8 self
.path
= self
.engine
.path
10 panel
= Gtk
.VBox(spacing
=5)
12 self
.filebutton
= Gtk
.FileChooserButton("Streamed file")
13 self
.filebutton
.set_action(Gtk
.FileChooserAction
.OPEN
)
14 self
.filebutton
.set_local_only(True)
15 self
.filebutton
.set_filename(self
.engine
.status().filename
)
16 self
.filebutton
.add_filter(standard_filter(["*.wav", "*.WAV", "*.ogg", "*.OGG", "*.flac", "*.FLAC"], "All loadable audio files"))
17 self
.filebutton
.add_filter(standard_filter(["*.wav", "*.WAV"], "RIFF WAVE files"))
18 self
.filebutton
.add_filter(standard_filter(["*.ogg", "*.OGG"], "OGG container files"))
19 self
.filebutton
.add_filter(standard_filter(["*.flac", "*.FLAC"], "FLAC files"))
20 self
.filebutton
.add_filter(standard_filter(["*"], "All files"))
21 self
.filebutton
.connect('file-set', self
.file_set
)
22 hpanel
= Gtk
.HBox(spacing
= 5)
23 hpanel
.pack_start(Gtk
.Label
.new_with_mnemonic("_Play file:"), False, False, 5)
24 hpanel
.pack_start(self
.filebutton
, True, True, 5)
25 panel
.pack_start(hpanel
, False, False, 5)
27 self
.adjustment
= Gtk
.Adjustment()
28 self
.adjustment_handler
= self
.adjustment
.connect('value-changed', self
.pos_slider_moved
)
29 self
.progress
= standard_hslider(self
.adjustment
)
30 panel
.pack_start(self
.progress
, False, False, 5)
32 self
.play_button
= Gtk
.Button
.new_with_mnemonic("_Play")
33 self
.rewind_button
= Gtk
.Button
.new_with_mnemonic("_Rewind")
34 self
.stop_button
= Gtk
.Button
.new_with_mnemonic("_Stop")
35 buttons
= Gtk
.HBox(spacing
= 5)
36 buttons
.add(self
.play_button
)
37 buttons
.add(self
.rewind_button
)
38 buttons
.add(self
.stop_button
)
39 panel
.pack_start(buttons
, False, False, 5)
42 self
.play_button
.connect('clicked', lambda x
: self
.engine
.play())
43 self
.rewind_button
.connect('clicked', lambda x
: self
.engine
.seek(0))
44 self
.stop_button
.connect('clicked', lambda x
: self
.engine
.stop())
45 set_timer(self
, 30, self
.update
)
48 attribs
= cbox
.GetThings("%s/status" % self
.path
, ['filename', 'pos', 'length', 'playing'], [])
49 self
.progress
.set_sensitive(attribs
.length
is not None)
50 if attribs
.length
is not None:
52 self
.adjustment
.handler_block(self
.adjustment_handler
)
53 self
.adjustment
.set_properties(value
= attribs
.pos
, lower
= 0, upper
= attribs
.length
)
54 #self.adjustment.set_all(attribs.pos, 0, attribs.length, 44100, 44100 * 10, 0)
56 self
.adjustment
.handler_unblock(self
.adjustment_handler
)
59 def pos_slider_moved(self
, adjustment
):
60 self
.engine
.seek(adjustment
.get_value())
62 def file_set(self
, button
):
63 self
.engine
.load(button
.get_filename())
67 def __init__(self
, attribs
):
68 self
.patches
= Gtk
.ListStore(GObject
.TYPE_STRING
, GObject
.TYPE_INT
)
69 self
.patch_combos
= []
71 self
.table
= Gtk
.Table(2, 16)
72 self
.table
.set_col_spacings(5)
75 self
.table
.attach(bold_label("Channel %s" % (1 + i
)), 0, 1, i
, i
+ 1, Gtk
.AttachOptions
.SHRINK
, Gtk
.AttachOptions
.SHRINK
)
76 cb
= standard_combo(self
.patches
, None)
77 cb
.connect('changed', self
.patch_combo_changed
, i
+ 1)
78 self
.table
.attach(cb
, 1, 2, i
, i
+ 1, Gtk
.AttachOptions
.SHRINK
, Gtk
.AttachOptions
.SHRINK
)
79 self
.patch_combos
.append(cb
)
82 set_timer(self
, 500, self
.patch_combo_update
)
84 def update_model(self
):
86 patches
= self
.engine
.get_patches()
87 ch_patches
= self
.engine
.status().patches
90 self
.mapping
[id] = len(self
.mapping
)
91 self
.patches
.append((self
.fmt_patch_name(patches
[id], id), id))
92 self
.patch_combo_update()
94 def patch_combo_changed(self
, combo
, channel
):
95 if combo
.get_active() == -1:
97 self
.engine
.set_patch(channel
, self
.patches
[combo
.get_active()][1])
99 def patch_combo_update(self
):
100 patch
= self
.engine
.status().patches
102 cb
= self
.patch_combos
[i
]
103 old_patch_index
= cb
.get_active() if cb
.get_active() >= 0 else -1
104 patch_id
= patch
[i
+ 1][0]
105 current_patch_index
= self
.mapping
[patch_id
] if (patch_id
>= 0 and patch_id
in self
.mapping
) else -1
106 if old_patch_index
!= current_patch_index
:
107 cb
.set_active(current_patch_index
)
108 #self.status_label.set_markup(s)
111 def fmt_patch_name(self
, patch
, id):
112 return "%s (%s)" % (patch
, id)
114 class FluidsynthWindow(Gtk
.VBox
, WithPatchTable
):
115 def __init__(self
, instrument
, iobj
):
116 Gtk
.VBox
.__init
__(self
)
117 self
.engine
= iobj
.engine
118 self
.path
= self
.engine
.path
121 attribs
= iobj
.status()
123 panel
= Gtk
.VBox(spacing
=5)
124 table
= Gtk
.Table(2, 1)
125 IntSliderRow("Polyphony", "polyphony", 2, 256).add_row(table
, 0, cbox
.VarPath(self
.path
), attribs
)
127 WithPatchTable
.__init
__(self
, attribs
)
128 panel
.pack_start(standard_vscroll_window(-1, 160, self
.table
), True, True, 5)
130 hpanel
= Gtk
.HBox(spacing
= 5)
131 self
.filebutton
= Gtk
.FileChooserButton("Soundfont")
132 self
.filebutton
.set_action(Gtk
.FileChooserAction
.OPEN
)
133 self
.filebutton
.set_local_only(True)
134 self
.filebutton
.set_filename(cbox
.GetThings("%s/status" % self
.path
, ['soundfont'], []).soundfont
)
135 self
.filebutton
.add_filter(standard_filter(["*.sf2", "*.SF2"], "SF2 Soundfonts"))
136 self
.filebutton
.add_filter(standard_filter(["*"], "All files"))
137 hpanel
.pack_start(Gtk
.Label
.new_with_mnemonic("_Load SF2:"), False, False, 5)
138 hpanel
.pack_start(self
.filebutton
, True, True, 5)
139 unload
= Gtk
.Button
.new_with_mnemonic("_Unload")
140 hpanel
.pack_start(unload
, False, False, 5)
141 unload
.connect('clicked', self
.unload
)
142 panel
.pack_start(hpanel
, False, False, 5)
144 self
.filebutton
.connect('file-set', self
.file_set
)
147 def file_set(self
, button
):
148 self
.engine
.load_soundfont(button
.get_filename())
150 def unload(self
, button
):
151 self
.filebutton
.set_filename('')
153 class LoadProgramDialog(SelectObjectDialog
):
154 title
= "Load a sampler program"
155 def __init__(self
, parent
):
156 SelectObjectDialog
.__init
__(self
, parent
)
157 def update_model(self
, model
):
158 for s
in cbox
.Config
.sections("spgm:"):
161 model
.append((s
.name
[5:], "Program", s
.name
, title
))
163 model
.append((s
.name
[5:], "SFZ", s
.name
, title
))
165 class SamplerWindow(Gtk
.VBox
, WithPatchTable
):
166 def __init__(self
, instrument
, iobj
):
167 Gtk
.VBox
.__init
__(self
)
168 self
.engine
= iobj
.engine
169 self
.path
= self
.engine
.path
171 iattribs
= iobj
.status()
172 attribs
= self
.engine
.status()
174 panel
= Gtk
.VBox(spacing
=5)
175 table
= Gtk
.Table(2, 2)
176 table
.set_col_spacings(5)
177 IntSliderRow("Polyphony", "polyphony", 1, 128).add_row(table
, 0, cbox
.VarPath(self
.path
), attribs
)
178 self
.voices_widget
= add_display_row(table
, 1, "Voices in use", cbox
.VarPath(self
.path
), attribs
, "active_voices")
179 panel
.pack_start(table
, False, False, 5)
181 WithPatchTable
.__init
__(self
, attribs
)
182 panel
.pack_start(standard_vscroll_window(-1, 160, self
.table
), True, True, 5)
184 hpanel
= Gtk
.HBox(spacing
= 5)
186 hpanel
.pack_start(Gtk
.Label
.new_with_mnemonic("Add from _SFZ:"), False, False, 5)
187 self
.filebutton
= Gtk
.FileChooserButton("Soundfont")
188 self
.filebutton
.set_action(Gtk
.FileChooserAction
.OPEN
)
189 self
.filebutton
.set_local_only(True)
190 #self.filebutton.set_filename(cbox.GetThings("%s/status" % self.path, ['soundfont'], []).soundfont)
191 self
.filebutton
.add_filter(standard_filter(["*.sfz", "*.SFZ"], "SFZ Programs"))
192 self
.filebutton
.add_filter(standard_filter(["*"], "All files"))
193 self
.filebutton
.connect('file-set', self
.load_sfz
)
194 hpanel
.pack_start(self
.filebutton
, False, True, 5)
196 load_button
= Gtk
.Button
.new_with_mnemonic("Add from _config")
197 load_button
.connect('clicked', self
.load_config
)
198 hpanel
.pack_start(load_button
, False, True, 5)
199 panel
.pack_start(hpanel
, False, False, 5)
201 set_timer(self
, 200, self
.voices_update
)
202 self
.output_model
= Gtk
.ListStore(GObject
.TYPE_INT
, GObject
.TYPE_STRING
)
203 for i
in range(iattribs
.outputs
):
204 self
.output_model
.append((i
+ 1, "Out %d" % (i
+ 1)))
206 self
.polyphony_labels
= {}
207 self
.output_combos
= {}
209 button
= Gtk
.Button("Dump SFZ")
210 button
.connect("clicked", self
.dump_sfz
, i
+ 1)
211 self
.table
.attach(button
, 2, 3, i
, i
+ 1, Gtk
.AttachOptions
.SHRINK
, Gtk
.AttachOptions
.SHRINK
)
212 label
= Gtk
.Label("")
213 self
.table
.attach(label
, 3, 4, i
, i
+ 1, Gtk
.AttachOptions
.SHRINK
, Gtk
.AttachOptions
.SHRINK
)
214 self
.polyphony_labels
[i
+ 1] = label
215 combo
= standard_combo(self
.output_model
, column
= 1)
216 combo
.connect('changed', self
.output_combo_changed
, i
+ 1)
217 self
.table
.attach(combo
, 4, 5, i
, i
+ 1, Gtk
.AttachOptions
.SHRINK
, Gtk
.AttachOptions
.SHRINK
)
218 self
.output_combos
[i
+ 1] = combo
219 self
.output_combo_update()
221 def output_combo_update(self
):
222 output
= self
.engine
.status().output
224 cb
= self
.output_combos
[i
+ 1]
225 old_channel_index
= cb
.get_active() if cb
.get_active() >= 0 else -1
226 if old_channel_index
!= output
[1 + i
]:
227 cb
.set_active(output
[1 + i
])
228 #self.status_label.set_markup(s)
231 def output_combo_changed(self
, combo
, channel
):
232 if combo
.get_active() == -1:
234 self
.engine
.set_output(channel
, combo
.get_active())
236 def dump_sfz(self
, w
, channel
):
237 attribs
= cbox
.GetThings("%s/status" % self
.path
, ['%patch', 'polyphony', 'active_voices'], [])
238 prog_no
, patch_name
= attribs
.patch
[channel
]
239 pname
, uuid
, in_use_cnt
= cbox
.GetThings("%s/patches" % self
.path
, ['%patch'], []).patch
[prog_no
]
240 print ("UUID=%s" % uuid
)
241 patch
= cbox
.Document
.map_uuid(uuid
)
242 groups
= patch
.get_groups()
243 for r
in groups
[0].get_children():
244 print ("<region> %s" % (r
.as_string()))
245 for grp
in patch
.get_groups()[1:]:
246 print ("<group> %s" % (grp
.as_string()))
247 for r
in grp
.get_children():
248 print ("<region> %s" % (r
.as_string()))
250 def load_config(self
, event
):
251 d
= LoadProgramDialog(self
.get_toplevel())
254 if response
== Gtk
.ResponseType
.OK
:
255 scene
= d
.get_selected_object()
256 pgm_id
= self
.engine
.get_unused_program()
257 self
.engine
.load_patch_from_cfg(pgm_id
, scene
[2], scene
[2][5:])
262 def load_sfz(self
, button
):
263 pgm_id
= self
.engine
.get_unused_program()
264 self
.engine
.load_patch_from_file(pgm_id
, self
.filebutton
.get_filename(), self
.filebutton
.get_filename())
267 def voices_update(self
):
268 status
= self
.engine
.status()
269 self
.voices_widget
.set_text("%s voices, %s pipes" % (status
.active_voices
, status
.active_pipes
))
271 self
.polyphony_labels
[i
+ 1].set_text("%d voices" % (status
.channel_voices
[i
+ 1],))
275 def fmt_patch_name(self
, patch
, id):
276 return "%s (%s)" % (patch
[0], id)
278 class TonewheelOrganWindow(Gtk
.VBox
):
280 (1, 'Upper', 'upper_vibrato', [(0, 'Off'), (1, 'On')]),
281 (1, 'Lower', 'lower_vibrato', [(0, 'Off'), (1, 'On')]),
282 (1, 'Mode', 'vibrato_mode', [(0, '1'), (1, '2'), (2, '3')]),
283 (1, 'Chorus', 'vibrato_chorus', [(0, 'Off'), (1, 'On')]),
284 (2, 'Enable', 'percussion_enable', [(0, 'Off'), (1, 'On')]),
285 (2, 'Harmonic', 'percussion_3rd', [(0, '2nd'), (1, '3rd')]),
287 def __init__(self
, instrument
, iobj
):
288 Gtk
.VBox
.__init
__(self
)
289 self
.engine
= iobj
.engine
290 self
.path
= self
.engine
.path
291 panel
= Gtk
.VBox(spacing
=10)
292 table
= Gtk
.Table(4, 10)
293 table
.props
.row_spacing
= 10
294 table
.set_col_spacings(5)
297 self
.hboxes
[1] = Gtk
.HBox(spacing
= 10)
298 self
.hboxes
[1].pack_start(Gtk
.Label('Vibrato: '), False, False, 5)
299 self
.hboxes
[2] = Gtk
.HBox(spacing
= 10)
300 self
.hboxes
[2].pack_start(Gtk
.Label('Percussion: '), False, False, 5)
302 for row
, name
, flag
, options
in TonewheelOrganWindow
.combos
:
303 label
= Gtk
.Label(name
)
304 self
.hboxes
[row
].pack_start(label
, False, False, 5)
305 model
= Gtk
.ListStore(GObject
.TYPE_INT
, GObject
.TYPE_STRING
)
306 for oval
, oname
in options
:
307 model
.append((oval
, oname
))
308 combo
= standard_combo(model
, column
= 1)
309 self
.hboxes
[row
].pack_start(combo
, False, False, 5)
310 combo
.update_handler
= combo
.connect('changed', lambda w
, setter
: setter(w
.get_model()[w
.get_active()][0]), getattr(self
.engine
, 'set_' + flag
))
311 self
.combos
[flag
] = combo
312 panel
.pack_start(self
.hboxes
[1], False, False, 5)
313 panel
.pack_start(self
.hboxes
[2], False, False, 5)
314 table
.attach(Gtk
.Label("Upper"), 0, 1, 0, 1)
315 table
.attach(Gtk
.Label("Lower"), 0, 1, 1, 2)
317 slider
= Gtk
.VScale(adjustment
= Gtk
.Adjustment(0, 0, 8, 1, 1))
318 slider
.props
.digits
= 0
319 table
.attach(slider
, i
+ 1, i
+ 2, 0, 1)
320 self
.drawbars
['u%d' % i
] = slider
.get_adjustment()
321 slider
.get_adjustment().connect('value-changed', lambda adj
, drawbar
: self
.engine
.set_upper_drawbar(drawbar
, int(adj
.get_value())), i
)
322 slider
= Gtk
.VScale(adjustment
= Gtk
.Adjustment(0, 0, 8, 1, 1))
323 slider
.props
.digits
= 0
324 table
.attach(slider
, i
+ 1, i
+ 2, 1, 2)
325 self
.drawbars
['l%d' % i
] = slider
.get_adjustment()
326 slider
.get_adjustment().connect('value-changed', lambda adj
, drawbar
: self
.engine
.set_lower_drawbar(drawbar
, int(adj
.get_value())), i
)
332 attribs
= self
.engine
.status()
334 self
.drawbars
['u%d' % i
].set_value(attribs
.upper_drawbar
[i
])
335 self
.drawbars
['l%d' % i
].set_value(attribs
.lower_drawbar
[i
])
336 for row
, name
, flag
, options
in TonewheelOrganWindow
.combos
:
337 combo
= self
.combos
[flag
]
338 combo
.handler_block(combo
.update_handler
)
339 combo
.set_active(ls_index(combo
.get_model(), getattr(attribs
, flag
), 0))
340 combo
.handler_unblock(combo
.update_handler
)
342 instrument_window_map
= {
343 'stream_player' : StreamWindow
,
344 'fluidsynth' : FluidsynthWindow
,
345 'sampler' : SamplerWindow
,
346 'tonewheel_organ' : TonewheelOrganWindow