~ubuntu-branches/ubuntu/dapper/terminatorx/dapper

« back to all changes in this revision

Viewing changes to src/tX_midiin.cc

  • Committer: Bazaar Package Importer
  • Author(s): Mike Furr
  • Date: 2004-04-26 21:20:09 UTC
  • Revision ID: james.westby@ubuntu.com-20040426212009-acjw8flkt05j945f
Tags: upstream-3.81
Import upstream version 3.81

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  terminatorX - realtime audio scratching software
 
3
  Copyright (C) 2002 Arthur Peters
 
4
        
 
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.
 
9
 
 
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.
 
14
 
 
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.
 
18
 
 
19
  File: tX_midiin.cc
 
20
 
 
21
  Description: Implements MIDI input to control turntable parameters.
 
22
  
 
23
        Changes (Alexander K�nig <alex@lisas.de>:
 
24
        - Using a glib GIOCallback instead of polling events
 
25
        - Updating the treeview immedialtey after bind/unbind_clicked
 
26
        - Adding "remove binding" option
 
27
        - Adding destroy handler for the GUI
 
28
        - moving printf to tX_* macros
 
29
        - removing some debug code
 
30
        for 3.81
 
31
        - re-connect to MIDI devices
 
32
        - auto MIDI mappings
 
33
*/    
 
34
 
 
35
#include "tX_midiin.h"
 
36
#include "tX_vtt.h"
 
37
#include "tX_glade_interface.h"
 
38
#include "tX_glade_support.h"
 
39
#include "tX_dialog.h"
 
40
#include "tX_mastergui.h"
 
41
 
 
42
#ifdef USE_ALSA_MIDI_IN
 
43
#include "tX_global.h"
 
44
#include <iostream>
 
45
#include "tX_engine.h"
 
46
 
 
47
using namespace std;
 
48
 
 
49
static gboolean midi_callback(GIOChannel *source, GIOCondition condition, gpointer data) {
 
50
        tX_midiin *midi=(tX_midiin *) data;
 
51
        midi->check_event();
 
52
        
 
53
        return TRUE;
 
54
}
 
55
 
 
56
tX_midiin::tX_midiin()
 
57
{
 
58
        is_open=false;
 
59
        sp_to_learn=NULL;
 
60
        learn_dialog=NULL;
 
61
        
 
62
        if (snd_seq_open(&ALSASeqHandle, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
 
63
                tX_error("tX_midiin(): failed to open the default sequencer device.");
 
64
                return;
 
65
        }
 
66
        snd_seq_set_client_name(ALSASeqHandle, "terminatorX");
 
67
        portid =
 
68
                snd_seq_create_simple_port(ALSASeqHandle,
 
69
                                                                   "Control Input",
 
70
                                                                   SND_SEQ_PORT_CAP_WRITE
 
71
                                                                   | SND_SEQ_PORT_CAP_SUBS_WRITE,
 
72
                                                                   SND_SEQ_PORT_TYPE_APPLICATION);
 
73
        if (portid < 0) {
 
74
                tX_error("tX_midiin(): error creating sequencer port.");
 
75
                return;
 
76
        }
 
77
 
 
78
        snd_seq_nonblock( ALSASeqHandle, 1 );
 
79
        
 
80
        struct pollfd fds[32];
 
81
        
 
82
        int res=snd_seq_poll_descriptors (ALSASeqHandle, fds, 32, POLLIN);
 
83
 
 
84
        if (res!=1) {
 
85
                tX_error("Failed to poll ALSA descriptors: %i.\n", res);
 
86
        }
 
87
        
 
88
        GIOChannel *ioc=g_io_channel_unix_new(fds[0].fd);
 
89
        g_io_add_watch(ioc, (GIOCondition)( G_IO_IN ), midi_callback, (gpointer) this);
 
90
        g_io_channel_unref(ioc);
 
91
        
 
92
        is_open=true;
 
93
 
 
94
        tX_debug("tX_midiin(): sequencer successfully opened."); 
 
95
}
 
96
 
 
97
tX_midiin::~tX_midiin()
 
98
{
 
99
        if (is_open) {
 
100
                snd_seq_close(ALSASeqHandle);
 
101
                tX_debug("tX_midiin(): sequencer closed.");
 
102
        }
 
103
}
 
104
 
 
105
int tX_midiin::check_event()
 
106
{
 
107
        snd_seq_event_t *ev;
 
108
                
 
109
        while( snd_seq_event_input(ALSASeqHandle, &ev) != -EAGAIN )
 
110
        {
 
111
 
 
112
                //MidiEvent::type MessageType=MidiEvent::NONE;
 
113
                //int Volume=0,Note=0,EventDevice=0;
 
114
                tX_midievent event;
 
115
                event.is_noteon = false;
 
116
                bool event_usable = true;
 
117
 
 
118
                switch (ev->type) {
 
119
                        case SND_SEQ_EVENT_CONTROLLER: 
 
120
                                event.type = tX_midievent::CC;
 
121
                                event.number = ev->data.control.param;
 
122
                                event.value = ev->data.control.value / 127.0;
 
123
                                event.channel = ev->data.control.channel;
 
124
                                break;
 
125
                        case SND_SEQ_EVENT_PITCHBEND:
 
126
                                event.type = tX_midievent::PITCHBEND;
 
127
                                event.number = ev->data.control.param;
 
128
                                event.value = (ev->data.control.value + 8191.0) / 16382.0; // 127.0;
 
129
                                event.channel = ev->data.control.channel;
 
130
                                break;
 
131
                        case SND_SEQ_EVENT_CONTROL14:
 
132
                                event.type = tX_midievent::CC14;
 
133
                                event.number = ev->data.control.param;
 
134
                                event.value = ev->data.control.value / 16383.0;
 
135
                                event.channel = ev->data.control.channel;
 
136
                                break;
 
137
                        case SND_SEQ_EVENT_REGPARAM:
 
138
                                event.type = tX_midievent::RPN;
 
139
                                event.number = ev->data.control.param;
 
140
                                event.value = ev->data.control.value / 16383.0;
 
141
                                event.channel = ev->data.control.channel;
 
142
                                break;
 
143
                        case SND_SEQ_EVENT_NONREGPARAM:
 
144
                                event.type = tX_midievent::NRPN;
 
145
                                event.number = ev->data.control.param;
 
146
                                event.value = ev->data.control.value / 16383.0;
 
147
                                event.channel = ev->data.control.channel;
 
148
                                break;                                          
 
149
                        case SND_SEQ_EVENT_NOTEON:
 
150
                                event.type = tX_midievent::NOTE;
 
151
                                event.number = ev->data.note.note;
 
152
                                event.value = ev->data.note.velocity / 127.0;
 
153
                                event.channel = ev->data.note.channel;
 
154
 
 
155
                                event.is_noteon = true;
 
156
                                if( event.value == 0 )
 
157
                                        event.is_noteon = false;
 
158
                                break;
 
159
                        case SND_SEQ_EVENT_NOTEOFF: 
 
160
                                event.type = tX_midievent::NOTE;
 
161
                                event.number = ev->data.note.note;
 
162
                                event.value = ev->data.note.velocity / 127.0;
 
163
                                event.channel = ev->data.note.channel;
 
164
                                
 
165
                                event.is_noteon = false;
 
166
                                break;
 
167
                        default:
 
168
                                event_usable = false;
 
169
                }
 
170
 
 
171
                snd_seq_free_event(ev);
 
172
                
 
173
                if( event_usable ) {
 
174
                        if (event.channel<0 || event.channel>15) {
 
175
                                tX_error("tX_midiin::check_event(): invaild event channel %i.", event.channel);
 
176
                                return -1;
 
177
                        }
 
178
 
 
179
                        if (sp_to_learn) {
 
180
                                sp_to_learn->bound_midi_event=event;
 
181
                                sp_to_learn=NULL;
 
182
                                
 
183
                                if (learn_dialog) {
 
184
                                        gtk_widget_destroy(learn_dialog);
 
185
                                        learn_dialog=NULL;
 
186
                                }
 
187
                        } else {
 
188
                                // This should be solved with a hash table. Possibly.
 
189
                                
 
190
                                list <tX_seqpar *> :: iterator sp;                      
 
191
                                
 
192
                                for (sp=tX_seqpar::all.begin(); sp!=tX_seqpar::all.end(); sp++) {
 
193
                                        if ( (*sp)->bound_midi_event.type_matches (event) ) {
 
194
                                                (*sp)->handle_midi_input (event);
 
195
                                        }
 
196
                                }
 
197
                        }
 
198
                        
 
199
                        last_event = event;
 
200
                }
 
201
 
 
202
        }
 
203
        return 1;
 
204
}
 
205
 
 
206
void tX_midiin::configure_bindings( vtt_class* vtt )
 
207
{
 
208
        list <tX_seqpar *> :: iterator sp;
 
209
 
 
210
        GType types[3] = { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER };
 
211
        GtkListStore* model = gtk_list_store_newv(3, types);
 
212
        GtkTreeIter iter;
 
213
        char tempstr[128];
 
214
        
 
215
        for (sp=tX_seqpar::all.begin(); sp!=tX_seqpar::all.end(); sp++) {
 
216
                if (((*sp)->is_mappable) && ((*sp)->vtt) == (void*) vtt) {
 
217
                        
 
218
                        snprintf( tempstr, sizeof(tempstr), "Type: %d, Number: %d, Channel: %d",
 
219
                                          (*sp)->bound_midi_event.type, (*sp)->bound_midi_event.number,
 
220
                                          (*sp)->bound_midi_event.channel );
 
221
 
 
222
                        gtk_list_store_append( model, &iter );
 
223
                        gtk_list_store_set( model, &iter,
 
224
                                                                0, (*sp)->get_name(),
 
225
                                                                1, tempstr,
 
226
                                                                2, (*sp),
 
227
                                                                -1 );
 
228
                }
 
229
        }
 
230
 
 
231
        // it will delete itself.
 
232
        new midi_binding_gui(GTK_TREE_MODEL(model), this);
 
233
}
 
234
 
 
235
tX_midiin::midi_binding_gui::midi_binding_gui ( GtkTreeModel* _model, tX_midiin* _midi )
 
236
        : model(_model), midi( _midi )
 
237
{
 
238
        GtkWidget *hbox1;
 
239
        GtkWidget *scrolledwindow1;
 
240
        GtkWidget *vbox1;
 
241
        GtkWidget *label1;
 
242
        GtkWidget *frame1;
 
243
        
 
244
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
245
        gtk_window_set_title (GTK_WINDOW (window), "Configure MIDI Bindings");
 
246
        gtk_window_set_default_size(GTK_WINDOW(window), 600, 260);
 
247
        
 
248
        hbox1 = gtk_hbox_new (FALSE, 2);
 
249
        gtk_widget_show (hbox1);
 
250
        gtk_container_add (GTK_CONTAINER (window), hbox1);
 
251
        gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
 
252
        
 
253
        scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
 
254
        gtk_widget_show (scrolledwindow1);
 
255
        gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow1, TRUE, TRUE, 0);
 
256
        
 
257
        parameter_treeview = gtk_tree_view_new_with_model (model);
 
258
        gtk_widget_show (parameter_treeview);
 
259
        gtk_container_add (GTK_CONTAINER (scrolledwindow1), parameter_treeview);
 
260
        
 
261
        GtkCellRenderer   *renderer = gtk_cell_renderer_text_new ();
 
262
        gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( parameter_treeview ),
 
263
                                                                                           -1, "Parameter", renderer,
 
264
                                                                                           "text", 0,
 
265
                                                                                           NULL );
 
266
        gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( parameter_treeview ),
 
267
                                                                                           -1, "Event", renderer,
 
268
                                                                                           "text", 1,
 
269
                                                                                           NULL );
 
