1/* 2 * Copyright (C) 1997-2004 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 <string.h> 23#include "tk.h" 24#include "snack.h" 25#include "jkCanvItems.h" 26 27#if defined(__WIN32__) 28# define WIN32_LEAN_AND_MEAN 29# include <windows.h> 30# undef WIN32_LEAN_AND_MEAN 31 32#ifdef __cplusplus 33extern "C" { 34#endif 35 36EXTERN int Snack_Init(Tcl_Interp *interp); 37EXTERN int Snack_SafeInit(Tcl_Interp *interp); 38 39#ifdef __cplusplus 40} 41#endif 42 43HINSTANCE snackHInst = NULL; 44 45BOOL APIENTRY 46DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved) 47{ 48 snackHInst = hInst; 49 return TRUE; 50} 51#endif 52 53#ifdef MAC 54#include <string.h> 55int main (void) 56{ 57 return 0; 58} 59 60double 61hypotd(double x, double y) 62{ 63 double sum; 64 65 sum = x*x + y*y; 66 return sqrt(sum); 67} 68#endif 69 70extern Tk_ItemType snackWaveType; 71extern Tk_ItemType snackSpectrogramType; 72extern Tk_ItemType snackSectionType; 73extern Tk_CustomOption waveTagsOption; 74extern Tk_CustomOption spegTagsOption; 75extern Tk_CustomOption sectTagsOption; 76 77#define play_width 19 78#define play_height 19 79static unsigned char play_bits[] = { 80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 81 0x78, 0x00, 0x00, 0xf8, 0x01, 0x00, 0xf8, 0x07, 0x00, 0xf8, 0x1f, 0x00, 82 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0xf8, 0x1f, 0x00, 0xf8, 0x07, 0x00, 83 0xf8, 0x01, 0x00, 0x78, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 85 86#define rec_width 19 87#define rec_height 19 88static unsigned char rec_bits[] = { 89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 90 0xe0, 0x1f, 0x00, 0xf0, 0x3f, 0x00, 0xf0, 0x3f, 0x00, 0xf8, 0x7f, 0x00, 91 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0xf0, 0x3f, 0x00, 92 0xf0, 0x3f, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 94 95#define stop_width 19 96#define stop_height 19 97static unsigned char stop_bits[] = { 98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 99 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 100 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 101 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 103 104#define pause_width 19 105#define pause_height 19 106static unsigned char pause_bits[] = { 107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7c, 0x00, 108 0xf8, 0x7c, 0x00, 0xf8, 0x7c, 0x00, 0xf8, 0x7c, 0x00, 0xf8, 0x7c, 0x00, 109 0xf8, 0x7c, 0x00, 0xf8, 0x7c, 0x00, 0xf8, 0x7c, 0x00, 0xf8, 0x7c, 0x00, 110 0xf8, 0x7c, 0x00, 0xf8, 0x7c, 0x00, 0xf8, 0x7c, 0x00, 0x00, 0x00, 0x00, 111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 112 113#define playnext_width 20 114#define playnext_height 19 115static unsigned char playnext_bits[] = { 116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xe0, 0x00, 117 0x78, 0xe0, 0x00, 0xf8, 0xe1, 0x00, 0xf8, 0xe7, 0x00, 0xf8, 0xff, 0x00, 118 0xf8, 0xff, 0x00, 0xf8, 0xff, 0x00, 0xf8, 0xff, 0x00, 0xf8, 0xe7, 0x00, 119 0xf8, 0xe1, 0x00, 0x78, 0xe0, 0x00, 0x18, 0xe0, 0x00, 0x00, 0x00, 0x00, 120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 121 122#define playprev_width 20 123#define playprev_height 19 124static unsigned char playprev_bits[] = { 125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xc0, 0x00, 126 0x38, 0xf0, 0x00, 0x38, 0xfc, 0x00, 0x38, 0xff, 0x00, 0xf8, 0xff, 0x00, 127 0xf8, 0xff, 0x00, 0xf8, 0xff, 0x00, 0xf8, 0xff, 0x00, 0x38, 0xff, 0x00, 128 0x38, 0xfc, 0x00, 0x38, 0xf0, 0x00, 0x38, 0xc0, 0x00, 0x00, 0x00, 0x00, 129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 130 131Tcl_Channel snackDebugChannel = NULL; 132static Tcl_Interp *debugInterp = NULL; 133int debugLevel = 0; 134char *snackDumpFile = NULL; 135 136int 137Snack_DebugCmd(ClientData cdata, Tcl_Interp *interp, int objc, 138 Tcl_Obj *CONST objv[]) 139{ 140 int len; 141 char *str; 142 CONST84 char *patchLevelStr; 143 144 if (objc > 1) { 145 if (Tcl_GetIntFromObj(interp, objv[1], &debugLevel) != TCL_OK) 146 return TCL_ERROR; 147 } 148 if (objc >= 3) { 149 if (Tcl_IsSafe(interp)) { 150 Tcl_AppendResult(interp, "can not open log file in a safe interpreter", 151 (char *) NULL); 152 return TCL_ERROR; 153 } 154 str = Tcl_GetStringFromObj(objv[2], &len); 155 if (len > 0) { 156 snackDebugChannel = Tcl_OpenFileChannel(interp, str, "w", 420); 157 if (snackDebugChannel == 0) { 158 return TCL_ERROR; 159 } 160 } 161 } 162 if (objc == 4) { 163 if (Tcl_IsSafe(interp)) { 164 Tcl_AppendResult(interp, "can not open dump file in a safe interpreter", 165 (char *) NULL); 166 return TCL_ERROR; 167 } 168 str = Tcl_GetStringFromObj(objv[3], &len); 169 snackDumpFile = (char *) ckalloc(len + 1); 170 strcpy(snackDumpFile, str); 171 } 172 if (debugLevel > 0) { 173 patchLevelStr = Tcl_GetVar(interp, "snack::patchLevel", TCL_GLOBAL_ONLY); 174 Tcl_Write(snackDebugChannel, "Snack patch level: ", 19); 175 Tcl_Write(snackDebugChannel, patchLevelStr, strlen(patchLevelStr)); 176 Tcl_Write(snackDebugChannel, "\n", 1); 177 Tcl_Flush(snackDebugChannel); 178 } 179 180 return TCL_OK; 181} 182 183#ifdef SNACK_CSLU_TOOLKIT 184extern int fromCSLUshWaveCmd(Sound *s, Tcl_Interp *interp, int objc, 185 Tcl_Obj *CONST objv[]); 186extern int toCSLUshWaveCmd(Sound *s, Tcl_Interp *interp, int objc, 187 Tcl_Obj *CONST objv[]); 188#endif 189 190int useOldObjAPI = 0; 191 192int 193Snack_setUseOldObjAPI(ClientData cdata, Tcl_Interp *interp, int objc, 194 Tcl_Obj *CONST objv[]) 195{ 196 useOldObjAPI = 1; 197 198 return TCL_OK; 199} 200 201 202static int initialized = 0; 203int littleEndian = 0; 204 205#ifdef __cplusplus 206extern "C" SnackStubs *snackStubs; 207#else 208extern SnackStubs *snackStubs; 209#endif 210 211extern Tcl_HashTable *filterHashTable; 212extern Tcl_HashTable *hsetHashTable; 213extern Tcl_HashTable *arHashTable; 214 215#if defined(Tcl_InitHashTable) && defined(USE_TCL_STUBS) 216#undef Tcl_InitHashTable 217#define Tcl_InitHashTable (tclStubsPtr->tcl_InitHashTable) 218#endif 219 220extern char defaultOutDevice[]; 221int defaultSampleRate = 16000; 222 223int 224Snack_Init(Tcl_Interp *interp) 225{ 226 Tcl_CmdInfo infoPtr; 227 CONST84 char *version; 228 Tcl_HashTable *soundHashTable; 229 union { 230 char c[sizeof(short)]; 231 short s; 232 } order; 233 char rates[100]; 234 235#ifdef USE_TCL_STUBS 236 if (Tcl_InitStubs(interp, "8", 0) == NULL) { 237 return TCL_ERROR; 238 } 239#endif 240 241 version = Tcl_GetVar(interp, "tcl_version", 242 (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); 243 244 if (strcmp(version, "8.0") == 0) { 245 useOldObjAPI = 1; 246 } 247 248#ifdef TCL_81_API 249 if (Tcl_PkgProvideEx(interp, "snack", SNACK_VERSION, 250 (ClientData) &snackStubs) != TCL_OK) { 251 return TCL_ERROR; 252 } 253#else 254 if (Tcl_PkgProvide(interp, "snack", SNACK_VERSION) != TCL_OK) { 255 return TCL_ERROR; 256 } 257#endif 258 259 if (Tcl_GetCommandInfo(interp, "button", &infoPtr) != 0) { 260#ifdef USE_TK_STUBS 261 if (Tk_InitStubs(interp, "8", 0) == NULL) { 262 return TCL_ERROR; 263 } 264#endif 265 266 if (initialized == 0) { 267 Tk_CreateItemType(&snackWaveType); 268 Tk_CreateItemType(&snackSpectrogramType); 269 Tk_CreateItemType(&snackSectionType); 270 } 271#if !defined(MAC) && !defined(MAC_OSX_TCL) 272 Tk_DefineBitmap(interp, Tk_GetUid("play"), (char *) play_bits, 273 play_width, play_height); 274 Tk_DefineBitmap(interp, Tk_GetUid("record"), (char *) rec_bits, 275 rec_width, rec_height); 276 Tk_DefineBitmap(interp, Tk_GetUid("stop"), (char *) stop_bits, 277 stop_width, stop_height); 278 Tk_DefineBitmap(interp, Tk_GetUid("pause"), (char *) pause_bits, 279 pause_width, pause_height); 280#endif 281 Tk_DefineBitmap(interp, Tk_GetUid("snackPlay"), (char *) play_bits, 282 play_width, play_height); 283 Tk_DefineBitmap(interp, Tk_GetUid("snackRecord"), (char *) rec_bits, 284 rec_width, rec_height); 285 Tk_DefineBitmap(interp, Tk_GetUid("snackStop"), (char *) stop_bits, 286 stop_width, stop_height); 287 Tk_DefineBitmap(interp, Tk_GetUid("snackPause"), (char *) pause_bits, 288 pause_width, pause_height); 289 Tk_DefineBitmap(interp, Tk_GetUid("snackPlayNext"), (char *) playnext_bits, 290 playnext_width, playnext_height); 291 Tk_DefineBitmap(interp, Tk_GetUid("snackPlayPrev"), (char *) playprev_bits, 292 playprev_width, playprev_height); 293 waveTagsOption.parseProc = Tk_CanvasTagsParseProc; 294 waveTagsOption.printProc = Tk_CanvasTagsPrintProc; 295 spegTagsOption.parseProc = Tk_CanvasTagsParseProc; 296 spegTagsOption.printProc = Tk_CanvasTagsPrintProc; 297 sectTagsOption.parseProc = Tk_CanvasTagsParseProc; 298 sectTagsOption.printProc = Tk_CanvasTagsPrintProc; 299 } 300 301 soundHashTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); 302 filterHashTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); 303 hsetHashTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); 304 arHashTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); 305 306 Tcl_CreateObjCommand(interp, "sound", Snack_SoundCmd, 307 (ClientData) soundHashTable, (Tcl_CmdDeleteProc *)NULL); 308 309 Tcl_CreateObjCommand(interp, "snack::sound", Snack_SoundCmd, 310 (ClientData) soundHashTable, Snack_SoundDeleteCmd); 311 312 Tcl_CreateObjCommand(interp, "audio", Snack_AudioCmd, 313 NULL, (Tcl_CmdDeleteProc *)NULL); 314 315 Tcl_CreateObjCommand(interp, "snack::audio", Snack_AudioCmd, 316 NULL, Snack_AudioDeleteCmd); 317 318 Tcl_CreateObjCommand(interp, "snack::mixer", Snack_MixerCmd, 319 NULL, Snack_MixerDeleteCmd); 320 321 Tcl_CreateObjCommand(interp, "snack::filter", Snack_FilterCmd, 322 (ClientData) filterHashTable, Snack_FilterDeleteCmd); 323 324 Tcl_CreateObjCommand(interp, "snack::hset", Snack_HSetCmd, 325 (ClientData) hsetHashTable, Snack_HSetDeleteCmd); 326 327 Tcl_CreateObjCommand(interp, "snack::ca", Snack_arCmd, 328 (ClientData) arHashTable, Snack_arDeleteCmd); 329 330 Tcl_CreateObjCommand(interp, "snack::isyn", isynCmd, 331 NULL, (Tcl_CmdDeleteProc *)NULL); 332 333 Tcl_CreateObjCommand(interp, "snack::osyn", osynCmd, 334 NULL, (Tcl_CmdDeleteProc *)NULL); 335 336 Tcl_CreateObjCommand(interp, "snack::debug", 337 (Tcl_ObjCmdProc*) Snack_DebugCmd, 338 NULL, (Tcl_CmdDeleteProc *)NULL); 339 340 Tcl_CreateObjCommand(interp, "snack::setUseOldObjAPI", 341 (Tcl_ObjCmdProc*) Snack_setUseOldObjAPI, 342 NULL, (Tcl_CmdDeleteProc *)NULL); 343 344 snackDebugChannel = Tcl_GetStdChannel(TCL_STDERR); 345 debugInterp = interp; 346 347 Tcl_SetVar(interp, "snack::patchLevel", SNACK_PATCH_LEVEL, TCL_GLOBAL_ONLY); 348 Tcl_SetVar(interp, "snack::version", SNACK_VERSION, TCL_GLOBAL_ONLY); 349 350 Tcl_InitHashTable(soundHashTable, TCL_STRING_KEYS); 351 Tcl_InitHashTable(filterHashTable, TCL_STRING_KEYS); 352 Tcl_InitHashTable(hsetHashTable, TCL_STRING_KEYS); 353 Tcl_InitHashTable(arHashTable, TCL_STRING_KEYS); 354 355 if (initialized == 0) { 356 SnackDefineFileFormats(interp); 357 SnackCreateFilterTypes(interp); 358 359 SnackAudioInit(); 360 361 Tcl_CreateExitHandler(Snack_ExitProc, (ClientData) NULL); 362 363 initialized = 1; 364 } 365#ifdef SNACK_CSLU_TOOLKIT 366 Snack_AddSubCmd(SNACK_SOUND_CMD, "fromCSLUshWave", 367 (Snack_CmdProc *) fromCSLUshWaveCmd, NULL); 368 Snack_AddSubCmd(SNACK_SOUND_CMD, "toCSLUshWave", 369 (Snack_CmdProc *) toCSLUshWaveCmd, NULL); 370#endif 371 372 /* Compute the byte order of this machine. */ 373 374 order.s = 1; 375 if (order.c[0] == 1) { 376 littleEndian = 1; 377 } 378 379 /* Determine a default sample rate for this machine, usually 16kHz. */ 380 381 SnackAudioGetRates(defaultOutDevice, rates, 100); 382 if (strstr(rates, "16000") != NULL || 383 sscanf(rates, "%d", &defaultSampleRate) != 1) { 384 defaultSampleRate = 16000; 385 } 386 387 return TCL_OK; 388} 389 390int 391Snack_SafeInit(Tcl_Interp *interp) 392{ 393 return Snack_Init(interp); 394} 395 396void 397Snack_WriteLog(char *str) 398{ 399 if (snackDebugChannel == NULL) { 400 snackDebugChannel = Tcl_OpenFileChannel(debugInterp, "_debug.txt", "w", 401 420); 402 } 403 Tcl_Write(snackDebugChannel, str, strlen(str)); 404 Tcl_Flush(snackDebugChannel); 405} 406 407void 408Snack_WriteLogInt(char *str, int num) 409{ 410 char buf[20]; 411 412 if (snackDebugChannel == NULL) { 413 snackDebugChannel = Tcl_OpenFileChannel(debugInterp, "_debug.txt", "w", 414 420); 415 } 416 Tcl_Write(snackDebugChannel, str, strlen(str)); 417 sprintf(buf, " %d", num); 418 Tcl_Write(snackDebugChannel, buf, strlen(buf)); 419 Tcl_Write(snackDebugChannel, "\n", 1); 420 Tcl_Flush(snackDebugChannel); 421} 422 423/* 424static double snack_t0; 425 426void 427TimerStart() { 428 snack_t0 = SnackCurrentTime(); 429} 430 431void 432TimerStop() { 433 char buf[20]; 434 sprintf(buf, "%f", SnackCurrentTime()-snack_t0); 435 Tcl_Write(snackDebugChannel, buf, strlen(buf)); 436 Tcl_Write(snackDebugChannel, "\n", 1); 437 Tcl_Flush(snackDebugChannel); 438} 439*/ 440