1/*
2 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
3 *
4 * This file is part of the Snack Sound Toolkit.
5 * The latest version can be found at http://www.speech.kth.se/snack/
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "tcl.h"
23#include "jkAudIO.h"
24#include <stdio.h>
25#include <fcntl.h>
26#include <unistd.h>
27
28extern void Snack_WriteLog(char *s);
29extern void Snack_WriteLogInt(char *s, int n);
30
31#ifndef min
32#define min(a,b) ((a)<(b)?(a):(b))
33#define max(a,b) ((a)>(b)?(a):(b))
34#endif
35
36#define SNACK_NUMBER_MIXERS 1
37
38struct MixerLink mixerLinks[SNACK_NUMBER_MIXERS][2];
39
40int
41SnackAudioOpen(ADesc *A, Tcl_Interp *interp, char *device, int mode, int freq,
42	       int nchannels, int encoding)
43{
44  return TCL_OK;
45}
46
47int
48SnackAudioClose(ADesc *A)
49{
50  return(0);
51}
52
53long
54SnackAudioPause(ADesc *A)
55{
56  return(-1);
57}
58
59void
60SnackAudioResume(ADesc *A)
61{
62}
63
64void
65SnackAudioFlush(ADesc *A)
66{
67}
68
69void
70SnackAudioPost(ADesc *A)
71{
72}
73
74int
75SnackAudioRead(ADesc *A, void *buf, int nFrames)
76{
77}
78
79int
80SnackAudioWrite(ADesc *A, void *buf, int nFrames)
81{
82}
83
84int
85SnackAudioReadable(ADesc *A)
86{
87}
88
89int
90SnackAudioWriteable(ADesc *A)
91{
92  return -1;
93}
94
95long
96SnackAudioPlayed(ADesc *A)
97{
98}
99
100void
101SnackAudioInit()
102{
103}
104
105void
106SnackAudioFree()
107{
108  int i, j;
109
110  for (i = 0; i < SNACK_NUMBER_MIXERS; i++) {
111    for (j = 0; j < 2; j++) {
112      if (mixerLinks[i][j].mixer != NULL) {
113	ckfree(mixerLinks[i][j].mixer);
114      }
115      if (mixerLinks[i][j].mixerVar != NULL) {
116	ckfree(mixerLinks[i][j].mixerVar);
117      }
118    }
119    if (mixerLinks[i][0].jack != NULL) {
120      ckfree(mixerLinks[i][0].jack);
121    }
122    if (mixerLinks[i][0].jackVar != NULL) {
123      ckfree((char *)mixerLinks[i][0].jackVar);
124    }
125  }
126}
127
128void
129ASetRecGain(int gain)
130{
131  int g = min(max(gain, 0), 100);
132}
133
134void
135ASetPlayGain(int gain)
136{
137  int g = min(max(gain, 0), 100);
138}
139
140int
141AGetRecGain()
142{
143  int g = 0;
144
145  return(g);
146}
147
148int
149AGetPlayGain()
150{
151  int g = 0;
152
153  return(g);
154}
155
156int
157SnackAudioGetEncodings(char *device)
158{
159  return(LIN16);
160}
161
162void
163SnackAudioGetRates(char *device, char *buf, int n)
164{
165  strncpy(buf, "8000 11025 16000 22050 32000 44100 48000", n);
166  buf[n-1] = '\0';
167}
168
169int
170SnackAudioMaxNumberChannels(char *device)
171{
172  return(2);
173}
174
175int
176SnackAudioMinNumberChannels(char *device)
177{
178  return(1);
179}
180
181void
182SnackMixerGetInputJackLabels(char *buf, int n)
183{
184  buf[0] = '\0';
185}
186
187void
188SnackMixerGetOutputJackLabels(char *buf, int n)
189{
190  buf[0] = '\0';
191}
192
193void
194SnackMixerGetInputJack(char *buf, int n)
195{
196  buf[0] = '\0';
197}
198
199int
200SnackMixerSetInputJack(Tcl_Interp *interp, char *jack, CONST84 char *status)
201{
202  return 1;
203}
204
205void
206SnackMixerGetOutputJack(char *buf, int n)
207{
208  buf[0] = '\0';
209}
210
211void
212SnackMixerSetOutputJack(char *jack, char *status)
213{
214}
215
216void
217SnackMixerGetChannelLabels(char *line, char *buf, int n)
218{
219  strncpy(buf, "Mono", n);
220  buf[n-1] = '\0';
221}
222
223void
224SnackMixerGetVolume(char *line, int channel, char *buf, int n)
225{
226  if (strncasecmp(line, "Play", strlen(line)) == 0) {
227    sprintf(buf, "%d", AGetPlayGain());
228  }
229}
230
231void
232SnackMixerSetVolume(char *line, int channel, int volume)
233{
234  if (strncasecmp(line, "Play", strlen(line)) == 0) {
235    ASetPlayGain(volume);
236  }
237}
238
239void
240SnackMixerLinkJacks(Tcl_Interp *interp, char *jack, Tcl_Obj *var)
241{
242}
243
244static char *
245VolumeVarProc(ClientData clientData, Tcl_Interp *interp, CONST84 char *name1,
246	      CONST84 char *name2, int flags)
247{
248  MixerLink *mixLink = (MixerLink *) clientData;
249  CONST84 char *stringValue;
250
251  if (flags & TCL_TRACE_UNSETS) {
252    if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
253      Tcl_Obj *obj, *var;
254      char tmp[VOLBUFSIZE];
255
256      SnackMixerGetVolume(mixLink->mixer, mixLink->channel, tmp, VOLBUFSIZE);
257      obj = Tcl_NewIntObj(atoi(tmp));
258      var = Tcl_NewStringObj(mixLink->mixerVar, -1);
259      Tcl_ObjSetVar2(interp, var, NULL, obj, TCL_GLOBAL_ONLY | TCL_PARSE_PART1);
260      Tcl_TraceVar(interp, mixLink->mixerVar,
261		   TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
262		   VolumeVarProc, (int *)mixLink);
263    }
264    return (char *) NULL;
265  }
266  stringValue = Tcl_GetVar(interp, mixLink->mixerVar, TCL_GLOBAL_ONLY);
267  if (stringValue != NULL) {
268    SnackMixerSetVolume(mixLink->mixer, mixLink->channel, atoi(stringValue));
269  }
270
271  return (char *) NULL;
272}
273
274void
275SnackMixerLinkVolume(Tcl_Interp *interp, char *line, int n,
276		     Tcl_Obj *CONST objv[])
277{
278  char *mixLabels[] = { "Play" };
279  int i, j, channel;
280  CONST84 char *value;
281  char tmp[VOLBUFSIZE];
282
283  for (i = 0; i < SNACK_NUMBER_MIXERS; i++) {
284    if (strncasecmp(line, mixLabels[i], strlen(line)) == 0) {
285      for (j = 0; j < n; j++) {
286	if (n == 1) {
287	  channel = -1;
288	} else {
289	  channel = j;
290	}
291	mixerLinks[i][j].mixer = (char *)SnackStrDup(line);
292	mixerLinks[i][j].mixerVar = (char *)SnackStrDup(Tcl_GetStringFromObj(objv[j+3], NULL));
293	mixerLinks[i][j].channel = j;
294	value = Tcl_GetVar(interp, mixerLinks[i][j].mixerVar, TCL_GLOBAL_ONLY);
295	if (value != NULL) {
296	  SnackMixerSetVolume(line, channel, atoi(value));
297	} else {
298	  Tcl_Obj *obj;
299	  SnackMixerGetVolume(line, channel, tmp, VOLBUFSIZE);
300	  obj = Tcl_NewIntObj(atoi(tmp));
301	  Tcl_ObjSetVar2(interp, objv[j+3], NULL, obj,
302			 TCL_GLOBAL_ONLY | TCL_PARSE_PART1);
303	}
304	Tcl_TraceVar(interp, mixerLinks[i][j].mixerVar,
305		     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
306		     VolumeVarProc, (ClientData) &mixerLinks[i][j]);
307      }
308    }
309  }
310}
311
312void
313SnackMixerUpdateVars(Tcl_Interp *interp)
314{
315  int i, j;
316  char tmp[VOLBUFSIZE];
317  Tcl_Obj *obj, *var;
318
319  for (i = 0; i < SNACK_NUMBER_MIXERS; i++) {
320    for (j = 0; j < 2; j++) {
321      if (mixerLinks[i][j].mixerVar != NULL) {
322	SnackMixerGetVolume(mixerLinks[i][j].mixer, mixerLinks[i][j].channel,
323			    tmp, VOLBUFSIZE);
324	obj = Tcl_NewIntObj(atoi(tmp));
325	var = Tcl_NewStringObj(mixerLinks[i][j].mixerVar, -1);
326	Tcl_ObjSetVar2(interp, var, NULL, obj, TCL_GLOBAL_ONLY|TCL_PARSE_PART1);
327      }
328    }
329  }
330}
331
332void
333SnackMixerGetLineLabels(char *buf, int n)
334{
335  strncpy(buf, "Play", n);
336  buf[n-1] = '\0';
337}
338
339int
340SnackGetOutputDevices(char **arr, int n)
341{
342  arr[0] = (char *) SnackStrDup("default");
343
344  return 1;
345}
346
347int
348SnackGetInputDevices(char **arr, int n)
349{
350  arr[0] = (char *) SnackStrDup("default");
351
352  return 1;
353}
354
355int
356SnackGetMixerDevices(char **arr, int n)
357{
358  arr[0] = (char *) SnackStrDup("default");
359
360  return 1;
361}
362