270
        gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(parameter_treeview), TRUE );
 
271
        
 
272
        vbox1 = gtk_vbox_new (FALSE, 0);
 
273
        gtk_widget_show (vbox1);
 
274
        gtk_box_pack_start (GTK_BOX (hbox1), vbox1, FALSE, FALSE, 0);
 
275
        
 
276
        label1 = gtk_label_new ("Selected MIDI Event:");
 
277
        gtk_widget_show (label1);
 
278
        gtk_box_pack_start (GTK_BOX (vbox1), label1, FALSE, FALSE, 0);
 
279
        gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT);
 
280
        
 
281
        frame1 = gtk_frame_new (NULL);
 
282
        gtk_widget_show (frame1);
 
283
        gtk_box_pack_start (GTK_BOX (vbox1), frame1, TRUE, TRUE, 0);
 
284
        gtk_container_set_border_width (GTK_CONTAINER (frame1), 2);
 
285
        gtk_frame_set_label_align (GTK_FRAME (frame1), 0, 0);
 
286
        gtk_frame_set_shadow_type (GTK_FRAME (frame1), GTK_SHADOW_IN);
 
287
        
 
288
        midi_event_info = gtk_label_new ("Use a MIDI thing to select it.");
 
289
        gtk_widget_show (midi_event_info);
 
