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

Contents of /src/pidim_transpose.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: 7266 byte(s)
fixed doc install
1 /* pidim_transpose, a small Gtk+/ALSA MIDI note transposer
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 outport_id; /* id of output port 0 */
37 } alsa_t;
38
39 /* globals */
40 GtkBuilder* ui = NULL;
41 int Transpose = 0;
42 int Controller = 0;
43 int Channel = 0;
44 char Instance[64];
45
46 /* Gtk stuff */
47 void ui_new (void)
48 {
49 gchar* ui_path = NULL;
50 GtkWidget *transpose_spinbutton, *controller_spinbutton, *channel_spinbutton;
51
52 if (g_file_test("./pidim_transpose.ui", G_FILE_TEST_EXISTS))
53 ui_path = "./pidim_transpose.ui";
54 else
55 ui_path = PACKAGE_DATA_DIR"/pidim/ui/pidim_transpose.ui";
56
57 ui = gtk_builder_new();
58 gtk_builder_add_from_file(ui, ui_path, NULL);
59 transpose_spinbutton = GTK_WIDGET(gtk_builder_get_object(ui, "transpose_spinbutton"));
60 gtk_spin_button_set_range(GTK_SPIN_BUTTON(transpose_spinbutton), -64, 63);
61 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(transpose_spinbutton), 1, 0);
62 controller_spinbutton = GTK_WIDGET(gtk_builder_get_object(ui, "controller_spinbutton"));
63 gtk_spin_button_set_range(GTK_SPIN_BUTTON(controller_spinbutton), 0, 127);
64 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(controller_spinbutton), 1, 0);
65 channel_spinbutton = GTK_WIDGET(gtk_builder_get_object(ui, "channel_spinbutton"));
66 gtk_spin_button_set_range(GTK_SPIN_BUTTON(channel_spinbutton), 0, 16);
67 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(channel_spinbutton), 1, 0);
68
69 gtk_builder_connect_signals(ui, NULL);
70 gtk_window_set_default_icon_from_file(PACKAGE_DATA_DIR"/pidim/ui/pidim.png", NULL);
71 }
72
73 void ui_show()
74 {
75 GtkWidget* main_window = GTK_WIDGET(gtk_builder_get_object(ui, "main_window"));
76 gtk_window_set_title(GTK_WINDOW(main_window), Instance);
77 gtk_widget_show_all(main_window);
78
79 }
80 gboolean on_main_window_delete_event(GtkWidget* main_window, GdkEvent* null1, gpointer null2) {
81 null1 = NULL;
82 null2 = NULL;
83 gtk_main_quit();
84 return TRUE;
85 }
86
87 /* callback called when the user interacts on transpose spin button */
88 void on_transpose_spinbutton_value_changed(GtkSpinButton* spin_button, gpointer* null) {
89 Transpose = (int) gtk_spin_button_get_value_as_int(spin_button);
90 null = NULL;
91 }
92
93 /* callback called when the user interacts on controller spin button */
94 void on_controller_spinbutton_value_changed(GtkSpinButton* spin_button, gpointer* null)
95 {
96 Controller = (unsigned char) gtk_spin_button_get_value_as_int(spin_button);
97 null = NULL;
98 }
99
100 /* callback called when the user interacts on channel spin button */
101 void on_channel_spinbutton_value_changed(GtkSpinButton* spin_button, gpointer* null) {
102 Channel = (int) gtk_spin_button_get_value_as_int(spin_button);
103 null = NULL;
104 }
105
106 /* transposition operation on midi events */
107 void do_transpose (snd_seq_event_t* ev, int val)
108 {
109 GtkWidget* transpose_spinbutton;
110 int i;
111 /* stuff needed to not loose matching ON/OFF even if 'val' has changed between note completion */
112 struct mem_t {
113 unsigned char channel;
114 unsigned char note;
115 int tr;
116 };
117 static struct mem_t* memory = NULL;
118 static int memory_len = 0;
119
120 if ((ev->type == SND_SEQ_EVENT_NOTEON) && (ev->data.note.velocity == 0))
121 ev->type = SND_SEQ_EVENT_NOTEOFF;
122
123 switch (ev->type) {
124 case SND_SEQ_EVENT_CONTROLLER:
125 if (!Channel || ev->data.control.channel == Channel) {
126 if (ev->data.control.param == Controller) {
127 val = Transpose = ev->data.control.value;
128 transpose_spinbutton = GTK_WIDGET(gtk_builder_get_object(ui, "transpose_spinbutton"));
129 gtk_spin_button_set_value(GTK_SPIN_BUTTON(transpose_spinbutton), Transpose);
130 }
131 }
132 break;
133 case SND_SEQ_EVENT_NOTEON:
134 if (!Channel || ev->data.note.channel == Channel) {
135 i = 0;
136 while (i < memory_len && memory[i].note != '\0') {
137 ++i;
138 }
139 if (i >= memory_len) {
140 memory = (struct mem_t*) realloc(memory, (memory_len + 1)*sizeof(struct mem_t));
141 memory_len += 1;
142 }
143 /* memorize the note and its transposition value */
144 memory[i].channel = ev->data.note.channel;
145 memory[i].note = ev->data.note.note;
146 memory[i].tr = val;
147 /* apply transposition */
148 ev->data.note.note += val;
149 }
150 break;
151 case SND_SEQ_EVENT_NOTEOFF:
152 if (!Channel || ev->data.note.channel == Channel) {
153 i = 0;
154 /* search matching note in memory */
155 while (i < memory_len && \
156 (memory[i].channel != ev->data.note.channel || \
157 memory[i].note != ev->data.note.note)) {
158 ++i;
159 }
160 if (i >= memory_len) {
161 /* should not append */
162 /* do nothing */
163 } else {
164 ev->data.note.note += memory[i].tr; /* apply memorized transposition */
165 /* then forget */
166 memory[i].note = '\0';
167 }
168 }
169 break;
170 }
171 return;
172 }
173
174 /* MIDI input callback */
175 gboolean handle_midi_input (GIOChannel* midi_input, GIOCondition cond, gpointer user_data)
176 {
177 snd_seq_event_t* ev;
178 alsa_t* alsa = (alsa_t*) user_data;
179 do {
180 snd_seq_event_input(alsa->handler, &ev);
181 do_transpose(ev, Transpose);
182 snd_seq_ev_set_source(ev, alsa->outport_id);
183 snd_seq_ev_set_subs(ev);
184 snd_seq_event_output_direct(alsa->handler, ev);
185 } while (snd_seq_event_input_pending(alsa->handler, 0) > 0);
186 cond = 0;
187 midi_input = NULL;
188 return TRUE;
189 }
190
191 /* starting point */
192 int main (int argc, char* argv[])
193 {
194 GIOChannel* midi_input;
195 int alsa_input_fd;
196 alsa_t alsa;
197
198 /* initialize language translation */
199 #ifdef ENABLE_NLS
200 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
201 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
202 textdomain (GETTEXT_PACKAGE);
203 #endif
204 /* initialize gtk+ */
205 gtk_set_locale();
206 gtk_init(&argc, &argv);
207
208 memset(Instance, '\0', 1);
209 strncat(Instance, "PIDIM Transpose ", 64);
210 /* read extra parameters */
211 if (argc == 2) {
212 strncat(Instance, argv[1], 48);
213 }
214
215 /* create window */
216 ui_new();
217 ui_show();
218
219 /* initialize alsa stuff */
220 alsa.handler = alsa_open_client(Instance);
221 if (!alsa.handler) {
222 exit(EXIT_FAILURE);
223 }
224 alsa.inport_id = alsa_open_input_port(alsa.handler, "IN");
225 alsa.outport_id = alsa_open_output_port(alsa.handler, "OUT");
226 alsa_input_fd = alsa_get_fd(alsa.handler);
227 midi_input = g_io_channel_unix_new(alsa_input_fd);
228 g_io_add_watch(midi_input, G_IO_IN, handle_midi_input, &alsa);
229
230 gtk_main();
231 exit(EXIT_SUCCESS);
232 }
233

  ViewVC Help
Powered by ViewVC 1.1.26