/[pidim]/src/pidim_split_port.c
ViewVC logotype

Annotation of /src/pidim_split_port.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (hide annotations)
Fri Aug 27 00:11:30 2010 UTC (10 years, 1 month ago) by ben
File MIME type: text/plain
File size: 8598 byte(s)
factorised cli code
1 ben 7 /* pidim_split_port, a small Gtk+/ALSA MIDI keyboard splitter over two ports
2     * Copyright (C) 2010 Benoit Rouits
3     *
4     * This program is free software; you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation; either version 2 of the License, or
7     * (at your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful,
10     * but WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     * GNU General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License along
15     * with this program; if not, write to the Free Software Foundation, Inc.,
16     * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17     */
18    
19 ben 1 #ifdef HAVE_CONFIG_H
20     #include <config.h>
21     #endif
22    
23     #include <libintl.h>
24     #include <glib.h>
25     #include <gtk/gtk.h>
26    
27     #include <stdlib.h>
28     #include <alsa/asoundlib.h>
29     #include "pidim_common.h"
30    
31     /* alsa-related type */
32     /* this application has one input and one output port */
33     typedef struct {
34     snd_seq_t* handler; /* sequencer handler */
35     int inport_id; /* id of input port 0 */
36     int low_outport_id; /* id of output port lowkeys */
37     int high_outport_id; /* id of output port highkeys */
38     } alsa_t;
39    
40     /* globals */
41     GtkBuilder* ui = NULL;
42     int Splitnote = 0;
43     int Controller = 0;
44     int Channel = 0;
45     char Instance[64];
46    
47     /* Gtk stuff */
48     void ui_new (void)
49     {
50     gchar* ui_path = NULL;
51     GtkWidget *split_spinbutton, *controller_spinbutton, *channel_spinbutton;
52    
53     if (g_file_test("./pidim_split_port.ui", G_FILE_TEST_EXISTS))
54     ui_path = "./pidim_split_port.ui";
55     else
56     ui_path = PACKAGE_DATA_DIR"/pidim/ui/pidim_split_port.ui";
57    
58     ui = gtk_builder_new();
59     gtk_builder_add_from_file(ui, ui_path, NULL);
60     split_spinbutton = GTK_WIDGET(gtk_builder_get_object(ui, "split_spinbutton"));
61 ben 15 gtk_spin_button_set_range(GTK_SPIN_BUTTON(split_spinbutton), 0, VAL_MAX);
62 ben 1 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(split_spinbutton), 1, 0);
63     controller_spinbutton = GTK_WIDGET(gtk_builder_get_object(ui, "controller_spinbutton"));
64 ben 15 gtk_spin_button_set_range(GTK_SPIN_BUTTON(controller_spinbutton), 0, CTRL_MAX);
65 ben 1 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(controller_spinbutton), 1, 0);
66     channel_spinbutton = GTK_WIDGET(gtk_builder_get_object(ui, "channel_spinbutton"));
67 ben 15 gtk_spin_button_set_range(GTK_SPIN_BUTTON(channel_spinbutton), 0, CHAN_MAX);
68 ben 1 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(channel_spinbutton), 1, 0);
69    
70     gtk_builder_connect_signals(ui, NULL);
71     gtk_window_set_default_icon_from_file(PACKAGE_DATA_DIR"/pidim/ui/pidim.png", NULL);
72     }
73    
74     void ui_show()
75     {
76     GtkWidget* main_window = GTK_WIDGET(gtk_builder_get_object(ui, "main_window"));
77     gtk_window_set_title(GTK_WINDOW(main_window), Instance);
78     gtk_widget_show_all(main_window);
79    
80     }
81     gboolean on_main_window_delete_event(GtkWidget* main_window, GdkEvent* null1, gpointer null2) {
82     null1 = NULL;
83     null2 = NULL;
84     gtk_main_quit();
85     return TRUE;
86     }
87    
88     /* callback called when the user interacts on split spin button */
89     void on_split_spinbutton_value_changed(GtkSpinButton* spin_button, gpointer* null) {
90     Splitnote = (int) gtk_spin_button_get_value_as_int(spin_button);
91     null = NULL;
92     }
93    
94     /* callback called when the user interacts on controller spin button */
95     void on_controller_spinbutton_value_changed(GtkSpinButton* spin_button, gpointer* null)
96     {
97     Controller = (unsigned char) gtk_spin_button_get_value_as_int(spin_button);
98     null = NULL;
99     }
100    
101     /* callback called when the user interacts on channel spin button */
102     void on_channel_spinbutton_value_changed(GtkSpinButton* spin_button, gpointer* null) {
103     Channel = (int) gtk_spin_button_get_value_as_int(spin_button);
104     null = NULL;
105     }
106    
107     /* split operation on midi events */
108     void do_split (snd_seq_event_t* ev, alsa_t* alsa, int point)
109     {
110     GtkWidget* split_spinbutton;
111     int i;
112     snd_seq_event_t dup;
113     /* stuff needed to not loose matching ON/OFF even if 'point' has changed between note completion */
114     struct mem_t {
115     unsigned char channel;
116     unsigned char note;
117     int split;
118     };
119     static struct mem_t* memory = NULL;
120     static int memory_len = 0;
121    
122     if ((ev->type == SND_SEQ_EVENT_NOTEON) && (ev->data.note.velocity == 0))
123     ev->type = SND_SEQ_EVENT_NOTEOFF;
124    
125     switch (ev->type) {
126     case SND_SEQ_EVENT_CONTROLLER:
127     if (!Channel || ev->data.control.channel == Channel) {
128     if (ev->data.control.param == Controller) {
129     point = Splitnote = ev->data.control.value;
130     split_spinbutton = GTK_WIDGET(gtk_builder_get_object(ui, "split_spinbutton"));
131     gtk_spin_button_set_value(GTK_SPIN_BUTTON(split_spinbutton), Splitnote);
132     }
133     }
134     /* duplicate controller event */
135     snd_seq_ev_clear(&dup);
136     memcpy(&dup, ev, sizeof(dup));
137     // snd_seq_ev_set_controller(&dup, ev->data.control.channel, ev->data.control.param, ev->data.control.value);
138     /* send data on the two ports */
139     snd_seq_ev_set_source(ev, alsa->low_outport_id);
140     snd_seq_ev_set_source(&dup, alsa->high_outport_id);
141    
142     snd_seq_ev_set_subs(ev);
143     snd_seq_ev_set_subs(&dup);
144    
145     snd_seq_ev_set_direct(ev);
146     snd_seq_ev_set_direct(&dup);
147    
148     snd_seq_event_output(alsa->handler, ev);
149     snd_seq_event_output(alsa->handler, &dup);
150    
151     snd_seq_drain_output(alsa->handler);
152     break;
153     case SND_SEQ_EVENT_NOTEON:
154     if (!Channel || ev->data.note.channel == Channel) {
155     i = 0;
156     while (i < memory_len && memory[i].note != '\0') {
157     ++i;
158     }
159     if (i >= memory_len) {
160     memory = (struct mem_t*) realloc(memory, (memory_len + 1)*sizeof(struct mem_t));
161     memory_len += 1;
162     }
163     /* memorize the note and its transposition value */
164     memory[i].channel = ev->data.note.channel;
165     memory[i].note = ev->data.note.note;
166     memory[i].split = point;
167     /* apply splitting */
168     if (ev->data.note.note < Splitnote) {
169     snd_seq_ev_set_source(ev, alsa->low_outport_id);
170     } else {
171     snd_seq_ev_set_source(ev, alsa->high_outport_id);
172     }
173     }
174     snd_seq_ev_set_subs(ev);
175     snd_seq_event_output_direct(alsa->handler, ev);
176     break;
177     case SND_SEQ_EVENT_NOTEOFF:
178     if (!Channel || ev->data.note.channel == Channel) {
179     i = 0;
180     /* search matching note in memory */
181     while (i < memory_len && \
182     (memory[i].channel != ev->data.note.channel || \
183     memory[i].note != ev->data.note.note)) {
184     ++i;
185     }
186     if (i >= memory_len) {
187     /* should not append */
188     /* do nothing */
189     } else {
190     /* apply memorized split */
191     if (memory[i].note == ev->data.note.note) {
192     if (ev->data.note.note < memory[i].split) {
193     snd_seq_ev_set_source(ev, alsa->low_outport_id);
194     } else {
195     snd_seq_ev_set_source(ev, alsa->high_outport_id);
196     }
197     }
198     /* then forget */
199     memory[i].note = '\0';
200     }
201     }
202     snd_seq_ev_set_subs(ev);
203     snd_seq_event_output_direct(alsa->handler, ev);
204     break;
205     }
206     return;
207     }
208    
209     /* MIDI input callback */
210     gboolean handle_midi_input (GIOChannel* midi_input, GIOCondition cond, gpointer user_data)
211     {
212     snd_seq_event_t* ev;
213     alsa_t* alsa = (alsa_t*) user_data;
214     do {
215     snd_seq_event_input(alsa->handler, &ev);
216     do_split(ev, alsa, Splitnote);
217     } while (snd_seq_event_input_pending(alsa->handler, 0) > 0);
218     cond = 0;
219     midi_input = NULL;
220     return TRUE;
221     }
222    
223     /* starting point */
224     int main (int argc, char* argv[])
225     {
226 ben 20 char* argv1;
227 ben 1 GIOChannel* midi_input;
228     int alsa_input_fd;
229     alsa_t alsa;
230    
231     /* initialize language translation */
232     #ifdef ENABLE_NLS
233     bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
234     bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
235     textdomain (GETTEXT_PACKAGE);
236     #endif
237     /* initialize gtk+ */
238     gtk_set_locale();
239     gtk_init(&argc, &argv);
240    
241     memset(Instance, '\0', 1);
242     strncat(Instance, "PIDIM Split Port ", 64);
243 ben 20
244 ben 1 /* read extra parameters */
245 ben 20 argv1 = cli_parse (argc, argv, "A Keyboard Splitter over 2 ports", \
246     "Enter the split point note number to control 2 MIDI sets with one keyboard.");
247     if (argv1) {
248     strncat(Instance, argv1, 48);
249 ben 1 }
250    
251     /* create window */
252     ui_new();
253     ui_show();
254    
255     /* initialize alsa stuff */
256     alsa.handler = alsa_open_client(Instance);
257     if (!alsa.handler) {
258     exit(EXIT_FAILURE);
259     }
260     alsa.inport_id = alsa_open_input_port(alsa.handler, "IN");
261     alsa.high_outport_id = alsa_open_output_port(alsa.handler, "OUT/UP");
262     alsa.low_outport_id = alsa_open_output_port(alsa.handler, "OUT/BOTTOM");
263     alsa_input_fd = alsa_get_fd(alsa.handler);
264     midi_input = g_io_channel_unix_new(alsa_input_fd);
265     g_io_add_watch(midi_input, G_IO_IN, handle_midi_input, &alsa);
266    
267     gtk_main();
268     exit(EXIT_SUCCESS);
269     }
270    

  ViewVC Help
Powered by ViewVC 1.1.26