290
        gtk_container_add (GTK_CONTAINER (frame1), midi_event_info);
 
291
        gtk_label_set_justify (GTK_LABEL (midi_event_info), GTK_JUSTIFY_LEFT);
 
292
        
 
293
        bind_button = gtk_button_new_with_mnemonic ("Bind");
 
294
        gtk_widget_show (bind_button);
 
295
        gtk_box_pack_start (GTK_BOX (vbox1), bind_button, FALSE, FALSE, 0);
 
296
        
 
297
        GtkWidget* unbind_button = gtk_button_new_with_mnemonic ("Remove Binding");
 
298
        gtk_widget_show (unbind_button);
 
299
        gtk_box_pack_start (GTK_BOX (vbox1), unbind_button, FALSE, FALSE, 0);   
 
300
        
 
301
        GtkWidget* close_button = gtk_button_new_with_mnemonic ("Close");
 
302
        gtk_widget_show (close_button);
 
303
        gtk_box_pack_start (GTK_BOX (vbox1), close_button, FALSE, FALSE, 0);
 
304
        
 
305
        g_signal_connect(G_OBJECT(bind_button), "clicked", (GtkSignalFunc) bind_clicked, (void *) this);
 
306
        g_signal_connect(G_OBJECT(unbind_button), "clicked", (GtkSignalFunc) unbind_clicked, (void *) this);    
 
