1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 	a_channel.h - Audio Engine high level control abstraction
4 ---------------------------------------------------------------------------
5  * Copyright (C) 2001, 2002, David Olofson
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22 #ifndef _A_CHANNEL_H_
23 #define _A_CHANNEL_H_
24 
25 #include "a_globals.h"
26 #include "a_types.h"
27 #include "a_voice.h"
28 
29 
30 /*----------------------------------------------------------
31 	Audio Group (Abstraction for group control)
32 ----------------------------------------------------------*/
33 typedef struct audio_group_t
34 {
35 	int		changed;
36 	accbank_t	ctl;
37 } audio_group_t;
38 
39 
40 /*----------------------------------------------------------
41 	Audio Channel (Abstraction for channel control)
42 ----------------------------------------------------------*/
43 typedef struct audio_channel_t
44 {
45 	audio_voice_t	*voices;	/* For "real" voices only */
46 
47 	int		playing;	/* # of "voices" playing */
48 	accbank_t	rctl;		/* Raw controls */
49 	accbank_t	ctl;		/* Transformed controls */
50 
51 	/* Event Control */
52 	aev_port_t	port;		/* Event input port */
53 
54 	patch_closure_t	closure;	/* Per-channel data for patch */
55 } audio_channel_t;
56 
57 
58 /*----------------------------------------------------------
59 	Audio Channel Event Interface
60 ------------------------------------------------------------
61  * These events are passed through the channel management
62  * code of the engine, where they are transformed through
63  * the groups. Then they're passed on directly to the patch
64  * plugins for custom processing.
65  *
66  * Notes:
67  *	* The rctl array (raw controls) is kept up to date
68  *	  by the engine.
69  *
70  *	* The ctl array (transformed controls) must be
71  *	  updated by the patch plugin as it receives the
72  *	  corresponding events.
73  *
74  *	* For things to work properly, patch plugins must
75  *	  remove all events for each frame processed.
76  *
77  *	* Tags passed to CE_CONTROL[2] can be any positive
78  *	  value including 0. Negative values are reserved
79  *	  for special uses: -1 means "all voices", whereas
80  *	  -2 means "new voices only"; ie -2 will cause no
81  *	  other action than updating the channel control
82  *	  values.
83  */
84 typedef enum channel_events_t
85 {
86 	CE_START = 0,	/* arg1 = tag, arg2 = pitch, arg3 = velocity */
87 	CE_STOP,	/* arg1 = tag, arg2 = velocity */
88 	CE_CONTROL	/* arg1 = tag, index = ctl, arg2 = value */
89 } channel_events_t;
90 
91 
92 /*
93  * Inline interface for sending the above events...
94  */
95 
ce_start_i(audio_channel_t * c,Uint16 delay,int tag,int pitch,int velocity)96 static inline aev_event_t *ce_start_i(audio_channel_t *c, Uint16 delay,
97 		int tag, int pitch, int velocity)
98 {
99 	aev_event_t *ev = aev_new();
100 	if(!ev)
101 		return NULL;
102 	ev->type = CE_START;
103 	ev->frame = delay + aev_timer;
104 	ev->arg1 = tag;
105 	ev->arg2 = pitch;
106 	ev->arg3 = velocity;
107 	aev_insert(&c->port, ev);
108 	return ev;
109 }
110 
ce_stop_i(audio_channel_t * c,Uint16 delay,int tag,int velocity)111 static inline aev_event_t *ce_stop_i(audio_channel_t *c, Uint16 delay,
112 		int tag, int velocity)
113 {
114 	aev_event_t *ev = aev_new();
115 	if(!ev)
116 		return NULL;
117 	ev->type = CE_STOP;
118 	ev->frame = delay + aev_timer;
119 	ev->arg1 = tag;
120 	ev->arg2 = velocity;
121 	aev_insert(&c->port, ev);
122 	return ev;
123 }
124 
ce_control_i(audio_channel_t * c,Uint16 delay,int tag,Uint8 ctl,int value)125 static inline aev_event_t *ce_control_i(audio_channel_t *c, Uint16 delay,
126 		int tag, Uint8 ctl, int value)
127 {
128 	aev_event_t *ev = aev_new();
129 	if(!ev)
130 		return NULL;
131 	ev->type = CE_CONTROL;
132 	ev->frame = delay + aev_timer;
133 	ev->arg1 = tag;
134 	ev->index = ctl;
135 	ev->arg2 = value;
136 	aev_insert(&c->port, ev);
137 	return ev;
138 }
139 
140 
141 /*
142  * Fast, non-sorting versions.
143  */
144 
ce_start(audio_channel_t * c,Uint16 delay,int tag,int pitch,int velocity)145 static inline aev_event_t *ce_start(audio_channel_t *c, Uint16 delay,
146 		int tag, int pitch, int velocity)
147 {
148 	aev_event_t *ev = aev_new();
149 	if(!ev)
150 		return NULL;
151 	ev->type = CE_START;
152 	ev->frame = delay + aev_timer;
153 	ev->arg1 = tag;
154 	ev->arg2 = pitch;
155 	ev->arg3 = velocity;
156 	aev_write(&c->port, ev);
157 	return ev;
158 }
159 
ce_stop(audio_channel_t * c,Uint16 delay,int tag,int velocity)160 static inline aev_event_t *ce_stop(audio_channel_t *c, Uint16 delay,
161 		int tag, int velocity)
162 {
163 	aev_event_t *ev = aev_new();
164 	if(!ev)
165 		return NULL;
166 	ev->type = CE_STOP;
167 	ev->frame = delay + aev_timer;
168 	ev->arg1 = tag;
169 	ev->arg2 = velocity;
170 	aev_write(&c->port, ev);
171 	return ev;
172 }
173 
ce_control(audio_channel_t * c,Uint16 delay,int tag,Uint8 ctl,int value)174 static inline aev_event_t *ce_control(audio_channel_t *c, Uint16 delay,
175 		int tag, Uint8 ctl, int value)
176 {
177 	aev_event_t *ev = aev_new();
178 	if(!ev)
179 		return NULL;
180 	ev->type = CE_CONTROL;
181 	ev->frame = delay + aev_timer;
182 	ev->arg1 = tag;
183 	ev->index = ctl;
184 	ev->arg2 = value;
185 	aev_write(&c->port, ev);
186 	return ev;
187 }
188 
189 
190 /*
191  * Brutally stop all voices on all channels.
192  *
193  * (Obviously, any other method is better - short of
194  * crashing the engine, perhaps... ;-)
195  */
196 void channel_stop_all(void);
197 
198 
199 /*
200  * Process events and patch plugins for all channels.
201  */
202 void channel_process_all(unsigned frames);
203 
204 void audio_channel_open(void);
205 void audio_channel_close(void);
206 
207 
208 /*----------------------------------------------------------
209 	Voice allocation stuff
210 ----------------------------------------------------------*/
211 
212 /* Link voice 'v' to channel 'c'. */
chan_link_voice(audio_channel_t * c,audio_voice_t * v)213 static inline void chan_link_voice(audio_channel_t *c, audio_voice_t *v)
214 {
215 	v->next = c->voices;
216 	if(v->next)
217 		v->next->prev = v;
218 	v->prev = NULL;
219 	v->channel = c;
220 	c->voices = v;
221 }
222 
223 /* Unlink voice 'v' from channel 'c'. */
chan_unlink_voice(audio_voice_t * v)224 static inline void chan_unlink_voice(audio_voice_t *v)
225 {
226 	if(v->prev)
227 	{
228 		v->prev->next = v->next;
229 		if(v->next)
230 			v->next->prev = v->prev;
231 	}
232 	else
233 	{
234 		v->channel->voices = v->next;
235 		if(v->next)
236 			v->next->prev = NULL;
237 	}
238 	v->channel = NULL;
239 }
240 
chan_get_first_voice(audio_channel_t * c)241 static inline audio_voice_t *chan_get_first_voice(audio_channel_t *c)
242 {
243 	return c->voices;
244 }
245 
chan_get_next_voice(audio_voice_t * v)246 static inline audio_voice_t *chan_get_next_voice(audio_voice_t *v)
247 {
248 	return v->next;
249 }
250 
251 #endif /*_A_CHANNEL_H_*/
252