make midimap obey channels
[galan.git] / plugins / libemu10k1.c
blobe4d4ac984c1ac09acceeeec80fafc4f5ed291684
1 /* gAlan - Graphical Audio Language
2 * Copyright (C) 1999 Tony Garnock-Jones
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.
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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
25 #include <sys/soundcard.h>
26 #include <fcntl.h>
27 #include <unistd.h>
29 #include <gdk/gdk.h>
30 #include <gtk/gtk.h>
32 #include "global.h"
33 #include "generator.h"
34 #include "comp.h"
35 #include "control.h"
36 #include "gencomp.h"
37 #include "msgbox.h"
38 #include "prefs.h"
40 #define SIG_LEFT_FRONT_CHANNEL 0
41 #define SIG_RIGHT_FRONT_CHANNEL 1
42 #define SIG_LEFT_REAR_CHANNEL 2
43 #define SIG_RIGHT_REAR_CHANNEL 3
45 #define DEFAULT_FRAGMENT_EXPONENT 12
47 typedef signed short OUTPUTSAMPLE;
49 typedef struct EmuData {
50 int audiofd1, audiofd2;
51 gint input_tag;
52 AClock *clock;
53 } EmuData;
55 PRIVATE int instance_count = 0;
56 PRIVATE int audio_fragment_exponent = DEFAULT_FRAGMENT_EXPONENT;
58 PRIVATE void audio_play_fragment(int audiofd, SAMPLE *left, SAMPLE *right, int length) {
59 OUTPUTSAMPLE *outbuf;
60 int buflen = length * sizeof(OUTPUTSAMPLE) * 2;
61 int i;
63 if (length <= 0)
64 return;
66 outbuf = malloc(buflen);
67 RETURN_UNLESS(outbuf != NULL);
69 for (i = 0; i < length; i++) {
70 outbuf[i<<1] = (OUTPUTSAMPLE) MIN(MAX(left[i] * 32767, -32768), 32767);
71 outbuf[(i<<1) + 1] = (OUTPUTSAMPLE) MIN(MAX(right[i] * 32767, -32768), 32767);
74 write(audiofd, outbuf, buflen);
75 free(outbuf);
78 PRIVATE int open_audiofd(int nr) {
79 int i;
80 int audiofd;
82 audiofd = open(nr==0 ? "/dev/dsp" : "/dev/dsp1", O_WRONLY);
83 RETURN_VAL_UNLESS(audiofd != -1, -1);
85 i = (4 << 16) | audio_fragment_exponent; /* 4 buffers */
86 RETURN_VAL_UNLESS(ioctl(audiofd, SNDCTL_DSP_SETFRAGMENT, &i) != -1, -1);
88 i = AFMT_S16_LE;
89 RETURN_VAL_UNLESS(ioctl(audiofd, SNDCTL_DSP_SETFMT, &i) != -1, -1);
91 i = 1;
92 RETURN_VAL_UNLESS(ioctl(audiofd, SNDCTL_DSP_STEREO, &i) != -1, -1);
94 i = 44100;
95 RETURN_VAL_UNLESS(ioctl(audiofd, SNDCTL_DSP_SPEED, &i) != -1, -1);
97 return audiofd;
100 PRIVATE void clock_handler(AClock *clock, AClockReason reason) {
101 EmuData *data = clock->gen->data;
103 switch (reason) {
104 case CLOCK_DISABLE:
105 gdk_input_remove(data->input_tag);
106 data->input_tag = -1;
107 break;
109 case CLOCK_ENABLE:
110 if (data->input_tag == -1)
111 data->input_tag = gdk_input_add(data->audiofd1, GDK_INPUT_WRITE,
112 (GdkInputFunction) gen_clock_mainloop, NULL);
113 break;
115 default:
116 g_message("Unreachable code reached (emu_output)... reason = %d", reason);
117 break;
121 PRIVATE void realtime_handler(Generator *g, AEvent *event) {
122 EmuData *data = g->data;
124 switch (event->kind) {
125 case AE_REALTIME: {
126 SAMPLE *lf_buf, *rf_buf, *lr_buf, *rr_buf;
127 int bufbytes = event->d.integer * sizeof(SAMPLE);
129 lf_buf = safe_malloc(bufbytes);
130 rf_buf = safe_malloc(bufbytes);
131 lr_buf = safe_malloc(bufbytes);
132 rr_buf = safe_malloc(bufbytes);
134 if (!gen_read_realtime_input(g, SIG_LEFT_FRONT_CHANNEL, -1, lf_buf, event->d.integer))
135 memset(lf_buf, 0, bufbytes);
137 if (!gen_read_realtime_input(g, SIG_RIGHT_FRONT_CHANNEL, -1, rf_buf, event->d.integer))
138 memset(rf_buf, 0, bufbytes);
140 if (!gen_read_realtime_input(g, SIG_LEFT_REAR_CHANNEL, -1, lr_buf, event->d.integer))
141 memset(lr_buf, 0, bufbytes);
143 if (!gen_read_realtime_input(g, SIG_RIGHT_REAR_CHANNEL, -1, rr_buf, event->d.integer))
144 memset(rr_buf, 0, bufbytes);
146 audio_play_fragment(data->audiofd1, lf_buf, rf_buf, event->d.integer);
147 audio_play_fragment(data->audiofd2, lr_buf, rr_buf, event->d.integer);
148 free(lf_buf);
149 free(rf_buf);
150 free(lr_buf);
151 free(rr_buf);
153 break;
156 default:
157 g_warning("emu_output module doesn't care for events of kind %d.", event->kind);
158 break;
162 PRIVATE int init_instance(Generator *g) {
163 EmuData *data;
165 instance_count++;
166 if (instance_count > 1)
167 /* Not allowed more than one of these things. */
168 return 0;
170 data = safe_malloc(sizeof(EmuData));
172 data->audiofd1 = open_audiofd(0);
174 if (data->audiofd1 < 0) {
175 free(data);
176 popup_msgbox("Error", MSGBOX_OK, 120000, MSGBOX_OK,
177 "Could not open audio device, %s.", "/dev/dsp");
178 return 0;
181 data->audiofd2 = open_audiofd(1);
183 if (data->audiofd2 < 0) {
184 free(data);
185 popup_msgbox("Error", MSGBOX_OK, 120000, MSGBOX_OK,
186 "Could not open audio device, %s.", "/dev/dsp1");
187 return 0;
190 data->input_tag = -1;
191 data->clock = gen_register_clock(g, "Emu Output Clock", clock_handler);
193 g->data = data;
195 gen_register_realtime_fn(g, realtime_handler);
196 gen_select_clock(data->clock); /* a not unreasonable assumption? */
198 return 1;
201 PRIVATE void destroy_instance(Generator *g) {
202 EmuData *data = g->data;
204 gen_deregister_realtime_fn(g, realtime_handler);
206 if (data != NULL) {
207 gen_deregister_clock(data->clock);
208 if (data->input_tag != -1)
209 gdk_input_remove(data->input_tag);
210 close(data->audiofd1);
211 close(data->audiofd2);
213 free(data);
216 instance_count--;
219 PRIVATE InputSignalDescriptor input_sigs[] = {
220 { "Left Front Channel", SIG_FLAG_REALTIME },
221 { "Right Front Channel", SIG_FLAG_REALTIME },
222 { "Left Rear Channel", SIG_FLAG_REALTIME },
223 { "Right Rear Channel", SIG_FLAG_REALTIME },
224 { NULL, }
227 PRIVATE void setup_class(void) {
228 GeneratorClass *k;
231 char *name = prefs_get_item("output_emu_fragment_size");
233 if (name == NULL || sscanf(name, "%d", &audio_fragment_exponent) != 1) {
234 audio_fragment_exponent = DEFAULT_FRAGMENT_EXPONENT;
237 audio_fragment_exponent = MAX(audio_fragment_exponent, 7);
239 prefs_register_option("output_emu_fragment_size", "7");
240 prefs_register_option("output_emu_fragment_size", "8");
241 prefs_register_option("output_emu_fragment_size", "9");
242 prefs_register_option("output_emu_fragment_size", "10");
243 prefs_register_option("output_emu_fragment_size", "11");
244 prefs_register_option("output_emu_fragment_size", "12");
245 prefs_register_option("output_emu_fragment_size", "13");
246 prefs_register_option("output_emu_fragment_size", "14");
247 prefs_register_option("output_emu_fragment_size", "15");
248 prefs_register_option("output_emu_fragment_size", "16");
250 k = gen_new_generatorclass("emu_out", FALSE, 0, 0,
251 input_sigs, NULL, NULL,
252 init_instance, destroy_instance,
253 (AGenerator_pickle_t) init_instance, NULL);
255 gencomp_register_generatorclass(k, FALSE, "Outputs/Emu10k1 Output",
256 PIXMAPDIRIFY("oss_output.xpm"),
257 NULL);
260 #include "emu10k1-include/dsp.h"
262 //PRIVATE void dspstuff( void ) {
263 // struct dsp_patch_manager mgr;
264 // int inputs[2] = {0,1};
265 // int outputs[2] = {0,1};
266 // mgr.mixer_fd = open( "/dev/mixer", O_RDWR, 0 );
267 // mgr.dsp_fd = open( "/dev/dsp", O_RDWR, 0 );
268 // dsp_init( &mgr );
269 // dsp_unload_all( &mgr );
270 // dsp_add_route( &mgr, 0, 0 );
271 // dsp_add_route( &mgr, 1, 1 );
272 // dsp_read_patch( &mgr, "/usr/local/share/emu10k1/chorus_2.bin", inputs, outputs, 2,2,1,"brr",0 );
273 // dsp_load( &mgr );
276 extern void init_emuiocomp( void );
277 extern void init_emupatchcomp( void );
278 extern void done_emuiocomp( void );
279 PUBLIC void init_plugin(void) {
280 setup_class();
281 init_emuiocomp();
282 init_emupatchcomp();
284 //dspstuff();