307
        g_signal_connect(G_OBJECT(close_button), "clicked", (GtkSignalFunc) close_clicked, (void *) this);
 
308
        g_signal_connect(G_OBJECT(window), "destroy", (GtkSignalFunc) close_clicked, (void *) this);
 
309
        
 
310
        timer_tag = gtk_timeout_add( 100, (GtkFunction) timer, (void *) this);
 
311
        
 
312
        gtk_widget_show_all( GTK_WIDGET( window ) );
 
313
}
 
314
 
 
315
void tX_midiin::midi_binding_gui::window_closed(GtkWidget *widget, gpointer _this )
 
316
{
 
317
        tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
 
318
 
 
319
        delete this_;
 
320
}
 
321
 
 
322
void tX_midiin::midi_binding_gui::unbind_clicked( GtkButton *button, gpointer _this )
 
323
{
 
324
        tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
 
325
        GtkTreeModel* model;
 
326
        GtkTreeSelection* selection;
 
327
        GtkTreeIter iter;
 
328
        char tmpstr[128];
 
329
        tX_seqpar* param;
 
330
 
 
331
        selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(this_->parameter_treeview) );
 
332
        gtk_tree_selection_get_selected( selection, &model, &iter );
 
333
        gtk_tree_model_get( model, &iter, 2, &param, -1 );
 
