1 /*
2 * Copyright (C) 1997-2005 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 "snack.h"
24 #include <string.h>
25 #include <math.h>
26
27 #define SNACK_PI 3.141592653589793
28
29 void
Snack_InitWindow(float * win,int winlen,int fftlen,int type)30 Snack_InitWindow(float *win, int winlen, int fftlen, int type)
31 {
32 int i;
33
34 if (winlen > fftlen)
35 winlen = fftlen;
36
37 if (type == SNACK_WIN_RECT) {
38 for (i = 0; i < winlen; i++)
39 win[i] = (float) 1.0;
40 } else if (type == SNACK_WIN_HANNING) {
41 for (i = 0; i < winlen; i++)
42 win[i] = (float)(0.5 * (1.0 - cos(i * 2.0 * SNACK_PI / (winlen - 1))));
43 } else if (type == SNACK_WIN_BARTLETT) {
44 for (i = 0; i < winlen/2; i++)
45 win[i] = (float)(((2.0 * i) / (winlen - 1)));
46 for (i = winlen/2; i < winlen; i++)
47 win[i] = (float)(2.0 * (1.0 - ((float)i / (winlen - 1))));
48 } else if (type == SNACK_WIN_BLACKMAN) {
49 for (i = 0; i < winlen; i++)
50 win[i] = (float)((0.42 - 0.5 * cos(i * 2.0 * SNACK_PI / (winlen - 1))
51 + 0.08 * cos(i * 4.0 * SNACK_PI / (winlen - 1))));
52 } else { /* default: Hamming window */
53 for (i = 0; i < winlen; i++)
54 win[i] = (float)(0.54 - 0.46 * cos(i * 2.0 * SNACK_PI / (winlen - 1)));
55 }
56
57 for (i = winlen; i < fftlen; i++)
58 win[i] = 0.0;
59 }
60
61 int
CheckFFTlen(Tcl_Interp * interp,int fftlen)62 CheckFFTlen(Tcl_Interp *interp, int fftlen)
63 {
64 int n = NMIN;
65 char str[10];
66
67 while (n <= NMAX) {
68 if (n == fftlen) return TCL_OK;
69 n *= 2;
70 }
71
72 Tcl_AppendResult(interp, "-fftlength must be one of { ", NULL);
73
74 for (n = NMIN; n <= NMAX; n*=2) {
75 sprintf(str, "%d ", n);
76 Tcl_AppendResult(interp, str, NULL);
77 }
78 Tcl_AppendResult(interp, "}", NULL);
79 return TCL_ERROR;
80 }
81
82 int
CheckWinlen(Tcl_Interp * interp,int winlen,int fftlen)83 CheckWinlen(Tcl_Interp *interp, int winlen, int fftlen)
84 {
85 char str[10];
86
87 if (winlen < 1) {
88 Tcl_AppendResult(interp, "-winlength must be > 0", NULL);
89 return TCL_ERROR;
90 }
91 if (winlen > fftlen) {
92 Tcl_AppendResult(interp, "-winlength must be <= fftlength (", NULL);
93 sprintf(str, "%d)", fftlen);
94 Tcl_AppendResult(interp, str, NULL);
95 return TCL_ERROR;
96 }
97
98 return TCL_OK;
99 }
100
101 void
GetFloatMonoSig(Sound * s,SnackLinkedFileInfo * info,float * sig,int beg,int len,int channel)102 GetFloatMonoSig(Sound *s,SnackLinkedFileInfo *info,
103 float *sig, int beg, int len, int channel) {
104 /* sig buffer must be allocated, file must be open! */
105
106 int i;
107
108 if (s->storeType == SOUND_IN_MEMORY) {
109 if (s->nchannels == 1 || channel != -1) {
110 int p = beg * s->nchannels + channel;
111
112 for (i = 0; i < len; i++) {
113 sig[i] = (float) (FSAMPLE(s, p));
114 p += s->nchannels;
115 }
116 } else {
117 int c;
118
119 for (i = 0; i < len; i++) {
120 sig[i] = 0.0;
121 }
122 for (c = 0; c < s->nchannels; c++) {
123 int p = beg * s->nchannels + c;
124
125 for (i = 0; i < len; i++) {
126 sig[i] += (float) (FSAMPLE(s, p));
127 p += s->nchannels;
128 }
129 }
130 for (i = 0; i < len; i++) {
131 sig[i] /= s->nchannels;
132 }
133 }
134 } else { /* storeType != SOUND_IN_MEMORY */
135 if (s->nchannels == 1 || channel != -1) {
136 int p = beg * s->nchannels + channel;
137
138 for (i = 0; i < len; i++) {
139 sig[i] = (float) (GetSample(info, p));
140 p += s->nchannels;
141 }
142 } else {
143 int c;
144
145 for (i = 0; i < len; i++) {
146 sig[i] = 0.0;
147 }
148 for (c = 0; c < s->nchannels; c++) {
149 int p = beg * s->nchannels + c;
150
151 for (i = 0; i < len; i++) {
152 sig[i] += (float) (GetSample(info, p));
153 p += s->nchannels;
154 }
155 }
156 for (i = 0; i < len; i++) {
157 sig[i] /= s->nchannels;
158 }
159 }
160 }
161 }
162
163 static float xfft[NMAX];
164 static float ffts[NMAX];
165 static float hamwin[NMAX];
166 #define SNACK_DEFAULT_DBPWINTYPE SNACK_WIN_HAMMING
167 #define SNACK_DEFAULT_DBP_LPC_ORDER 20
168 #define SNACK_MAX_LPC_ORDER 40
169
170 int
CheckLPCorder(Tcl_Interp * interp,int lpcorder)171 CheckLPCorder(Tcl_Interp *interp, int lpcorder)
172 {
173 char str[10];
174 if (lpcorder < 1) {
175 Tcl_AppendResult(interp, "-lpcorder must be > 0", NULL);
176 return TCL_ERROR;
177 }
178 if (lpcorder > SNACK_MAX_LPC_ORDER) {
179 Tcl_AppendResult(interp, "-lpcorder must be <= ", NULL);
180 sprintf(str, "%d)", SNACK_MAX_LPC_ORDER);
181 Tcl_AppendResult(interp, str, NULL);
182 return TCL_ERROR;
183 }
184
185 return TCL_OK;
186 }
187
188 extern void Snack_PowerSpectrum(float *z);
189
190 int
dBPowerSpectrumCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])191 dBPowerSpectrumCmd(Sound *s, Tcl_Interp *interp, int objc,
192 Tcl_Obj *CONST objv[])
193 {
194 double dpreemph = 0.0;
195 float preemph = 0.0;
196 int i, j, n = 0, arg;
197 int channel = 0, winlen = 256, fftlen = 512;
198 int startpos = 0, endpos = -1, skip = -1;
199 Tcl_Obj *list;
200 SnackLinkedFileInfo info;
201 SnackWindowType wintype = SNACK_DEFAULT_DBPWINTYPE;
202 static CONST84 char *subOptionStrings[] = {
203 "-start", "-end", "-channel", "-fftlength", "-winlength", "-windowlength",
204 "-preemphasisfactor", "-skip", "-windowtype", "-analysistype",
205 "-lpcorder", NULL
206 };
207 enum subOptions {
208 START, END, CHANNEL, FFTLEN, WINLEN, WINDOWLEN, PREEMPH, SKIP, WINTYPE,
209 ANATYPE, LPCORDER
210 };
211 float *sig_lpc;
212 float presample = 0.0;
213 int siglen, type = 0, lpcOrder = SNACK_DEFAULT_DBP_LPC_ORDER;
214 float g_lpc;
215
216 if (s->debug > 0) Snack_WriteLog("Enter dBPowerSpectrumCmd\n");
217
218 for (arg = 2; arg < objc; arg += 2) {
219 int index;
220
221 if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
222 "option", 0, &index) != TCL_OK) {
223 return TCL_ERROR;
224 }
225
226 if (arg + 1 == objc) {
227 Tcl_AppendResult(interp, "No argument given for ",
228 subOptionStrings[index], " option", (char *) NULL);
229 return TCL_ERROR;
230 }
231
232 switch ((enum subOptions) index) {
233 case START:
234 {
235 if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
236 return TCL_ERROR;
237 break;
238 }
239 case END:
240 {
241 if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
242 return TCL_ERROR;
243 break;
244 }
245 case CHANNEL:
246 {
247 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
248 if (GetChannel(interp, str, s->nchannels, &channel) != TCL_OK) {
249 return TCL_ERROR;
250 }
251 break;
252 }
253 case FFTLEN:
254 {
255 if (Tcl_GetIntFromObj(interp, objv[arg+1], &fftlen) != TCL_OK)
256 return TCL_ERROR;
257 break;
258 }
259 case WINDOWLEN:
260 case WINLEN:
261 {
262 if (Tcl_GetIntFromObj(interp, objv[arg+1], &winlen) != TCL_OK)
263 return TCL_ERROR;
264 break;
265 }
266 case PREEMPH:
267 {
268 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dpreemph) != TCL_OK)
269 return TCL_ERROR;
270 break;
271 }
272 case SKIP:
273 {
274 if (Tcl_GetIntFromObj(interp, objv[arg+1], &skip) != TCL_OK)
275 return TCL_ERROR;
276 break;
277 }
278 case WINTYPE:
279 {
280 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
281 if (GetWindowType(interp, str, &wintype) != TCL_OK)
282 return TCL_ERROR;
283 break;
284 }
285 case ANATYPE:
286 {
287 int len;
288 char *str = Tcl_GetStringFromObj(objv[arg+1], &len);
289
290 if (strncasecmp(str, "lpc", len) == 0) {
291 type = 1;
292 } else if (strncasecmp(str, "fft", len) == 0) {
293 type = 0;
294 } else {
295 Tcl_AppendResult(interp, "-type should be FFT or LPC", (char *)NULL);
296 return TCL_ERROR;
297 }
298 break;
299 }
300 case LPCORDER:
301 {
302 if (Tcl_GetIntFromObj(interp, objv[arg+1], &lpcOrder) != TCL_OK)
303 return TCL_ERROR;
304 if (CheckLPCorder(interp, lpcOrder) != TCL_OK)
305 return TCL_ERROR;
306 break;
307 }
308 }
309 }
310
311 if (CheckFFTlen(interp, fftlen) != TCL_OK) return TCL_ERROR;
312
313 if (CheckWinlen(interp, winlen, fftlen) != TCL_OK) return TCL_ERROR;
314
315 preemph = (float) dpreemph;
316
317 if (startpos < 0 || startpos > s->length - fftlen) {
318 Tcl_AppendResult(interp, "FFT window out of bounds", NULL);
319 return TCL_ERROR;
320 }
321
322 if (endpos < 0)
323 endpos = startpos;
324
325 if (endpos > s->length - 1) {
326 Tcl_AppendResult(interp, "FFT window out of bounds", NULL);
327 return TCL_ERROR;
328 }
329
330 for (i = 0; i < NMAX/2; i++) {
331 ffts[i] = 0.0;
332 }
333
334 if (s->storeType != SOUND_IN_MEMORY) {
335 if (OpenLinkedFile(s, &info) != TCL_OK) {
336 return TCL_OK;
337 }
338 }
339
340 Snack_InitWindow(hamwin, winlen, fftlen, wintype);
341 Snack_InitFFT(fftlen);
342
343 if (skip < 1) {
344 skip = fftlen;
345 }
346 siglen = endpos - startpos;
347 n = siglen / skip;
348 if (n < 1) {
349 n = 1;
350 }
351
352 if (s->nchannels == 1) {
353 channel = 0;
354 }
355
356 if (type != 0 && n > 0) { /* LPC + FFT */
357 if (siglen < fftlen) siglen = fftlen;
358 sig_lpc = (float *) ckalloc(siglen * sizeof(float));
359
360 GetFloatMonoSig(s, &info, sig_lpc, startpos, siglen, channel);
361 if (startpos > 0)
362 GetFloatMonoSig(s, &info, &presample, startpos - 1, 1, channel);
363 PreEmphase(sig_lpc, presample, siglen, preemph);
364
365 /* windowing signal to make lpc look more like the fft spectrum ??? */
366 for (i = 0; i < winlen/2; i++) {
367 sig_lpc[i] = sig_lpc[i] * hamwin[i];
368 }
369 for (i = winlen/2; i < winlen; i++) {
370 sig_lpc[i + siglen - winlen] = sig_lpc[i + siglen - winlen] * hamwin[i];
371 }
372
373 g_lpc = LpcAnalysis(sig_lpc, siglen, xfft, lpcOrder);
374 ckfree((char *) sig_lpc);
375
376 for (i = 0; i <= lpcOrder; i++) {
377 /* the factor is a guess, try looking for analytical value */
378 xfft[i] = xfft[i] * 5000000000.0f;
379 }
380 for (i = lpcOrder + 1; i < fftlen; i++) {
381 xfft[i] = 0.0;
382 }
383
384 Snack_DBPowerSpectrum(xfft);
385
386 for (i = 0; i < fftlen/2; i++) {
387 ffts[i] = -xfft[i];
388 }
389
390 } else { /* usual FFT */
391
392 for (j = 0; j < n; j++) {
393 if (s->storeType == SOUND_IN_MEMORY) {
394 if (s->nchannels == 1 || channel != -1) {
395 int p = (startpos + j * skip) * s->nchannels + channel;
396
397 for (i = 0; i < fftlen; i++) {
398 xfft[i] = (float) ((FSAMPLE(s, p + s->nchannels)
399 - preemph * FSAMPLE(s, p))
400 * hamwin[i]);
401 p += s->nchannels;
402 }
403 } else {
404 int c;
405
406 for (i = 0; i < fftlen; i++) {
407 xfft[i] = 0.0;
408 }
409 for (c = 0; c < s->nchannels; c++) {
410 int p = (startpos + j * skip) * s->nchannels + c;
411
412 for (i = 0; i < fftlen; i++) {
413 xfft[i] += (float) ((FSAMPLE(s, p + s->nchannels)
414 - preemph * FSAMPLE(s, p))
415 * hamwin[i]);
416 p += s->nchannels;
417 }
418 }
419 for (i = 0; i < fftlen; i++) {
420 xfft[i] /= s->nchannels;
421 }
422 }
423 } else { /* storeType != SOUND_IN_MEMORY */
424 if (s->nchannels == 1 || channel != -1) {
425 int p = (startpos + j * skip) * s->nchannels + channel;
426
427 for (i = 0; i < fftlen; i++) {
428 xfft[i] = (float) ((GetSample(&info, p + s->nchannels)
429 - preemph * GetSample(&info, p))
430 * hamwin[i]);
431 p += s->nchannels;
432 }
433 } else {
434 int c;
435
436 for (i = 0; i < fftlen; i++) {
437 xfft[i] = 0.0;
438 }
439 for (c = 0; c < s->nchannels; c++) {
440 int p = (startpos + j * skip) * s->nchannels + c;
441
442 for (i = 0; i < fftlen; i++) {
443 xfft[i] += (float) ((GetSample(&info, p + s->nchannels)
444 - preemph * GetSample(&info, p))
445 * hamwin[i]);
446 p += s->nchannels;
447 }
448 }
449 for (i = 0; i < fftlen; i++) {
450 xfft[i] /= s->nchannels;
451 }
452 }
453 }
454
455 Snack_PowerSpectrum(xfft);
456
457 for (i = 0; i < fftlen/2; i++) {
458 ffts[i] += xfft[i];
459 }
460 }
461 }
462
463 if (s->storeType != SOUND_IN_MEMORY) {
464 CloseLinkedFile(&info);
465 }
466
467 if (type == 0) {
468 for (i = 0; i < fftlen/2; i++) {
469 ffts[i] = ffts[i] / (float) n;
470 }
471 for (i = 1; i < fftlen/2; i++) {
472 if (ffts[i] < SNACK_INTLOGARGMIN)
473 ffts[i] = SNACK_INTLOGARGMIN;
474 ffts[i] = (float) (SNACK_DB * log(ffts[i]) - SNACK_CORRN);
475 }
476 if (ffts[0] < SNACK_INTLOGARGMIN)
477 ffts[0] = SNACK_INTLOGARGMIN;
478 ffts[0] = (float) (SNACK_DB * log(ffts[0]) - SNACK_CORR0);
479 }
480 list = Tcl_NewListObj(0, NULL);
481 for (i = 0; i < fftlen/2; i++) {
482 Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj(ffts[i]));
483 }
484
485 Tcl_SetObjResult(interp, list);
486
487 if (s->debug > 0) Snack_WriteLog("Exit dBPowerSpectrumCmd\n");
488
489 return TCL_OK;
490 }
491
492 int
GetChannel(Tcl_Interp * interp,char * str,int nchan,int * channel)493 GetChannel(Tcl_Interp *interp, char *str, int nchan, int *channel)
494 {
495 int n = -2;
496 int len = strlen(str);
497
498 if (strncasecmp(str, "left", len) == 0) {
499 n = 0;
500 } else if (strncasecmp(str, "right", len) == 0) {
501 n = 1;
502 } else if (strncasecmp(str, "all", len) == 0) {
503 n = -1;
504 } else if (strncasecmp(str, "both", len) == 0) {
505 n = -1;
506 } else {
507 Tcl_GetInt(interp, str, &n);
508 }
509
510 if (n < -1 || n >= nchan) {
511 Tcl_AppendResult(interp, "-channel must be left, right, both, all, -1, or an integer between 0 and the number channels - 1", NULL);
512 return TCL_ERROR;
513 }
514
515 *channel = n;
516
517 return TCL_OK;
518 }
519
520 int
GetWindowType(Tcl_Interp * interp,char * str,SnackWindowType * wintype)521 GetWindowType(Tcl_Interp *interp, char *str, SnackWindowType *wintype)
522 {
523 SnackWindowType type = -1;
524 int len = strlen(str);
525
526 if (strncasecmp(str, "hamming", len) == 0) {
527 type = SNACK_WIN_HAMMING;
528 } else if (strncasecmp(str, "hanning", len) == 0) {
529 type = SNACK_WIN_HANNING;
530 } else if (strncasecmp(str, "bartlett", len) == 0) {
531 type = SNACK_WIN_BARTLETT;
532 } else if (strncasecmp(str, "blackman", len) == 0) {
533 type = SNACK_WIN_BLACKMAN;
534 } else if (strncasecmp(str, "rectangle", len) == 0) {
535 type = SNACK_WIN_RECT;
536 }
537
538 if (type == -1) {
539 Tcl_AppendResult(interp, "-windowtype must be hanning, hamming, bartlett,"
540 "blackman, or rectangle", NULL);
541 return TCL_ERROR;
542 }
543
544 *wintype = type;
545
546 return TCL_OK;
547 }
548
549 float
LpcAnalysis(float * data,int N,float * f,int order)550 LpcAnalysis (float *data, int N, float *f, int order) {
551 int i,m;
552 float sumU = 0.0;
553 float sumD = 0.0;
554 float b[SNACK_MAX_LPC_ORDER+1];
555 float KK;
556
557 float ParcorCoeffs[SNACK_MAX_LPC_ORDER];
558 /* PreData should be used when signal is not windowed */
559 float PreData[SNACK_MAX_LPC_ORDER];
560 float *errF;
561 float *errB;
562 float errF_m = 0.0;
563
564 if ((order < 1) || (order > SNACK_MAX_LPC_ORDER)) return 0.0f;
565
566 errF = (float *) ckalloc((N+SNACK_MAX_LPC_ORDER) * sizeof(float));
567 errB = (float *) ckalloc((N+SNACK_MAX_LPC_ORDER) * sizeof(float));
568
569 for (i=0; i<order; i++) {
570 ParcorCoeffs[i] = 0.0;
571 PreData[i] = 0.0; /* delete here and use as argument when sig not windowed */
572 };
573
574 for (m=0; m<order; m++)
575 errF[m] = PreData[m];
576 for (m=0; m<N; m++)
577 errF[m+order] = data[m] ;
578
579 errB[0] = 0.0;
580 for (m=1; m<N+order; m++)
581 errB[m] = errF[m-1];
582
583 for (i=0; i<order; i++) {
584
585 sumU=0.0;
586 sumD=0.0;
587 for (m=i+1; m<N+order; m++) {
588 sumU -= errF[m] * errB[m];
589 sumD += errF[m] * errF[m] + errB[m] * errB[m];
590 };
591
592 if (sumD != 0) KK = 2.0f * sumU / sumD;
593 else KK = 0;
594 ParcorCoeffs[i] = KK;
595
596
597 for (m=N+order-1; m>i; m--) {
598 errF[m] += KK * errB[m];
599 errB[m] = errB[m-1] + KK * errF[m-1];
600 };
601 };
602
603 for (i=order; i<N+order; i++) {
604 errF_m += errF[i]*errF[i];
605 }
606 errF_m /= N;
607
608 ckfree((char *)errF);
609 ckfree((char *)errB);
610
611 /* convert to direct filter coefficients */
612 f[0] = 1.0;
613 for (m=1; m<=order; m++) {
614 f[m] = ParcorCoeffs[m-1];
615 for (i=1; i<m; i++)
616 b[i] = f[i];
617 for (i=1; i<m; i++)
618 f[i] = b[i] + ParcorCoeffs[m-1] * b[m-i];
619 }
620
621 return (float)sqrt(errF_m);
622 }
623
624
PreEmphase(float * sig,float presample,int len,float preemph)625 void PreEmphase(float *sig, float presample, int len, float preemph) {
626 int i;
627 float temp;
628
629 if (preemph == 0.0) return;
630
631 for (i = 0; i < len; i++) {
632 temp = sig[i];
633 sig[i] = temp - preemph * presample;
634 presample = temp;
635 }
636 }
637
638 int
powerSpectrumCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])639 powerSpectrumCmd(Sound *s, Tcl_Interp *interp, int objc,
640 Tcl_Obj *CONST objv[])
641 {
642 double dpreemph = 0.0;
643 float preemph = 0.0;
644 int i, j, n = 0, arg;
645 int channel = 0, winlen = 256, fftlen = 512;
646 int startpos = 0, endpos = -1, skip = -1;
647 Tcl_Obj *list;
648 SnackLinkedFileInfo info;
649 SnackWindowType wintype = SNACK_DEFAULT_DBPWINTYPE;
650 static CONST84 char *subOptionStrings[] = {
651 "-start", "-end", "-channel", "-fftlength", "-winlength", "-windowlength",
652 "-preemphasisfactor", "-skip", "-windowtype", "-analysistype",
653 "-lpcorder", NULL
654 };
655 enum subOptions {
656 START, END, CHANNEL, FFTLEN, WINLEN, WINDOWLEN, PREEMPH, SKIP, WINTYPE,
657 ANATYPE, LPCORDER
658 };
659 float *sig_lpc;
660 float presample = 0.0;
661 int siglen, type = 0, lpcOrder = SNACK_DEFAULT_DBP_LPC_ORDER;
662 float g_lpc;
663
664 if (s->debug > 0) Snack_WriteLog("Enter powerSpectrumCmd\n");
665
666 for (arg = 2; arg < objc; arg += 2) {
667 int index;
668
669 if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
670 "option", 0, &index) != TCL_OK) {
671 return TCL_ERROR;
672 }
673
674 if (arg + 1 == objc) {
675 Tcl_AppendResult(interp, "No argument given for ",
676 subOptionStrings[index], " option", (char *) NULL);
677 return TCL_ERROR;
678 }
679
680 switch ((enum subOptions) index) {
681 case START:
682 {
683 if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
684 return TCL_ERROR;
685 break;
686 }
687 case END:
688 {
689 if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
690 return TCL_ERROR;
691 break;
692 }
693 case CHANNEL:
694 {
695 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
696 if (GetChannel(interp, str, s->nchannels, &channel) != TCL_OK) {
697 return TCL_ERROR;
698 }
699 break;
700 }
701 case FFTLEN:
702 {
703 if (Tcl_GetIntFromObj(interp, objv[arg+1], &fftlen) != TCL_OK)
704 return TCL_ERROR;
705 break;
706 }
707 case WINDOWLEN:
708 case WINLEN:
709 {
710 if (Tcl_GetIntFromObj(interp, objv[arg+1], &winlen) != TCL_OK)
711 return TCL_ERROR;
712 break;
713 }
714 case PREEMPH:
715 {
716 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dpreemph) != TCL_OK)
717 return TCL_ERROR;
718 break;
719 }
720 case SKIP:
721 {
722 if (Tcl_GetIntFromObj(interp, objv[arg+1], &skip) != TCL_OK)
723 return TCL_ERROR;
724 break;
725 }
726 case WINTYPE:
727 {
728 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
729 if (GetWindowType(interp, str, &wintype) != TCL_OK)
730 return TCL_ERROR;
731 break;
732 }
733 case ANATYPE:
734 {
735 int len;
736 char *str = Tcl_GetStringFromObj(objv[arg+1], &len);
737
738 if (strncasecmp(str, "lpc", len) == 0) {
739 type = 1;
740 } else if (strncasecmp(str, "fft", len) == 0) {
741 type = 0;
742 } else {
743 Tcl_AppendResult(interp, "-type should be FFT or LPC", (char *)NULL);
744 return TCL_ERROR;
745 }
746 break;
747 }
748 case LPCORDER:
749 {
750 if (Tcl_GetIntFromObj(interp, objv[arg+1], &lpcOrder) != TCL_OK)
751 return TCL_ERROR;
752 if (CheckLPCorder(interp, lpcOrder) != TCL_OK)
753 return TCL_ERROR;
754 break;
755 }
756 }
757 }
758
759 if (CheckFFTlen(interp, fftlen) != TCL_OK) return TCL_ERROR;
760
761 if (CheckWinlen(interp, winlen, fftlen) != TCL_OK) return TCL_ERROR;
762
763 preemph = (float) dpreemph;
764
765 if (startpos < 0 || startpos > s->length - fftlen) {
766 Tcl_AppendResult(interp, "FFT window out of bounds", NULL);
767 return TCL_ERROR;
768 }
769
770 if (endpos < 0)
771 endpos = startpos;
772
773 if (endpos > s->length - 1) {
774 Tcl_AppendResult(interp, "FFT window out of bounds", NULL);
775 return TCL_ERROR;
776 }
777
778 for (i = 0; i < NMAX/2; i++) {
779 ffts[i] = 0.0;
780 }
781
782 if (s->storeType != SOUND_IN_MEMORY) {
783 if (OpenLinkedFile(s, &info) != TCL_OK) {
784 return TCL_OK;
785 }
786 }
787
788 Snack_InitWindow(hamwin, winlen, fftlen, wintype);
789
790 Snack_InitFFT(fftlen);
791
792 if (skip < 1) {
793 skip = fftlen;
794 }
795 siglen = endpos - startpos;
796 n = siglen / skip;
797 if (n < 1) {
798 n = 1;
799 }
800
801 if (s->nchannels == 1) {
802 channel = 0;
803 }
804
805 if (type != 0 && n > 0) { /* LPC + FFT */
806 if (siglen < fftlen) siglen = fftlen;
807 sig_lpc = (float *) ckalloc(siglen * sizeof(float));
808
809 GetFloatMonoSig(s, &info, sig_lpc, startpos, siglen, channel);
810 if (startpos > 0)
811 GetFloatMonoSig(s, &info, &presample, startpos - 1, 1, channel);
812 PreEmphase(sig_lpc, presample, siglen, preemph);
813
814 /* windowing signal to make lpc look more like the fft spectrum ??? */
815 for (i = 0; i < winlen/2; i++) {
816 sig_lpc[i] = sig_lpc[i] * hamwin[i];
817 }
818 for (i = winlen/2; i < winlen; i++) {
819 sig_lpc[i + siglen - winlen] = sig_lpc[i + siglen - winlen] * hamwin[i];
820 }
821
822 g_lpc = LpcAnalysis(sig_lpc, siglen, xfft, lpcOrder);
823 ckfree((char *) sig_lpc);
824
825 for (i = 0; i <= lpcOrder; i++) {
826 /* the factor is a guess, try looking for analytical value */
827 xfft[i] = xfft[i] * 5000000000.0f;
828 }
829 for (i = lpcOrder + 1; i < fftlen; i++) {
830 xfft[i] = 0.0;
831 }
832
833 Snack_PowerSpectrum(xfft);
834
835 for (i = 0; i < fftlen/2; i++) {
836 ffts[i] = -xfft[i];
837 }
838
839 } else { /* usual FFT */
840
841 for (j = 0; j < n; j++) {
842 if (s->storeType == SOUND_IN_MEMORY) {
843 if (s->nchannels == 1 || channel != -1) {
844 int p = (startpos + j * skip) * s->nchannels + channel;
845
846 for (i = 0; i < fftlen; i++) {
847 /* if (i < 4) printf("a %f %d\n", FSAMPLE(s, i), n);*/
848 xfft[i] = (float) ((FSAMPLE(s, p + s->nchannels)
849 - preemph * FSAMPLE(s, p))
850 * hamwin[i]);
851 /* if (i < 4) printf("b %f %f\n", xfft[i], hamwin[i]);*/
852 p += s->nchannels;
853 }
854 } else {
855 int c;
856
857 for (i = 0; i < fftlen; i++) {
858 xfft[i] = 0.0;
859 }
860 for (c = 0; c < s->nchannels; c++) {
861 int p = (startpos + j * skip) * s->nchannels + c;
862
863 for (i = 0; i < fftlen; i++) {
864 xfft[i] += (float) ((FSAMPLE(s, p + s->nchannels)
865 - preemph * FSAMPLE(s, p))
866 * hamwin[i]);
867 p += s->nchannels;
868 }
869 }
870 for (i = 0; i < fftlen; i++) {
871 xfft[i] /= s->nchannels;
872 }
873 }
874 } else { /* storeType != SOUND_IN_MEMORY */
875 if (s->nchannels == 1 || channel != -1) {
876 int p = (startpos + j * skip) * s->nchannels + channel;
877
878 for (i = 0; i < fftlen; i++) {
879 xfft[i] = (float) ((GetSample(&info, p + s->nchannels)
880 - preemph * GetSample(&info, p))
881 * hamwin[i]);
882 p += s->nchannels;
883 }
884 } else {
885 int c;
886
887 for (i = 0; i < fftlen; i++) {
888 xfft[i] = 0.0;
889 }
890 for (c = 0; c < s->nchannels; c++) {
891 int p = (startpos + j * skip) * s->nchannels + c;
892
893 for (i = 0; i < fftlen; i++) {
894 xfft[i] += (float) ((GetSample(&info, p + s->nchannels)
895 - preemph * GetSample(&info, p))
896 * hamwin[i]);
897 p += s->nchannels;
898 }
899 }
900 for (i = 0; i < fftlen; i++) {
901 xfft[i] /= s->nchannels;
902 }
903 }
904 }
905
906 Snack_PowerSpectrum(xfft);
907 for (i = 0; i < fftlen/2; i++) {
908 ffts[i] += (float)sqrt(xfft[i]);
909 /* if (i < 4) printf("power %f %f\n", xfft[i],ffts[i]);*/
910 }
911 }
912 }
913
914 if (s->storeType != SOUND_IN_MEMORY) {
915 CloseLinkedFile(&info);
916 }
917
918 for (i = 0; i < fftlen/2; i++) {
919 ffts[i] = ffts[i] / (float) n;
920 }
921
922 list = Tcl_NewListObj(0, NULL);
923 for (i = 0; i < fftlen/2; i++) {
924 Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj(ffts[i]));
925 }
926
927 Tcl_SetObjResult(interp, list);
928
929 if (s->debug > 0) Snack_WriteLog("Exit powerSpectrumCmd\n");
930
931 return TCL_OK;
932 }
933
934 #define SNACK_DEFAULT_POWERWINTYPE SNACK_WIN_HAMMING
935
936 int
powerCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])937 powerCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
938 {
939 double dpreemph = 0.0, dscale = 1.0, dframelen = -1.0;
940 float preemph = 0.0, scale = 1.0;
941 int i, j, n = 0;
942 int channel = 0, winlen = 256;
943 int arg, startpos = 0, endpos = -1, framelen;
944 float *powers = NULL;
945 Tcl_Obj *list;
946 SnackLinkedFileInfo info;
947 SnackWindowType wintype = SNACK_DEFAULT_POWERWINTYPE;
948 static CONST84 char *subOptionStrings[] = {
949 "-start", "-end", "-channel", "-framelength", "-windowlength",
950 "-windowtype", "-preemphasisfactor", "-scale", "-progress", NULL
951 };
952 enum subOptions {
953 START, END, CHANNEL, FRAMELEN, WINDOWLEN, WINTYPE, PREEMPH, SCALE,
954 PROGRESS
955 };
956
957 if (s->debug > 0) { Snack_WriteLog("Enter powerCmd\n"); }
958
959 if (s->cmdPtr != NULL) {
960 Tcl_DecrRefCount(s->cmdPtr);
961 s->cmdPtr = NULL;
962 }
963
964 for (arg = 2; arg < objc; arg += 2) {
965 int index;
966
967 if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
968 "option", 0, &index) != TCL_OK) {
969 return TCL_ERROR;
970 }
971
972 if (arg + 1 == objc) {
973 Tcl_AppendResult(interp, "No argument given for ",
974 subOptionStrings[index], " option", (char *) NULL);
975 return TCL_ERROR;
976 }
977
978 switch ((enum subOptions) index) {
979 case START:
980 {
981 if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
982 return TCL_ERROR;
983 break;
984 }
985 case END:
986 {
987 if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
988 return TCL_ERROR;
989 break;
990 }
991 case CHANNEL:
992 {
993 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
994 if (GetChannel(interp, str, s->nchannels, &channel) != TCL_OK) {
995 return TCL_ERROR;
996 }
997 break;
998 }
999 case FRAMELEN:
1000 {
1001 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dframelen) != TCL_OK)
1002 return TCL_ERROR;
1003 break;
1004 }
1005 case WINDOWLEN:
1006 {
1007 if (Tcl_GetIntFromObj(interp, objv[arg+1], &winlen) != TCL_OK)
1008 return TCL_ERROR;
1009 break;
1010 }
1011 case WINTYPE:
1012 {
1013 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
1014 if (GetWindowType(interp, str, &wintype) != TCL_OK)
1015 return TCL_ERROR;
1016 break;
1017 }
1018 case PREEMPH:
1019 {
1020 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dpreemph) != TCL_OK)
1021 return TCL_ERROR;
1022 break;
1023 }
1024 case SCALE:
1025 {
1026 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dscale) != TCL_OK)
1027 return TCL_ERROR;
1028 break;
1029 }
1030 case PROGRESS:
1031 {
1032 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
1033
1034 if (strlen(str) > 0) {
1035 Tcl_IncrRefCount(objv[arg+1]);
1036 s->cmdPtr = objv[arg+1];
1037 }
1038 break;
1039 }
1040 }
1041 }
1042
1043 if (winlen < 1) {
1044 Tcl_AppendResult(interp, "-windowlength must be > 0", NULL);
1045 return TCL_ERROR;
1046 }
1047 if (winlen > NMAX) {
1048 char str[10];
1049
1050 sprintf(str, "%d", NMAX);
1051 Tcl_AppendResult(interp, "-windowlength must be <= ", str, NULL);
1052 return TCL_ERROR;
1053 }
1054
1055 preemph = (float) dpreemph;
1056 scale = (float) dscale;
1057
1058 if (startpos < 0) startpos = 0;
1059 if (endpos >= (s->length - 1) || endpos == -1)
1060 endpos = s->length - 1;
1061 if (startpos > endpos) return TCL_OK;
1062
1063 if (s->storeType != SOUND_IN_MEMORY) {
1064 if (OpenLinkedFile(s, &info) != TCL_OK) {
1065 return TCL_OK;
1066 }
1067 }
1068
1069 Snack_InitWindow(hamwin, winlen, winlen, wintype);
1070
1071 if (dframelen == -1.0) {
1072 dframelen = 0.01;
1073 }
1074 framelen = (int) (dframelen * s->samprate);
1075 n = (endpos - startpos - winlen / 2) / framelen + 1;
1076 if (n < 1) {
1077 n = 1;
1078 }
1079 if (s->nchannels == 1) {
1080 channel = 0;
1081 }
1082
1083 powers = (float *) ckalloc(sizeof(float) * n);
1084
1085 Snack_ProgressCallback(s->cmdPtr, interp, "Computing power", 0.0);
1086
1087 for (j = 0; j < n; j++) {
1088 float power;
1089 int winstart = 0;
1090 if (s->storeType == SOUND_IN_MEMORY) {
1091 if (s->nchannels == 1 || channel != -1) {
1092 int p = (startpos + j * framelen - winlen/2) * s->nchannels + channel;
1093
1094 if (p < 0) p = 0;
1095 if (p < winlen / 2) winstart = winlen / 2 - p;
1096 for (i = winstart; i < winlen; i++) {
1097 xfft[i] = (float) ((FSAMPLE(s, p + s->nchannels)
1098 - preemph * FSAMPLE(s, p))
1099 * hamwin[i]);
1100 p += s->nchannels;
1101 }
1102 } else {
1103 int c;
1104
1105 for (i = 0; i < winlen; i++) {
1106 xfft[i] = 0.0;
1107 }
1108 for (c = 0; c < s->nchannels; c++) {
1109 int p = (startpos + j * framelen - winlen/2) * s->nchannels + c;
1110
1111 if (p < 0) p = 0;
1112 if (p < winlen / 2) winstart = winlen / 2 - p;
1113 for (i = winstart; i < winlen; i++) {
1114 xfft[i] += (float) ((FSAMPLE(s, p + s->nchannels)
1115 - preemph * FSAMPLE(s, p))
1116 * hamwin[i]);
1117 p += s->nchannels;
1118 }
1119 }
1120 for (i = 0; i < winlen; i++) {
1121 xfft[i] /= s->nchannels;
1122 }
1123 }
1124 } else { /* storeType != SOUND_IN_MEMORY */
1125 if (s->nchannels == 1 || channel != -1) {
1126 int p = (startpos + j * framelen - winlen/2) * s->nchannels + channel;
1127
1128 if (p < 0) p = 0;
1129 if (p < winlen / 2) winstart = winlen / 2 - p;
1130 for (i = winstart; i < winlen; i++) {
1131 xfft[i] = (float) ((GetSample(&info, p + s->nchannels)
1132 - preemph * GetSample(&info, p))
1133 * hamwin[i]);
1134 p += s->nchannels;
1135 }
1136 } else {
1137 int c;
1138
1139 for (i = 0; i < winlen; i++) {
1140 xfft[i] = 0.0;
1141 }
1142 for (c = 0; c < s->nchannels; c++) {
1143 int p = (startpos + j * framelen - winlen/2) * s->nchannels + c;
1144
1145 if (p < 0) p = 0;
1146 if (p < winlen / 2) winstart = winlen / 2 - p;
1147 for (i = winstart; i < winlen; i++) {
1148 xfft[i] += (float) ((GetSample(&info, p + s->nchannels)
1149 - preemph * GetSample(&info, p))
1150 * hamwin[i]);
1151 p += s->nchannels;
1152 }
1153 }
1154 for (i = 0; i < winlen; i++) {
1155 xfft[i] /= s->nchannels;
1156 }
1157 }
1158 }
1159
1160 power = 0.0f;
1161 for (i = winstart; i < winlen; i++) {
1162 power += xfft[i] * xfft[i];
1163 }
1164 if (power < 1.0) power = 1.0;
1165 powers[j] = (float) (SNACK_DB * log(scale * power / (float)(winlen - winstart)));
1166
1167 if ((j % 10000) == 9999) {
1168 int res = Snack_ProgressCallback(s->cmdPtr, interp, "Computing power",
1169 (double) j / n);
1170 if (res != TCL_OK) {
1171 ckfree((char *) powers);
1172 return TCL_ERROR;
1173 }
1174 }
1175 }
1176
1177 Snack_ProgressCallback(s->cmdPtr, interp, "Computing power", 1.0);
1178
1179 list = Tcl_NewListObj(0, NULL);
1180 for (i = 0; i < n; i++) {
1181 Tcl_ListObjAppendElement(interp,list, Tcl_NewDoubleObj((double)powers[i]));
1182 }
1183 Tcl_SetObjResult(interp, list);
1184
1185 if (s->storeType != SOUND_IN_MEMORY) {
1186 CloseLinkedFile(&info);
1187 }
1188 ckfree((char *) powers);
1189
1190 if (s->debug > 0) { Snack_WriteLog("Exit powerCmd\n"); }
1191
1192 return TCL_OK;
1193 }
1194
1195 float
mel(float f)1196 mel(float f)
1197 {
1198 return((float)(1127.0 * log(1.0f + f / 700.0f)));
1199 }
1200
1201 float regarr[15][5];
1202
1203 static void
obsv(Sound * s,int nStatCoeffs,float * v,int t,int nReg)1204 obsv(Sound *s, int nStatCoeffs, float *v, int t, int nReg)
1205 {
1206 int i, j, ne, pr;
1207 float sum;
1208
1209 for (i = 0; i < nStatCoeffs; i++) {
1210 for (j = 1; j < 5; j++) {
1211 regarr[i][j-1] = regarr[i][j];
1212 }
1213 }
1214
1215 if (t >= 0) {
1216 for (i = 0; i < nStatCoeffs; i++) {
1217 v[i] = FSAMPLE(s, s->nchannels * t + i);
1218 }
1219 }
1220 if (nReg) {
1221 for (i = 0; i < nStatCoeffs; i++) {
1222 sum = 0.0f;
1223 for (j = 1; j <= 2; j++) {
1224 pr = t + 2 - j;
1225 if (pr < 0) pr = 0;
1226 ne = t + 2 + j;
1227 if (ne >= s->length) ne = s->length - 1;
1228 sum += j * (FSAMPLE(s, s->nchannels * ne + i)-FSAMPLE(s, s->nchannels * pr + i));
1229 }
1230 regarr[i][4] = sum / 10.0f;
1231 v[i+nStatCoeffs] = regarr[i][2];
1232 }
1233 }
1234 if (nReg > 1) {
1235 for (i = 0; i < nStatCoeffs; i++) {
1236 sum = 0.0f;
1237 for (j = 1; j <= 2; j++) {
1238 pr = 2 - j;
1239 if (t == 0) pr = 2;
1240 if (t == 1 && j == 2) pr = 1;
1241 ne = 2 + j;
1242 if (t == s->length-1) ne = 2;
1243 if (t == s->length-2 && j == 2) ne = 3;
1244 sum += j * (regarr[i][ne]-regarr[i][pr]);
1245 }
1246 v[i+2*nStatCoeffs] = sum / 10.0f;
1247 }
1248 }
1249
1250 /* for (i = 0; i < 13; i++) { printf("%f ",v[i]); } printf("\n");
1251 for (i=13; i < 26; i++) { printf("%f ",v[i]); } printf("\n");
1252 for (i=26; i < 39; i++) { printf("%f ",v[i]); } printf("\n");*/
1253 }
1254
1255 int
speaturesCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1256 speaturesCmd(Sound *s, Tcl_Interp *interp, int objc,
1257 Tcl_Obj *CONST objv[])
1258 {
1259 double tmpdouble = 0.0, dframelen = 0.01;
1260 float preemph = 0.97f, lowcut = 0.0f, highcut = (float) (s->samprate / 2.0);
1261 int i, j, k, n = 1, arg;
1262 int channel = 0;
1263 double dwinlen = 0.0256;
1264 int winlen;
1265 int fftlen = 2;
1266 int startpos = 0, endpos = -1, framelen;
1267 SnackLinkedFileInfo info;
1268 SnackWindowType wintype = SNACK_DEFAULT_DBPWINTYPE;
1269 static CONST84 char *subOptionStrings[] = {
1270 "-start", "-end", "-channel", "-framelength", "-windowlength",
1271 "-preemphasisfactor", "-windowtype",
1272 "-nchannels", "-ncoeff", "-cepstrallifter", "-energy", "-zeromean",
1273 "-zerothcepstralcoeff", "-lowcutoff", "-highcutoff",
1274 "-regressionorder", NULL
1275 };
1276 enum subOptions {
1277 START, END, CHANNEL, FRAMELEN, WINDOWLEN, PREEMPH, WINTYPE,
1278 NCHANNELS, NCOEFF, CEPLIFT, ENERGY, ZEROMEAN, ZEROTHCC,
1279 LOWCUT, HIGHCUT, REGRESSION
1280 };
1281 float *outarr;
1282 int numchannels = 20, ncoeff = 12;
1283 int lowInd, highInd;
1284 float lowMel, highMel;
1285 float cf[40];
1286 float fb[40];
1287 float lifter[20];
1288 float mfcc[20];
1289 int map[512];
1290 float fbw[512];
1291 float frame[1024];
1292 double ceplifter = 22.0;
1293 int doEnergy = 0, doZeroMean = 0, doZerothCC = 0, regression = 0;
1294 int vectorLength, regVecLen;
1295 Sound *outsnd;
1296 char *string;
1297
1298 if (s->debug > 0) Snack_WriteLog("Enter speaturesCmd\n");
1299
1300 string = Tcl_GetStringFromObj(objv[2], NULL);
1301
1302 if ((outsnd = Snack_GetSound(interp, string)) == NULL) {
1303 return TCL_ERROR;
1304 }
1305
1306 for (arg = 3; arg < objc; arg += 2) {
1307 int index;
1308
1309 if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
1310 "option", 0, &index) != TCL_OK) {
1311 return TCL_ERROR;
1312 }
1313
1314 if (arg + 1 == objc) {
1315 Tcl_AppendResult(interp, "No argument given for ",
1316 subOptionStrings[index], " option", (char *) NULL);
1317 return TCL_ERROR;
1318 }
1319
1320 switch ((enum subOptions) index) {
1321 case START:
1322 {
1323 if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
1324 return TCL_ERROR;
1325 break;
1326 }
1327 case END:
1328 {
1329 if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
1330 return TCL_ERROR;
1331 break;
1332 }
1333 case CHANNEL:
1334 {
1335 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
1336 if (GetChannel(interp, str, s->nchannels, &channel) != TCL_OK) {
1337 return TCL_ERROR;
1338 }
1339 break;
1340 }
1341 case FRAMELEN:
1342 {
1343 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dframelen) != TCL_OK)
1344 return TCL_ERROR;
1345 break;
1346 }
1347 case WINDOWLEN:
1348 {
1349 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dwinlen) != TCL_OK)
1350 return TCL_ERROR;
1351 break;
1352 }
1353 case PREEMPH:
1354 {
1355 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &tmpdouble) != TCL_OK)
1356 return TCL_ERROR;
1357 preemph = (float) tmpdouble;
1358 break;
1359 }
1360 case WINTYPE:
1361 {
1362 char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
1363 if (GetWindowType(interp, str, &wintype) != TCL_OK)
1364 return TCL_ERROR;
1365 break;
1366 }
1367 case NCHANNELS:
1368 {
1369 if (Tcl_GetIntFromObj(interp, objv[arg+1], &numchannels) != TCL_OK)
1370 return TCL_ERROR;
1371 break;
1372 }
1373 case NCOEFF:
1374 {
1375 if (Tcl_GetIntFromObj(interp, objv[arg+1], &ncoeff) != TCL_OK)
1376 return TCL_ERROR;
1377 break;
1378 }
1379 case CEPLIFT:
1380 {
1381 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &ceplifter) != TCL_OK)
1382 return TCL_ERROR;
1383 break;
1384 }
1385 case ENERGY:
1386 {
1387 if (Tcl_GetIntFromObj(interp, objv[arg+1], &doEnergy) != TCL_OK)
1388 return TCL_ERROR;
1389 break;
1390 }
1391 case ZEROMEAN:
1392 {
1393 if (Tcl_GetIntFromObj(interp, objv[arg+1], &doZeroMean) != TCL_OK)
1394 return TCL_ERROR;
1395 break;
1396 }
1397 case ZEROTHCC:
1398 {
1399 if (Tcl_GetIntFromObj(interp, objv[arg+1], &doZerothCC) != TCL_OK)
1400 return TCL_ERROR;
1401 break;
1402 }
1403 case LOWCUT:
1404 {
1405 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &tmpdouble) != TCL_OK)
1406 return TCL_ERROR;
1407 lowcut = (float) tmpdouble;
1408 break;
1409 }
1410 case HIGHCUT:
1411 {
1412 if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &tmpdouble) != TCL_OK)
1413 return TCL_ERROR;
1414 highcut = (float) tmpdouble;
1415 break;
1416 }
1417 case REGRESSION:
1418 {
1419 if (Tcl_GetIntFromObj(interp, objv[arg+1], ®ression) != TCL_OK)
1420 return TCL_ERROR;
1421 break;
1422 }
1423 }
1424 }
1425
1426 winlen = (int) (s->samprate * dwinlen);
1427
1428 if ((startpos < 0 || startpos > s->length - fftlen) && s->length > 0) {
1429 Tcl_AppendResult(interp, "FFT window out of bounds", NULL);
1430 return TCL_ERROR;
1431 }
1432
1433 if (startpos < 0) startpos = 0;
1434 if (endpos >= (s->length - 1) || endpos == -1)
1435 endpos = s->length - 1;
1436 if (startpos > endpos) return TCL_OK;
1437
1438 if (s->storeType != SOUND_IN_MEMORY) {
1439 if (OpenLinkedFile(s, &info) != TCL_OK) {
1440 return TCL_OK;
1441 }
1442 }
1443
1444 while (fftlen < winlen) fftlen *= 2;
1445
1446 framelen = (int) (dframelen * s->samprate);
1447 n = (endpos - startpos - winlen) / framelen + 1;
1448 if (n < 1) {
1449 n = 0;
1450 }
1451
1452 vectorLength = ncoeff;
1453 if (doEnergy) vectorLength++;
1454 if (doZerothCC) vectorLength++;
1455
1456 outarr = (float *) ckalloc(sizeof(float) * vectorLength * n + 1);
1457
1458 lowMel = (float) mel(lowcut);
1459 lowInd = (int) ((lowcut * fftlen / s->samprate) + 1.5);
1460 if (lowInd < 1) lowInd = 1;
1461 highMel = (float) mel(highcut);
1462 highInd = (int) ((highcut * fftlen / s->samprate) - 0.5);
1463 if (highInd > fftlen / 2 - 1) highInd = fftlen / 2 - 1;
1464
1465 for (i = 0; i < numchannels + 1; i++) {
1466 cf[i] = ((float) (i+1) / (numchannels+1)) * (highMel - lowMel) + lowMel;
1467 }
1468
1469 for (i = 0; i < fftlen / 2; i++) {
1470 float melInd = mel((float) i * s->samprate / fftlen);
1471 float new;
1472 int ch = 0;
1473
1474 if (i < lowInd || i > highInd) {
1475 map[i] = -1;
1476 new = 0.0;
1477 } else {
1478 while (cf[ch] < melInd && ch < numchannels + 1) ++ch;
1479 map[i] = ch - 1;
1480 if (ch - 1 >= 0) {
1481 new = ((cf[ch] - mel((float) i*s->samprate/fftlen)) /
1482 (cf[ch] - cf[ch-1]));
1483 } else {
1484 new = (cf[0] - mel((float) i*s->samprate/fftlen)) / (cf[0] - lowMel);
1485 }
1486 }
1487 fbw[i] = new;
1488 }
1489
1490 for (i = 0; i <= ncoeff; i++) {
1491 lifter[i] = (float)(1.0 + ceplifter /2.0 * sin(SNACK_PI * i / ceplifter));
1492 }
1493
1494 Snack_InitWindow(hamwin, winlen, fftlen, wintype);
1495
1496 Snack_InitFFT(fftlen);
1497
1498 for (j = 0; j < n; j++) {
1499 float sum = 0.0;
1500
1501 for (i = 0; i < fftlen; i++) {
1502 frame[i] = 0.0f;
1503 }
1504 if (s->storeType == SOUND_IN_MEMORY) {
1505 if (s->nchannels == 1 || channel != -1) {
1506 int p = (startpos + j * framelen) * s->nchannels + channel;
1507
1508 for (i = 0; i < winlen; i++) {
1509 frame[i] = FSAMPLE(s, p);
1510 p += s->nchannels;
1511 }
1512 } else {
1513 int c;
1514
1515 for (c = 0; c < s->nchannels; c++) {
1516 int p = (startpos + j * framelen) * s->nchannels + c;
1517
1518 for (i = 0; i < winlen; i++) {
1519 frame[i] += FSAMPLE(s, p);
1520 p += s->nchannels;
1521 }
1522 }
1523 for (i = 0; i < winlen; i++) {
1524 frame[i] /= s->nchannels;
1525 }
1526 }
1527 } else { /* storeType != SOUND_IN_MEMORY */
1528 if (s->nchannels == 1 || channel != -1) {
1529 int p = (startpos + j * framelen) * s->nchannels + channel;
1530
1531 for (i = 0; i < winlen; i++) {
1532 frame[i] = GetSample(&info, p);
1533 p += s->nchannels;
1534 }
1535 } else {
1536 int c;
1537
1538 for (c = 0; c < s->nchannels; c++) {
1539 int p = (startpos + j * framelen) * s->nchannels + c;
1540
1541 for (i = 0; i < winlen; i++) {
1542 frame[i] += GetSample(&info, p);
1543 p += s->nchannels;
1544 }
1545 }
1546 for (i = 0; i < winlen; i++) {
1547 frame[i] /= s->nchannels;
1548 }
1549 }
1550 }
1551
1552 for (i = 0; i < winlen; i++) {
1553 float sample = frame[i];
1554 sum += sample * sample;
1555 }
1556 if (sum < 1.0) sum = 1.0f;
1557
1558 xfft[0] = (float) (1.0f - preemph) * frame[0] * hamwin[0];
1559 for (i = 1; i < fftlen; i++) {
1560 xfft[i] = (float) ((frame[i] - preemph * frame[i - 1]) * hamwin[i]);
1561 }
1562
1563 Snack_PowerSpectrum(xfft);
1564
1565 for (i = 0; i < numchannels + 1; i++) {
1566 fb[i] = 0.0;
1567 }
1568 for (i = lowInd; i <= highInd; i++) {
1569 float e = (float) (0.5 * sqrt(xfft[i]));
1570 int bin = map[i];
1571 float we = fbw[i] * e;
1572
1573 if (bin > -1) fb[bin] += we;
1574 if (bin < numchannels - 1) fb[bin + 1] += e - we;
1575 }
1576 for (i = 0; i < numchannels; i++) {
1577 if (fb[i] < 1.0) {
1578 fb[i] = 0.0f;
1579 } else {
1580 fb[i] = (float) log(fb[i]);
1581 }
1582 }
1583
1584 for (i = 0; i < ncoeff; i++) {
1585 mfcc[i] = 0.0f;
1586 for (k = 0; k < numchannels; k++) {
1587 mfcc[i] += (float) (fb[k] * cos(SNACK_PI * (i + 1) / numchannels *
1588 (k + 0.5f)));
1589 }
1590 mfcc[i] *= (float) (sqrt(2.0f / numchannels) * lifter[i + 1]);
1591 }
1592 mfcc[ncoeff] = (float) log(sum);
1593 for (i = 0; i < ncoeff + 1; i++) {
1594 outarr[j * vectorLength + i] = mfcc[i];
1595 }
1596 if (doZerothCC) {
1597 float sum = 0.0f;
1598
1599 for (i = 0; i < numchannels; i++) {
1600 sum += fb[i];
1601 }
1602 outarr[j*vectorLength+ncoeff] = (float) (sum * sqrt(2.0 / numchannels));
1603 }
1604 } /* for (j = 0;... */
1605
1606 if (doZeroMean) {
1607 for (i = 0; i < ncoeff; i++) {
1608 float sum = 0.0f, offset;
1609
1610 for (j = 0; j < n; j++) {
1611 sum += outarr[j * vectorLength + i];
1612 }
1613 offset = sum / n;
1614 for (j = 0; j < n; j++) {
1615 outarr[j * vectorLength + i] -= offset;
1616 }
1617 }
1618 }
1619 if (doEnergy) {
1620 float max = -1000000.0f, min;
1621
1622 for (i = ncoeff; i < n * vectorLength; i += vectorLength) {
1623 if (outarr[i] > max) max = outarr[i];
1624 }
1625 min = (float) (max - 50.0f * log(10.0f) / 10.0f);
1626 for (i = ncoeff; i < n * vectorLength; i += vectorLength) {
1627 if (outarr[i] < min) outarr[i] = min;
1628 outarr[i] = 1.0f - 0.1f * (max - outarr[i]);
1629 }
1630 }
1631
1632 if (s->storeType != SOUND_IN_MEMORY) {
1633 CloseLinkedFile(&info);
1634 }
1635 regVecLen = vectorLength * (regression + 1);
1636 if (outsnd->nchannels < regVecLen) {
1637 outsnd->nchannels = regVecLen;
1638 }
1639 if (Snack_ResizeSoundStorage(outsnd, n) != TCL_OK) {
1640 return TCL_ERROR;
1641 }
1642 outsnd->length = n;
1643
1644 for (i = 0; i < n; i++) {
1645 for (k = 0; k < vectorLength; k++) {
1646 FSAMPLE(outsnd, i*outsnd->nchannels+k) = outarr[i*vectorLength+k];
1647 }
1648 }
1649
1650 if (regression) {
1651 float obs[45];
1652
1653 for (k = -2; k < 2; k++) {
1654 for (i = 0; i < vectorLength; i++) {
1655 float sum = 0.0f;
1656 for (j = 1; j <= 2; j++) {
1657 int pr = k - j;
1658 int ne = k + j;
1659 if (pr < 0) pr = 0;
1660 if (ne < 0) ne = 0;
1661 if (ne >= n) ne = n - 1;
1662 sum += j * (FSAMPLE(outsnd, outsnd->nchannels * ne + i)
1663 - FSAMPLE(outsnd, outsnd->nchannels * pr + i));
1664 }
1665 regarr[i][k+3] = sum / 10.0f;
1666 }
1667 }
1668 for (i = 0; i < n; i++) {
1669 obsv(outsnd, vectorLength, obs, i, regression);
1670 for (k = vectorLength; k < regVecLen; k++) {
1671 FSAMPLE(outsnd, i * outsnd->nchannels + k) = obs[k];
1672 }
1673 }
1674 }
1675
1676 ckfree((char*) outarr);
1677
1678 outsnd->encoding = SNACK_FLOAT;
1679 outsnd->samprate = (int) (1.0 / dframelen + 0.5);
1680 Snack_UpdateExtremes(outsnd, 0, n, SNACK_NEW_SOUND);
1681 Snack_ExecCallbacks(outsnd, SNACK_NEW_SOUND);
1682
1683 if (s->debug > 0) Snack_WriteLog("Exit speaturesCmd\n");
1684
1685 return TCL_OK;
1686 }
1687
1688 extern int cGet_f0(Sound *s, Tcl_Interp *interp, float **outlist, int *length);
1689
1690 static int
searchZX(Sound * s,int pos)1691 searchZX(Sound *s, int pos)
1692 {
1693 int i, j;
1694
1695 for(i = 0; i < 20000; i++) {
1696 j = pos + i;
1697 if (j>0 && j<s->length && FSAMPLE(s, j-1) < 0.0 && FSAMPLE(s, j) >= 0.0) {
1698 return(j);
1699 }
1700 j = pos - i;
1701 if (j>0 && j<s->length && FSAMPLE(s, j-1) < 0.0 && FSAMPLE(s, j) >= 0.0) {
1702 return(j);
1703 }
1704 }
1705 return(pos);
1706 }
1707
1708 int
stretchCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1709 stretchCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
1710 {
1711 int i, ind, last, start, arg, segOnly = 0;
1712 static CONST84 char *subOptionStrings[] = {
1713 "-segments", NULL
1714 };
1715 enum subOptions {
1716 SEGMENTS
1717 };
1718 float *cPitchList;
1719 int *segs;
1720 int *sege;
1721 int cPitchLength = 0;
1722 int skip = s->samprate / 100;
1723
1724 if (s->debug > 0) Snack_WriteLog("Enter stretchCmd\n");
1725
1726 for (arg = 2; arg < objc; arg += 2) {
1727 int index;
1728
1729 if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
1730 "option", 0, &index) != TCL_OK) {
1731 return TCL_ERROR;
1732 }
1733
1734 if (arg + 1 == objc) {
1735 Tcl_AppendResult(interp, "No argument given for ",
1736 subOptionStrings[index], " option", (char *) NULL);
1737 return TCL_ERROR;
1738 }
1739
1740 switch ((enum subOptions) index) {
1741 case SEGMENTS:
1742 {
1743 if (Tcl_GetIntFromObj(interp, objv[arg+1], &segOnly) != TCL_OK)
1744 return TCL_ERROR;
1745 break;
1746 }
1747 }
1748 }
1749
1750 if (s->length == 0) {
1751 return TCL_OK;
1752 }
1753
1754 cGet_f0(s, interp, &cPitchList, &cPitchLength);
1755
1756 ind = 0;
1757 start = 0;
1758 last = 0;
1759 segs = (int *) ckalloc(sizeof(int) * cPitchLength * 2);
1760 sege = (int *) ckalloc(sizeof(int) * cPitchLength * 2);
1761
1762 if (s->length < 8000 && cPitchList[0] == 0.0 && cPitchList[1] == 0.0 && \
1763 cPitchList[2] == 0.0) {
1764 } else {
1765 for (i = 1; i < s->length; i++) {
1766 int pitchListIndex = (int) (i/(float)skip+.5);
1767 float point;
1768
1769 if (pitchListIndex >= cPitchLength) {
1770 pitchListIndex = cPitchLength - 1;
1771 }
1772 if (ind >= cPitchLength*2) {
1773 ind = cPitchLength * 2 - 1;
1774 }
1775 point = cPitchList[pitchListIndex];
1776
1777 if (point == 0.0) {
1778 i += 9;
1779 continue;
1780 }
1781 if (start == 0) {
1782 i = searchZX(s, (int)(i+s->samprate/point));
1783 segs[ind] = start;
1784 sege[ind] = i;
1785 start = i;
1786 ind++;
1787 } else {
1788 i = searchZX(s, (int)(i+s->samprate/point));
1789 if (i == last) {
1790 int j = i + 10;
1791 while (last == i) {
1792 i = searchZX(s, j);
1793 j += 10;
1794 }
1795 }
1796 /* this is needed to make stretch.test happy, can surely be improved*/
1797 if (i - last < (int)(0.8*s->samprate/point) && s->length - i < 200) {
1798 i = -1;
1799 }
1800 last = i;
1801 if (i > 0) {
1802 segs[ind] = start;
1803 sege[ind] = i;
1804 start = i;
1805 ind++;
1806 } else {
1807 segs[ind] = start;
1808 sege[ind] = s->length;
1809 start = s->length;
1810 ind++;
1811 break;
1812 }
1813 }
1814 }
1815 if (ind == 0) {
1816 segs[ind] = start;
1817 ind = 1;
1818 }
1819 sege[ind-1] = s->length-1;
1820 }
1821
1822 if (segOnly) {
1823 Tcl_Obj *list = Tcl_NewListObj(0, NULL);
1824 for (i = 0; i < ind; i++) {
1825 Tcl_ListObjAppendElement(interp, list,
1826 Tcl_NewIntObj((int) segs[i]));
1827 }
1828 Tcl_SetObjResult(interp, list);
1829 ckfree((char *)segs);
1830 ckfree((char *)sege);
1831 ckfree((char *)cPitchList);
1832
1833 if (s->debug > 0) Snack_WriteLog("Exit stretchCmd\n");
1834
1835 return TCL_OK;
1836 }
1837
1838 return TCL_OK;
1839 }
1840
1841 int
joinCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1842 joinCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
1843 {
1844 return TCL_OK;
1845 }
1846
1847 int
ocCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1848 ocCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
1849 {
1850 return TCL_OK;
1851 }
1852
1853 int
fitCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1854 fitCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
1855 {
1856 return TCL_OK;
1857 }
1858
1859 #define PI 3.141592653589793
1860
1861 double singtabf[32];
1862 double singtabb[32];
1863 float futdat[512+10];
1864 float smerg[512+10];
1865
1866 int
inaCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1867 inaCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
1868 {
1869 float a1[32],a2[32],mn[32];
1870 int i,j,noli,nofpts=512,shobeg=2,nosing;
1871 int start;
1872 int plLen = 0;
1873 Tcl_Obj** plElems;
1874 Tcl_Obj *list, *listInv, *listFlow;
1875
1876 if (Tcl_GetIntFromObj(interp, objv[2], &start) != TCL_OK) return TCL_ERROR;
1877
1878 if (Tcl_ListObjGetElements(interp, objv[3], &plLen, &plElems) != TCL_OK)
1879 return TCL_ERROR;
1880
1881 nosing = plLen / 2;
1882
1883 for (i=0;i<nosing;i++) {
1884 if (Tcl_GetDoubleFromObj(interp, plElems[i], &singtabf[i]) != TCL_OK)
1885 return TCL_ERROR;
1886 if (Tcl_GetDoubleFromObj(interp, plElems[i+nosing], &singtabb[i]) != TCL_OK)
1887 return TCL_ERROR;
1888 }
1889
1890 for (i = 0; i < nofpts; i++) {
1891 futdat[i] = FSAMPLE(s, start + i);
1892 }
1893 for (i = nofpts; i < nofpts+4; i++) {
1894 futdat[i] = 0.0f;
1895 }
1896
1897 noli=0; /* zero 2nd order filter */
1898 for (i=0;i<nosing;i++) {
1899 if ((singtabf[i]>0.0) && (singtabb[i]>0.0)) {
1900 a2[noli]=(float)exp((double)(-PI*singtabb[i]/s->samprate));
1901 a1[noli]= -2*a2[noli]*(float)cos((double)(2.0*PI*singtabf[i]/s->samprate));
1902 a2[noli]=a2[noli]*a2[noli];
1903 mn[noli]=1.0f/(1.0f+a1[noli]+a2[noli]);
1904 a1[noli]=mn[noli]*a1[noli];
1905 a2[noli]=mn[noli]*a2[noli];
1906 noli++;
1907 }
1908 }
1909 for (j=0;j<noli;j++) {
1910 for (i=shobeg+nofpts;i>=shobeg;i--) {
1911 futdat[i]=mn[j]*futdat[i]+a1[j]*futdat[i-1]+a2[j]*futdat[i-2];
1912 }
1913 }
1914
1915 noli=0; /* pole 2nd order filter */
1916 for (i=0;i<nosing;i++) {
1917 if ((singtabf[i]>0.0) && (singtabb[i]<0.0)) {
1918 a2[noli]=(float)exp((double)(PI*singtabb[i]/s->samprate));
1919 a1[noli]= -2*a2[noli]*(float)cos((double)(2.0*PI*singtabf[i]/s->samprate));
1920 a2[noli]=a2[noli]*a2[noli];
1921 mn[noli]=1.0f+a1[noli]+a2[noli];
1922 noli++;
1923 }
1924 }
1925 for (j=0;j<noli;j++) {
1926 for (i=shobeg;i<shobeg+nofpts;i++) {
1927 futdat[i]=mn[j]*futdat[i]-a1[j]*futdat[i-1]-a2[j]*futdat[i-2];
1928 }
1929 }
1930
1931 noli=0; /* pole 1st order filter */
1932 for (i=0;i<nosing;i++) {
1933 if ((singtabf[i]==0.0) && (singtabb[i]<0.0)) {
1934 a1[noli]= -(float)exp((double)(PI*singtabb[i]/s->samprate));
1935 mn[noli]=1.0f+a1[noli];
1936 noli++;
1937 }
1938 }
1939 for (j=0;j<noli;j++) {
1940 for (i=shobeg;i<shobeg+nofpts;i++) {
1941 futdat[i]=mn[j]*(futdat[i]-futdat[i-1])+futdat[i-1];
1942 }
1943 }
1944 /*shobeg = 1;*/ /* ugly fix, think about this*/
1945 smerg[shobeg-1]=0.0;
1946 for (i=shobeg;i<shobeg+nofpts;i++) {
1947 smerg[i]=(futdat[i]-smerg[i-1])/32.0f+smerg[i-1];
1948 }
1949
1950 list = Tcl_NewListObj(0, NULL);
1951 listInv = Tcl_NewListObj(0, NULL);
1952 listFlow = Tcl_NewListObj(0, NULL);
1953 for (i = shobeg; i < shobeg+nofpts; i++) {
1954 Tcl_ListObjAppendElement(interp, listInv, Tcl_NewDoubleObj(futdat[i]));
1955 Tcl_ListObjAppendElement(interp, listFlow, Tcl_NewDoubleObj(smerg[i]));
1956 }
1957 Tcl_ListObjAppendElement(interp, list, listInv);
1958 Tcl_ListObjAppendElement(interp, list, listFlow);
1959 Tcl_SetObjResult(interp, list);
1960
1961 return TCL_OK;
1962 }
1963
1964 Tcl_HashTable *arHashTable;
1965
1966 int
Snack_arCmd(ClientData cdata,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1967 Snack_arCmd(ClientData cdata, Tcl_Interp *interp, int objc,
1968 Tcl_Obj *CONST objv[])
1969 {
1970 return TCL_OK;
1971 }
1972
1973 void
Snack_arDeleteCmd(ClientData clientData)1974 Snack_arDeleteCmd(ClientData clientData)
1975 {
1976 }
1977
1978 int
vpCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1979 vpCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
1980 {
1981 return TCL_OK;
1982 }
1983
1984 Tcl_HashTable *hsetHashTable;
1985
1986 int
Snack_HSetCmd(ClientData cdata,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1987 Snack_HSetCmd(ClientData cdata, Tcl_Interp *interp, int objc,
1988 Tcl_Obj *CONST objv[])
1989 {
1990
1991 return TCL_OK;
1992 }
1993
1994 void
Snack_HSetDeleteCmd(ClientData clientData)1995 Snack_HSetDeleteCmd(ClientData clientData)
1996 {
1997 }
1998
1999 int
alCmd(Sound * s,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])2000 alCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
2001 {
2002 return TCL_OK;
2003 }
2004
2005 int
isynCmd(ClientData cdata,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])2006 isynCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
2007 {
2008 return TCL_OK;
2009 }
2010
2011 int
osynCmd(ClientData cdata,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])2012 osynCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
2013 {
2014 return TCL_OK;
2015 }
2016