merge Marcel Bonnet's patches for Free-BSD
[ardour.git] / libs / fst / vsti.c
1 /*
2  *   VST instrument support
3  *
4  *   Derived from code that was marked:    
5  *   Copyright (C) Kjetil S. Matheussen 2004 (k.s.matheussen@notam02.no)
6  *   Alsa-seq midi-code made by looking at the jack-rack source made by Bob Ham.
7  *    
8  *   This program is free software; you can redistribute it and/or modify
9  *   it under the terms of the GNU General Public License as published by
10  *   the Free Software Foundation; either version 2 of the License, or
11  *   (at your option) any later version.
12  *
13  *   This program is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  *   $Id: vsti.c,v 1.2 2004/04/07 01:56:23 pauld Exp $
23  */
24
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <memory.h>
30 #include <fcntl.h>
31 #include <stdbool.h>
32 #include <jackvst.h>
33 #include <pthread.h>
34 #include <sched.h>
35 #include "ardour/vestige/aeffectx.h"
36
37 #ifdef WITH_ALSA
38
39 snd_seq_t *
40 create_sequencer (const char* client_name, bool isinput)
41 {
42         snd_seq_t * seq;
43         int err;
44         
45         if ((err = snd_seq_open (&seq, "default", SND_SEQ_OPEN_DUPLEX, 0)) != 0) {
46                 fst_error ("Could not open ALSA sequencer, aborting\n\n%s\n\n"
47                            "Make sure you have configure ALSA properly and that\n"
48                            "/proc/asound/seq/clients exists and contains relevant\n"
49                            "devices (%s).", 
50                            snd_strerror (err));
51                 return NULL;
52         }
53         
54         snd_seq_set_client_name (seq, client_name);
55         
56         if ((err = snd_seq_create_simple_port (seq, isinput? "Input" : "Output",
57                                                (isinput? SND_SEQ_PORT_CAP_WRITE: SND_SEQ_PORT_CAP_READ)| SND_SEQ_PORT_CAP_DUPLEX |
58                                                SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_SUBS_WRITE,
59                                                SND_SEQ_PORT_TYPE_APPLICATION|SND_SEQ_PORT_TYPE_SPECIFIC)) != 0) {
60                 fst_error ("Could not create ALSA port: %s", snd_strerror (err));
61                 snd_seq_close(seq);
62                 return NULL;
63         }
64         
65         return seq;
66 }
67
68 static void 
69 queue_midi (JackVST *jvst, int val1, int val2, int val3)
70 {
71         VstMidiEvent *pevent;
72         jack_ringbuffer_data_t vec[2];
73
74         jack_ringbuffer_get_write_vector (jvst->event_queue, vec);
75
76         if (vec[0].len < sizeof (VstMidiEvent)) {
77                 fst_error ("event queue has no write space");
78                 return;
79         }
80                 
81         pevent = (VstMidiEvent *) vec[0].buf;
82
83         //  printf("note: %d\n",note);
84         
85         pevent->type = kVstMidiType;
86         pevent->byteSize = 24;
87         pevent->deltaFrames = 0;
88         pevent->flags = 0;
89         pevent->detune = 0;
90         pevent->noteLength = 0;
91         pevent->noteOffset = 0;
92         pevent->reserved1 = 0;
93         pevent->reserved2 = 0;
94         pevent->noteOffVelocity = 0;
95         pevent->midiData[0] = val1;
96         pevent->midiData[1] = val2;
97         pevent->midiData[2] = val3;
98         pevent->midiData[3] = 0;
99         
100         //printf("Sending: %x %x %x\n",val1,val2,val3);
101
102         jack_ringbuffer_write_advance (jvst->event_queue, sizeof (VstMidiEvent));
103 }
104
105 void *midireceiver(void *arg)
106 {
107         snd_seq_event_t *event;
108         JackVST *jvst = (JackVST* )arg;
109         int val;
110
111         struct sched_param scp;
112         scp.sched_priority = 50;
113
114         // Try to set fifo priority...
115         // this works, if we are root or newe sched-cap manegment is used...
116         pthread_setschedparam( pthread_self(), SCHED_FIFO, &scp ); 
117         
118         while (1) {
119
120                 snd_seq_event_input (jvst->seq, &event);
121
122                 if (jvst->midiquit) {
123                         break;
124                 }
125
126                 switch(event->type){
127                 case SND_SEQ_EVENT_NOTEON:
128                         queue_midi(jvst,0x90+event->data.note.channel,event->data.note.note,event->data.note.velocity);
129                         //printf("Noteon, channel: %d note: %d vol: %d\n",event->data.note.channel,event->data.note.note,event->data.note.velocity);
130                         break;
131                 case SND_SEQ_EVENT_NOTEOFF:
132                         queue_midi(jvst,0x80+event->data.note.channel,event->data.note.note,0);
133                         //printf("Noteoff, channel: %d note: %d vol: %d\n",event->data.note.channel,event->data.note.note,event->data.note.velocity);
134                         break;
135                 case SND_SEQ_EVENT_KEYPRESS:
136                         //printf("Keypress, channel: %d note: %d vol: %d\n",event->data.note.channel,event->data.note.note,event->data.note.velocity);
137                         queue_midi(jvst,0xa0+event->data.note.channel,event->data.note.note,event->data.note.velocity);
138                         break;
139                 case SND_SEQ_EVENT_CONTROLLER:
140                         queue_midi(jvst,0xb0+event->data.control.channel,event->data.control.param,event->data.control.value);
141                         //printf("Control: %d %d %d\n",event->data.control.channel,event->data.control.param,event->data.control.value);
142                         break;
143                 case SND_SEQ_EVENT_PITCHBEND:
144                         val=event->data.control.value + 0x2000;
145                         queue_midi(jvst,0xe0+event->data.control.channel,val&127,val>>7);
146                         //printf("Pitch: %d %d %d\n",event->data.control.channel,event->data.control.param,event->data.control.value);
147                         break;
148                 case SND_SEQ_EVENT_CHANPRESS:
149                         //printf("chanpress: %d %d %d\n",event->data.control.channel,event->data.control.param,event->data.control.value);
150                         queue_midi(jvst,0xd0+event->data.control.channel,event->data.control.value,0);
151                         break;
152                 case SND_SEQ_EVENT_PGMCHANGE:
153                         //printf("pgmchange: %d %d %d\n",event->data.control.channel,event->data.control.param,event->data.control.value);
154                         queue_midi(jvst,0xc0+event->data.control.channel,event->data.control.value,0);
155                         break;
156                 default:
157                         //printf("Unknown type: %d\n",event->type);
158                         break;
159                 }
160         }
161         
162         return NULL;
163 }
164
165 void stop_midireceiver (JackVST *jvst)
166 {
167         int err; 
168         snd_seq_event_t event;
169         snd_seq_t *seq2 = create_sequencer ("jfstquit", true);
170         
171         jvst->midiquit = 1;
172         
173         snd_seq_connect_to (seq2, 0, snd_seq_client_id (jvst->seq),0);
174         snd_seq_ev_clear      (&event);
175         snd_seq_ev_set_direct (&event);
176         snd_seq_ev_set_subs   (&event);
177         snd_seq_ev_set_source (&event, 0);
178         snd_seq_ev_set_controller (&event,1,0x80,50);
179         
180         if ((err = snd_seq_event_output (seq2, &event)) < 0) {
181                 fst_error ("cannot send stop event to midi thread: %s\n",
182                            snd_strerror (err));
183         }
184
185         snd_seq_drain_output (seq2);
186         snd_seq_close (seq2);
187         pthread_join (jvst->midi_thread,NULL);
188         snd_seq_close (jvst->seq);
189 }
190 #endif
191
192