334
        
 
335
        param->bound_midi_event.type=tX_midievent::NONE;
 
336
        param->bound_midi_event.number=0;
 
337
        param->bound_midi_event.channel=0;
 
338
        
 
339
        snprintf( tmpstr, sizeof(tmpstr), "Type: %d, Number: %d, Channel: %d",
 
340
                                param->bound_midi_event.type, param->bound_midi_event.number,
 
341
                                param->bound_midi_event.channel );
 
342
 
 
343
        gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, param->get_name(), 1, tmpstr, 2, param, -1 );       
 
344
}
 
345
 
 
346
 
 
347
void tX_midiin::midi_binding_gui::bind_clicked( GtkButton *button, gpointer _this )
 
348
{
 
349
        tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
 
350
        GtkTreeModel* model;
 
351
        GtkTreeSelection* selection;
 
352
        GtkTreeIter iter;
 
353
        char tmpstr[128];
 
354
        tX_seqpar* param;
 
355
 
 
356
        selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(this_->parameter_treeview) );
 
357
        gtk_tree_selection_get_selected( selection, &model, &iter );
 
358
        gtk_tree_model_get( model, &iter, 2, &param, -1 );
 
359
        
 
360
        param->bound_midi_event = this_->last_event;
 
361
        
 
362
        snprintf( tmpstr, sizeof(tmpstr), "Type: %d, Number: %d, Channel: %d",
 
363
                                param->bound_midi_event.type, param->bound_midi_event.number,
 
364
                                param->bound_midi_event.channel );
 
365
 
 
366
        gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, param->get_name(), 1, tmpstr, 2, param, -1 );       
 
367
}
 
368
 
 
369
void tX_midiin::midi_binding_gui::close_clicked( GtkButton *button, gpointer _this )
 
370
{
 
371
        tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
 
372
        
 
373
        gtk_widget_destroy( this_->window );
 
374
}
 
375
 
 
376
gint tX_midiin::midi_binding_gui::timer( gpointer _this )
 
377
{
 
378
        tX_midiin::midi_binding_gui* this_ = (tX_midiin::midi_binding_gui*)_this;
 
379
        tX_midievent tmpevent = this_->midi->get_last_event();
 
380
 
 
381
        if( tmpevent.type_matches( this_->last_event ) )
 
382
                return TRUE;
 
383
        
 
384
        this_->last_event = tmpevent;
 
385
        this_->last_event.clear_non_type();
 
386
 
 
387
        snprintf( this_->tempstr, sizeof(this_->tempstr),
 
388
                          "Type: %d (CC=%d, NOTE=%d)\nNumber: %d\nChannel: %d\n",
 
389
                          this_->last_event.type, tX_midievent::CC, tX_midievent::NOTE,
 
390
                          this_->last_event.number,
 
391
                          this_->last_event.channel );
 
392
 
 
393
        gtk_label_set_text( GTK_LABEL(this_->midi_event_info), this_->tempstr );
 
394
 
 
395
        return TRUE;
 
396
}
 
397
 
 
398
tX_midiin::midi_binding_gui::~midi_binding_gui ()
 
399
{
 
400
        gtk_timeout_remove( timer_tag );
 
401
}
 
402
 
 
403
void tX_midiin::set_midi_learn_sp(tX_seqpar *sp)
 
