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

Contents of /src/pidim_split_port.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Thu Aug 26 16:46:46 2010 UTC (10 years ago) by ben
File MIME type: text/plain
File size: 8421 byte(s)
fixed doc install
1 /* 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 #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 gtk_spin_button_set_range(GTK_SPIN_BUTTON(split_spinbutton), 0, 127);
62 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 gtk_spin_button_set_range(GTK_SPIN_BUTTON(controller_spinbutton), 0, 127);
65 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 gtk_spin_button_set_range(GTK_SPIN_BUTTON(channel_spinbutton), 0, 16);
68 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 GIOChannel* midi_input;
227 int alsa_input_fd;
228 alsa_t alsa;
229
230 /* initialize language translation */
231 #ifdef ENABLE_NLS
232 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
233 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
234 textdomain (GETTEXT_PACKAGE);
235 #endif
236 /* initialize gtk+ */
237 gtk_set_locale();
238 gtk_init(&argc, &argv);
239
240 memset(Instance, '\0', 1);
241 strncat(Instance, "PIDIM Split Port ", 64);
242 /* read extra parameters */
243 if (argc == 2) {
244 strncat(Instance, argv[1], 48);
245 }
246
247 /* create window */
248 ui_new();
249 ui_show();
250
251 /* initialize alsa stuff */
252 alsa.handler = alsa_open_client(Instance);
253 if (!alsa.handler) {
254 exit(EXIT_FAILURE);
255 }
256 alsa.inport_id = alsa_open_input_port(alsa.handler, "IN");
257 alsa.high_outport_id = alsa_open_output_port(alsa.handler, "OUT/UP");
258 alsa.low_outport_id = alsa_open_output_port(alsa.handler, "OUT/BOTTOM");
259 alsa_input_fd = alsa_get_fd(alsa.handler);
260 midi_input = g_io_channel_unix_new(alsa_input_fd);
261 g_io_add_watch(midi_input, G_IO_IN, handle_midi_input, &alsa);
262
263 gtk_main();
264 exit(EXIT_SUCCESS);
265 }
266

  ViewVC Help
Powered by ViewVC 1.1.26