2 terminatorX - realtime audio scratching software
3 Copyright (C) 2002 Arthur Peters
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 Description: Implements MIDI input to control turntable parameters.
24 #include "tX_midiin.h"
27 #ifdef USE_ALSA_MIDI_IN
28 #include "tX_global.h"
33 static gboolean midi_callback(GIOChannel *source, GIOCondition condition, gpointer data) {
34 tX_midiin *midi=(tX_midiin *) data;
38 tX_midiin::tX_midiin()
44 if (snd_seq_open(&ALSASeqHandle, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
45 tX_error("tX_midiin(): failed to open the default sequencer device.");
48 snd_seq_set_client_name(ALSASeqHandle, "terminatorX");
50 snd_seq_create_simple_port(ALSASeqHandle,
52 SND_SEQ_PORT_CAP_WRITE
53 | SND_SEQ_PORT_CAP_SUBS_WRITE,
54 SND_SEQ_PORT_TYPE_APPLICATION);
56 tX_error("tX_midiin(): error creating sequencer port.");
60 snd_seq_nonblock( ALSASeqHandle, 1 );
62 struct pollfd fds[32];
64 int res=snd_seq_poll_descriptors (ALSASeqHandle, fds, 32, POLLIN);
67 tX_error("Failed to poll ALSA descriptors: %i.\n", res);
70 GIOChannel *ioc=g_io_channel_unix_new(fds[0].fd);
71 g_io_add_watch(ioc, (GIOCondition)( G_IO_IN ), midi_callback, (gpointer) this);
72 g_io_channel_unref(ioc);
76 tX_debug("tX_midiin(): sequencer successfully opened.");
79 tX_midiin::~tX_midiin()
81 snd_seq_close(ALSASeqHandle);
82 tX_debug("tX_midiin(): sequencer closed.");
85 int tX_midiin::check_event()
89 while( snd_seq_event_input(ALSASeqHandle, &ev) != -EAGAIN )
92 //MidiEvent::type MessageType=MidiEvent::NONE;
93 //int Volume=0,Note=0,EventDevice=0;
95 event.is_noteon = false;
96 bool event_usable = true;
99 case SND_SEQ_EVENT_CONTROLLER:
100 event.type = tX_midievent::CC;
101 event.number = ev->data.control.param;
102 event.value = ev->data.control.value / 127.0;
103 event.channel = ev->data.control.channel;
105 case SND_SEQ_EVENT_PITCHBEND:
106 event.type = tX_midievent::PITCHBEND;
107 event.number = ev->data.control.param;
108 event.value = ev->data.control.value / 127.0;
109 event.channel = ev->data.control.channel;
111 case SND_SEQ_EVENT_NOTEON:
112 event.type = tX_midievent::NOTE;
113 event.number = ev->data.note.note;
114 event.value = ev->data.note.velocity / 127.0;
115 event.channel = ev->data.note.channel;
117 event.is_noteon = true;
118 if( event.value == 0 )
119 event.is_noteon = false;
121 case SND_SEQ_EVENT_NOTEOFF:
122 event.type = tX_midievent::NOTE;
123 event.number = ev->data.note.note;
124 event.value = ev->data.note.velocity / 127.0;
125 event.channel = ev->data.note.channel;
127 event.is_noteon = false;
130 event_usable = false;
133 snd_seq_free_event(ev);
137 if (event.channel<0 || event.channel>15)
139 tX_error("tX_midiin::check_event(): invaild event channel %i.", event.channel);
143 // This should be solved with a hash table. Possibly.
145 list <tX_seqpar *> :: iterator sp;
147 for (sp=tX_seqpar::all.begin(); sp!=tX_seqpar::all.end(); sp++) {
148 if ( (*sp)->bound_midi_event.type_matches (event) ) {
149 (*sp)->handle_midi_input (event);
160 void tX_midiin::configure_bindings( vtt_class* vtt )
162 list <tX_seqpar *> :: iterator sp;
164 GType types[3] = { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER };
165 GtkListStore* model = gtk_list_store_newv(3, types);
169 for (sp=tX_seqpar::all.begin(); sp!=tX_seqpar::all.end(); sp++) {
170 if (((*sp)->is_mappable) && ((*sp)->vtt) == (void*) vtt) {
172 snprintf( tempstr, sizeof(tempstr), "Type: %d, Number: %d, Channel: %d",
173 (*sp)->bound_midi_event.type, (*sp)->bound_midi_event.number,
174 (*sp)->bound_midi_event.channel );
176 gtk_list_store_append( model, &iter );
177 gtk_list_store_set( model, &iter,
178 0, (*sp)->get_name(),
185 // it will delete itself.
186 new midi_binding_gui(GTK_TREE_MODEL(model), this);
189 tX_midiin::midi_binding_gui::midi_binding_gui ( GtkTreeModel* _model, tX_midiin* _midi )
190 : model(_model), midi( _midi )
193 GtkWidget *scrolledwindow1;
198 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
199 gtk_window_set_title (GTK_WINDOW (window), "Configure MIDI Bindings");
200 gtk_window_set_default_size(GTK_WINDOW(window), 600, 260);
202 hbox1 = gtk_hbox_new (FALSE, 2);
203 gtk_widget_show (hbox1);
204 gtk_container_add (GTK_CONTAINER (window), hbox1);
205 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
207 scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
208 gtk_widget_show (scrolledwindow1);
209 gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow1, TRUE, TRUE, 0);
211 parameter_treeview = gtk_tree_view_new_with_model (model);
212 gtk_widget_show (parameter_treeview);
213 gtk_container_add (GTK_CONTAINER (scrolledwindow1), parameter_treeview);
215 GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
216 gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( parameter_treeview ),
217 -1, "Parameter", renderer,
220 gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( parameter_treeview ),
221 -1, "Event", renderer,
224 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(parameter_treeview), TRUE );
226 vbox1 = gtk_vbox_new (FALSE, 0);
227 gtk_widget_show (vbox1);
228 gtk_box_pack_start (GTK_BOX (hbox1), vbox1, FALSE, FALSE, 0);
230 label1 = gtk_label_new ("Selected MIDI Event:");
231 gtk_widget_show (label1);
232 gtk_box_pack_start (GTK_BOX (vbox1), label1, FALSE, FALSE, 0);
233 gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT);
235 frame1 = gtk_frame_new (NULL);
236 gtk_widget_show (frame1);
237 gtk_box_pack_start (GTK_BOX (vbox1), frame1, TRUE, TRUE, 0);
238 gtk_container_set_border_width (GTK_CONTAINER (frame1), 2);
239 gtk_frame_set_label_align (GTK_FRAME (frame1), 0, 0);
240 gtk_frame_set_shadow_type (GTK_FRAME (frame1), GTK_SHADOW_IN);
242 midi_event_info = gtk_label_new ("Use a MIDI thing to select it.");
243 gtk_widget_show (midi_event_info);
244 gtk_container_add (GTK_CONTAINER (frame1), midi_event_info);
245 gtk_label_set_justify (GTK_LABEL (midi_event_info), GTK_JUSTIFY_LEFT);
247 bind_button = gtk_button_new_with_mnemonic ("Bind");
248 gtk_widget_show (bind_button);
249 gtk_box_pack_start (GTK_BOX (vbox1), bind_button, FALSE, FALSE, 0);
251 GtkWidget* unbind_button = gtk_button_new_with_mnemonic ("Remove Binding");
252 gtk_widget_show (unbind_button);
253 gtk_box_pack_start (GTK_BOX (vbox1), unbind_button, FALSE, FALSE, 0);
255 GtkWidget* close_button = gtk_button_new_with_mnemonic ("Close");
256 gtk_widget_show (close_button);
257 gtk_box_pack_start (GTK_BOX (vbox1), close_button, FALSE, FALSE, 0);
259 gtk_signal_connect(GTK_OBJECT(bind_button), "clicked", (GtkSignalFunc) bind_clicked, (void *) this);
260 gtk_signal_connect(GTK_OBJECT(unbind_button), "clicked", (GtkSignalFunc) unbind_clicked, (void *) this);
261 gtk_signal_connect(GTK_OBJECT(close_button), "clicked", (GtkSignalFunc) close_clicked, (void *) this);
262 gtk_signal_connect(GTK_OBJECT(window), "destroy", (GtkSignalFunc) close_clicked, (void *) this);
264 timer_tag = gtk_timeout_add( 100, (GtkFunction) timer, (void *) this);
266 gtk_widget_show_all( GTK_WIDGET( window ) );
269 void tX_midiin::midi_binding_gui::window_closed(GtkWidget *widget, gpointer _this )
271 tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
276 void tX_midiin::midi_binding_gui::unbind_clicked( GtkButton *button, gpointer _this )
278 tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
280 GtkTreeSelection* selection;
285 selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(this_->parameter_treeview) );
286 gtk_tree_selection_get_selected( selection, &model, &iter );
287 gtk_tree_model_get( model, &iter, 2, ¶m, -1 );
289 param->bound_midi_event.type=tX_midievent::NONE;
290 param->bound_midi_event.number=0;
291 param->bound_midi_event.channel=0;
293 snprintf( tmpstr, sizeof(tmpstr), "Type: %d, Number: %d, Channel: %d",
294 param->bound_midi_event.type, param->bound_midi_event.number,
295 param->bound_midi_event.channel );
297 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, param->get_name(), 1, tmpstr, 2, param, -1 );
301 void tX_midiin::midi_binding_gui::bind_clicked( GtkButton *button, gpointer _this )
303 tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
305 GtkTreeSelection* selection;
310 selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(this_->parameter_treeview) );
311 gtk_tree_selection_get_selected( selection, &model, &iter );
312 gtk_tree_model_get( model, &iter, 2, ¶m, -1 );
314 param->bound_midi_event = this_->last_event;
316 snprintf( tmpstr, sizeof(tmpstr), "Type: %d, Number: %d, Channel: %d",
317 param->bound_midi_event.type, param->bound_midi_event.number,
318 param->bound_midi_event.channel );
320 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, param->get_name(), 1, tmpstr, 2, param, -1 );
323 void tX_midiin::midi_binding_gui::close_clicked( GtkButton *button, gpointer _this )
325 tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
327 gtk_widget_destroy( this_->window );
332 gint tX_midiin::midi_binding_gui::timer( gpointer _this )
334 tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
335 tX_midievent tmpevent = this_->midi->get_last_event();
337 if( tmpevent.type_matches( this_->last_event ) )
340 this_->last_event = tmpevent;
341 this_->last_event.clear_non_type();
343 snprintf( this_->tempstr, sizeof(this_->tempstr),
344 "Type: %d (CC=%d, NOTE=%d)\nNumber: %d\nChannel: %d\n",
345 this_->last_event.type, tX_midievent::CC, tX_midievent::NOTE,
346 this_->last_event.number,
347 this_->last_event.channel );
349 gtk_label_set_text( GTK_LABEL(this_->midi_event_info), this_->tempstr );
354 tX_midiin::midi_binding_gui::~midi_binding_gui ()
356 gtk_timeout_remove( timer_tag );
359 #endif // USE_ALSA_MIDI_IN