404
{
 
405
        char buffer[512];
 
406
        
 
407
        if (learn_dialog) {
 
408
                gtk_widget_destroy(learn_dialog);
 
409
        }
 
410
        
 
411
        sp_to_learn=sp;
 
412
        
 
413
        if (!sp_to_learn) return;
 
414
        
 
415
        learn_dialog=create_tX_midilearn();
 
416
        tX_set_icon(learn_dialog);
 
417
        GtkWidget *label=lookup_widget(learn_dialog, "midilabel");
 
418
        
 
419
        sprintf(buffer, "Learning MIDI mapping for <b>%s</b>\nfor turntable <b>%s</b>.\n\nWaiting for MIDI event...", sp->get_name(), sp->get_vtt_name());
 
420
        gtk_label_set_markup(GTK_LABEL(label), buffer);
 
421
        gtk_widget_show(learn_dialog);
 
422
        
 
423
        g_signal_connect(G_OBJECT(lookup_widget(learn_dialog, "cancel")), "clicked", G_CALLBACK (tX_midiin::midi_learn_cancel), this);
 
424
        g_signal_connect(G_OBJECT(learn_dialog), "destroy", G_CALLBACK (tX_midiin::midi_learn_destroy), this);
 
425
}
 
426
 
 
427
void tX_midiin::cancel_midi_learn()
 
428
{
 
429
        sp_to_learn=NULL;
 
430
        learn_dialog=NULL;
 
431
}
 
432
 
 
433
gboolean tX_midiin::midi_learn_cancel(GtkWidget *widget, tX_midiin *midi)
 
434
{
 
435
        midi->sp_to_learn=NULL;
 
436
        gtk_widget_destroy(midi->learn_dialog);
 
437
        
 
438
        return FALSE;
 
439
}
 
440
 
 
441
gboolean tX_midiin::midi_learn_destroy(GtkWidget *widget, tX_midiin *midi)
 
442
{
 
443
        midi->cancel_midi_learn();
 
444
        
 
445
        return FALSE;
 
446
}
 
447
 
 
448
void tX_midiin::store_connections(FILE *rc, char *indent) 
 
449
{
 
450
        gzFile *rz=NULL;
 
451
        
 
452
        tX_store("%s<midi_connections>\n", indent);
 
453
        strcat(indent, "\t");
 
454
 
 
455
        snd_seq_addr_t my_addr;
 
456
        my_addr.client=snd_seq_client_id(ALSASeqHandle);
 
457
        my_addr.port=portid;
 
458
 
 
459
        snd_seq_query_subscribe_t *subs;
 
460
        snd_seq_query_subscribe_alloca(&subs);
 
461
        snd_seq_query_subscribe_set_root(subs, &my_addr);
 
462
        snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_WRITE);
 
463
        snd_seq_query_subscribe_set_index(subs, 0);
 
464
        
 
465
        while (snd_seq_query_port_subscribers(ALSASeqHandle, subs) >= 0) {
 
466
                const snd_seq_addr_t *addr;
 
467
                addr = snd_seq_query_subscribe_get_addr(subs);
 
468
                
 
469
                tX_store("%s<link client=\"%i\" port=\"%i\"/>\n", indent, addr->client, addr->port);
 
470
                snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1);
 
471
        }       
 
472
                
 
473
        indent[strlen(indent)-1]=0;
 
474
        tX_store("%s</midi_connections>\n", indent);    
 
475
}
 
476
 
 
477
void tX_midiin::restore_connections(xmlNodePtr node)
 
478
{
 
479
        snd_seq_addr_t my_addr;
 
480
        my_addr.client=snd_seq_client_id(ALSASeqHandle);
 
481
        my_addr.port=portid;
 
482
        
 
483
        if (xmlStrcmp(node->name, (xmlChar *) "midi_connections")==0) {
 
484
                for (xmlNodePtr cur=node->xmlChildrenNode; cur != NULL; cur = cur->next) {
 
485
                        if (cur->type == XML_ELEMENT_NODE) {
 
486
                                if (xmlStrcmp(cur->name, (xmlChar *) "link")==0) {
 
487
                                        char *buffer;
 
488
                                        int client=-1;
 
489
                                        int port=-1;
 
490
                                        
 
491
                                        buffer=(char *) xmlGetProp(cur, (xmlChar *) "client");
 
492
                                        if (buffer) {
 
493
                                                sscanf(buffer, "%i", &client);
 
494
                                        }
 
495
                                        
 
496
                                        buffer=(char *) xmlGetProp(cur, (xmlChar *) "port");
 
497
                                        if (buffer) {
 
498
                                                sscanf(buffer, "%i", &port);
 
499
                                        }
 
500
                                        
 
501
                                        if ((port>=0) && (client>=0)) {
 
502
                                                snd_seq_addr_t sender_addr;
 
503
                                                sender_addr.client=client;
 
504
                                                sender_addr.port=port;
 
505
                                                
 
506
                                                snd_seq_port_subscribe_t *subs;
 
507
                                                snd_seq_port_subscribe_alloca(&subs);
 
508
                                                snd_seq_port_subscribe_set_sender(subs, &sender_addr);
 
509
                                                snd_seq_port_subscribe_set_dest(subs, &my_addr);
 
510
 
 
511
                                                if (snd_seq_subscribe_port(ALSASeqHandle, subs) < 0) {
 
512
                                                        tX_error("tX_midiin::restore_connections() -> failed to connect to: %d:%d.", port, client);
 
513
                                                }
 
514
                                        } else {
 
515
                                                tX_error("tX_midiin::restore_connections() -> invalid port: %d:%d.", port, client);
 
516
                                        }
 
517
                                        
 
518
                                } else {
 
519
                                        tX_error("tX_midiin::restore_connections() -> invalid element: %s.", cur->name);
 
520
                                }
 
521
                        }
 
522
                }
 
523
        } else {
 
524
                tX_error("tX_midiin::restore_connections() -> invalid XML element.");
 
525
        }
 
526
}
 
527
 
 
528
extern "C" {
 
529
        void tX_midiin_store_connections(FILE *rc, char *indent);
 
530
        void tX_midiin_restore_connections(xmlNodePtr node);
 
531
};
 
532
 
 
533
void tX_midiin_store_connections(FILE *rc, char *indent) 
 
534
{
 
535
        tX_engine::get_instance()->get_midi()->store_connections(rc, indent);
 
536
}
 
537
 
 
538
void tX_midiin_restore_connections(xmlNodePtr node) 
 
539
{
 
540
        tX_engine::get_instance()->get_midi()->restore_connections(node);
 
541
}
 
542
 
 
543
static inline void cc_map(tX_seqpar *sp, int channel, int number) {
 
544
        if (sp->bound_midi_event.type==tX_midievent::NONE) {
 
545
                sp->bound_midi_event.type=tX_midievent::CC;
 
546
                sp->bound_midi_event.channel=channel;
 
547
                sp->bound_midi_event.number=number;
 
548
                sp->reset_upper_midi_bound();
 
549
                sp->reset_lower_midi_bound();
 
550
        }
 
551
}
 
552
 
 
553
static inline void cc_note(tX_seqpar *sp, int channel, int number) {
 
554
        if (sp->bound_midi_event.type==tX_midievent::NONE) {
 
555
                sp->bound_midi_event.type=tX_midievent::NOTE;
 
556
                sp->bound_midi_event.channel=channel;
 
557
                sp->bound_midi_event.number=number;
 
558
                sp->reset_upper_midi_bound();
 
559
                sp->reset_lower_midi_bound();
 
560
        }
 
561
}
 
562
 
 
563
void tX_midiin::auto_assign_midi_mappings(GtkWidget *widget, gpointer dummy)
 
564
{
 
565
        std::list<vtt_class *>::iterator vtt;
 
566
        int ctr=0;
 
567
        
 
568
/*      if (dummy) {
 
569
                GtkWidget *dialog=gtk_message_dialog_new(GTK_WINDOW(main_window), 
 
570
                GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO,
 
571
                "Assigning the default mappings will overwrite existing MIDI mappings. OK, to overwrite existing MIDI mappings?");
 
572
                
 
573
                int res=gtk_dialog_run(GTK_DIALOG(dialog));
 
574
                gtk_widget_destroy(dialog);
 
575
                        
 
576
                if (res!=GTK_RESPONSE_YES) {
 
577
                        return;
 
578
                }               
 
579
        } */
 
580
        
 
581
        /* Works on my hardware :) */
 
582
        cc_map(&sp_master_volume, 0, 28);
 
583
        cc_map(&sp_master_volume, 0, 29);       
 
584
        
 
585
        for (vtt=vtt_class::main_list.begin(); (vtt!=vtt_class::main_list.end()) && (ctr<16); vtt++, ctr++) {
 
586
                /* These are pretty standard... */
 
587
                cc_map((&(*vtt)->sp_volume),            ctr, 07);
 
588
                cc_map((&(*vtt)->sp_pan),                       ctr, 10);
 
589
                cc_map((&(*vtt)->sp_lp_freq),           ctr, 13);
 
590
                cc_map((&(*vtt)->sp_lp_reso),           ctr, 12);
 
591
                
 
592
                /* These are on "general purpose"... */
 
593
                cc_map((&(*vtt)->sp_lp_gain),           ctr, 16);
 
594
                cc_map((&(*vtt)->sp_speed),             ctr, 17);
 
595
                cc_map((&(*vtt)->sp_pitch),             ctr, 18);
 
596
                cc_map((&(*vtt)->sp_sync_cycles),       ctr, 19);
 
597
                
 
598
                /* Sound Controller 6-10 */
 
599
                cc_map((&(*vtt)->sp_ec_length),         ctr, 75);
 
600
                cc_map((&(*vtt)->sp_ec_feedback),       ctr, 76);
 
601
                cc_map((&(*vtt)->sp_ec_volume),         ctr, 77);
 
602
                cc_map((&(*vtt)->sp_ec_pan),            ctr, 78);
 
603
                
 
604
                /* The toggles mapped to notes... */
 
605
                cc_note((&(*vtt)->sp_trigger),          0, 60+ctr);
 
606
                cc_note((&(*vtt)->sp_sync_client),      1, 60+ctr);
 
607
                cc_note((&(*vtt)->sp_loop),             2, 60+ctr);
 
608
                cc_note((&(*vtt)->sp_lp_enable),        3, 60+ctr);
 
609
                cc_note((&(*vtt)->sp_ec_enable),        4, 60+ctr);
 
610
                cc_note((&(*vtt)->sp_mute),             5, 60+ctr);
 
611
                cc_note((&(*vtt)->sp_spin),             6, 60+ctr);
 
612
        }
 
613
}
 
614
 
 
615
void tX_midiin::clear_midi_mappings(GtkWidget *widget, gpointer dummy)
 
616
{
 
617
        std::list<tX_seqpar *>::iterator sp;
 
618
        
 
619
        if (dummy) {
 
620
                GtkWidget *dialog=gtk_message_dialog_new(GTK_WINDOW(main_window), 
 
621
                GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO,
 
622
                "Really clear all current MIDI mappings?");
 
623
                
 
624
                int res=gtk_dialog_run(GTK_DIALOG(dialog));
 
625
                gtk_widget_destroy(dialog);
 
626
                        
 
627
                if (res!=GTK_RESPONSE_YES) {
 
628
                        return;
 
629
                }               
 
630
        }
 
631
        
 
632
        for (sp=tX_seqpar::all.begin(); sp!=tX_seqpar::all.end(); sp++) {
 
633
                (*sp)->bound_midi_event.type=tX_midievent::NONE;
 
634
                (*sp)->bound_midi_event.channel=0;
 
635
                (*sp)->bound_midi_event.number=0;
 
636
                (*sp)->reset_upper_midi_bound();
 
637
                (*sp)->reset_lower_midi_bound();
 
638
        }
 
639
}
 
640
#endif // USE_ALSA_MIDI_IN