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 <stdio.h> 25#include <stdlib.h> 26#define USE_OLD_CANVAS /* To keep Tk8.3 happy */ 27#include "tk.h" 28#include "jkCanvItems.h" 29#include <string.h> 30#include <math.h> 31#ifdef MAC 32#include <Xlib.h> 33#include <Xutil.h> 34#else 35#include <X11/Xlib.h> 36#include <X11/Xutil.h> 37#endif 38 39#ifndef Solaris 40# ifndef TkPutImage 41EXTERN void TkPutImage _ANSI_ARGS_((unsigned long *colors, 42 int ncolors, Display* display, Drawable d, 43 GC gc, XImage* image, int src_x, int src_y, 44 int dest_x, int dest_y, unsigned int width, 45 unsigned int height)); 46# endif 47#endif 48 49#define SNACK_DEFAULT_SPEGWINTYPE SNACK_WIN_HAMMING 50#define SNACK_DEFAULT_SPEGWINTYPE_NAME "hamming" 51 52/* 53 * Spectrogram item structure 54 */ 55 56typedef struct SpectrogramItem { 57 58 Tk_Item header; 59 Tk_Canvas canvas; 60 double x, y; 61 Tk_Anchor anchor; 62 char *newSoundName; 63 char *soundName; 64 Sound *sound; 65 SnackItemInfo si; 66 int height; 67 int width; 68 int oldheight; 69 int oldwidth; 70 int startSmp; 71 int endSmp; 72 int ssmp; 73 int esmp; 74 int id; 75 int mode; 76 GC copyGC; 77 double bright; 78 double contrast; 79 char *channelstr; 80 double topFrequency; 81 int infft; 82 char *progressCmd; 83 char *windowTypeStr; 84 Tcl_Interp *interp; 85 double preemph; 86 87} SpectrogramItem; 88 89float xfft[NMAX]; 90 91static int ParseColorMap(ClientData clientData, Tcl_Interp *interp, 92 Tk_Window tkwin, CONST84 char *value, char *recordPtr, 93 int offset); 94 95static char *PrintColorMap(ClientData clientData, Tk_Window tkwin, 96 char *recordPtr, int offset, 97 Tcl_FreeProc **freeProcPtr); 98 99Tk_CustomOption spegTagsOption = { (Tk_OptionParseProc *) NULL, 100 (Tk_OptionPrintProc *) NULL, 101 (ClientData) NULL }; 102 103static Tk_CustomOption colorMapOption = { ParseColorMap, 104 PrintColorMap, 105 (ClientData) NULL}; 106 107typedef enum { 108 OPTION_ANCHOR, 109 OPTION_TAGS, 110 OPTION_SOUND, 111 OPTION_HEIGHT, 112 OPTION_WIDTH, 113 OPTION_FFTLEN, 114 OPTION_WINLEN, 115 OPTION_PREEMP, 116 OPTION_PIXPSEC, 117 OPTION_START, 118 OPTION_END, 119 OPTION_BRIGHTNESS, 120 OPTION_CONTRAST, 121 OPTION_TOPFREQUENCY, 122 OPTION_GRIDTSPACING, 123 OPTION_GRIDFSPACING, 124 OPTION_CHANNEL, 125 OPTION_COLORMAP, 126 OPTION_PROGRESS, 127 OPTION_GRIDCOLOR, 128 OPTION_WINTYPE 129} ConfigSpec; 130 131static Tk_ConfigSpec configSpecs[] = { 132 133 {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, 134 "nw", Tk_Offset(SpectrogramItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, 135 136 {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, 137 (char *) NULL, 0, TK_CONFIG_NULL_OK, &spegTagsOption}, 138 139 {TK_CONFIG_STRING, "-sound", (char *) NULL, (char *) NULL, 140 "", Tk_Offset(SpectrogramItem, newSoundName), TK_CONFIG_NULL_OK}, 141 142 {TK_CONFIG_INT, "-height", (char *) NULL, (char *) NULL, 143 "128", Tk_Offset(SpectrogramItem, height), 0}, 144 145 {TK_CONFIG_INT, "-width", (char *) NULL, (char *) NULL, 146 "378", Tk_Offset(SpectrogramItem, width), 0}, 147 148 {TK_CONFIG_INT, "-fftlength", (char *) NULL, (char *) NULL, 149 "256", Tk_Offset(SpectrogramItem, si.fftlen), 0}, 150 151 {TK_CONFIG_INT, "-winlength", (char *) NULL, (char *) NULL, 152 "128", Tk_Offset(SpectrogramItem, si.winlen), 0}, 153 154 {TK_CONFIG_DOUBLE, "-preemphasisfactor", (char *) NULL, (char *) NULL, 155 "0.97", Tk_Offset(SpectrogramItem, preemph), 0}, 156 157 {TK_CONFIG_DOUBLE, "-pixelspersecond", "pps", (char *) NULL, 158 "250.0", Tk_Offset(SpectrogramItem, si.pixpsec), 0}, 159 160 {TK_CONFIG_INT, "-start", (char *) NULL, (char *) NULL, 161 "0", Tk_Offset(SpectrogramItem, startSmp), 0}, 162 163 {TK_CONFIG_INT, "-end", (char *) NULL, (char *) NULL, 164 "-1", Tk_Offset(SpectrogramItem, endSmp), 0}, 165 166 {TK_CONFIG_DOUBLE, "-brightness", (char *) NULL, (char *) NULL, 167 "0.0", Tk_Offset(SpectrogramItem, bright), 0}, 168 169 {TK_CONFIG_DOUBLE, "-contrast", (char *) NULL, (char *) NULL, 170 "0.0", Tk_Offset(SpectrogramItem, contrast), 0}, 171 172 {TK_CONFIG_DOUBLE, "-topfrequency", (char *) NULL, (char *) NULL, 173 "0.0", Tk_Offset(SpectrogramItem, topFrequency), 0}, 174 175 {TK_CONFIG_DOUBLE, "-gridtspacing", (char *) NULL, (char *) NULL, 176 "0.0", Tk_Offset(SpectrogramItem, si.gridTspacing), 0}, 177 178 {TK_CONFIG_INT, "-gridfspacing", (char *) NULL, (char *) NULL, 179 "0", Tk_Offset(SpectrogramItem, si.gridFspacing), 0}, 180 181 {TK_CONFIG_STRING, "-channel", (char *) NULL, (char *) NULL, 182 "-1", Tk_Offset(SpectrogramItem, channelstr), TK_CONFIG_NULL_OK}, 183 184 {TK_CONFIG_CUSTOM, "-colormap", (char *) NULL, (char *) NULL, 185 "", Tk_Offset(SpectrogramItem, si.xcolor), TK_CONFIG_NULL_OK, 186 &colorMapOption}, 187 188 {TK_CONFIG_STRING, "-progress", (char *) NULL, (char *) NULL, 189 "", Tk_Offset(SpectrogramItem, progressCmd), TK_CONFIG_NULL_OK}, 190 191 {TK_CONFIG_COLOR, "-gridcolor", (char *) NULL, (char *) NULL, 192 "red", Tk_Offset(SpectrogramItem, si.gridcolor), TK_CONFIG_NULL_OK}, 193 194 {TK_CONFIG_STRING, "-windowtype", (char *) NULL, (char *) NULL, 195 SNACK_DEFAULT_SPEGWINTYPE_NAME, Tk_Offset(SpectrogramItem, windowTypeStr), 196 0}, 197 198 {TK_CONFIG_INT, "-debug", (char *) NULL, (char *) NULL, 199 "0", Tk_Offset(SpectrogramItem, si.debug), 0}, 200 201 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, 202 (char *) NULL, 0, 0} 203 204}; 205 206/* 207 * Protos 208 */ 209 210static void ComputeSpectrogramBbox(Tk_Canvas canvas, 211 SpectrogramItem *spegPtr); 212 213static int ConfigureSpectrogram(Tcl_Interp *interp, Tk_Canvas canvas, 214 Tk_Item *itemPtr, int argc, 215 char **argv, int flags); 216 217static int CreateSpectrogram(Tcl_Interp *interp, Tk_Canvas canvas, 218 struct Tk_Item *itemPtr, 219 int argc, char **argv); 220 221static void DeleteSpectrogram(Tk_Canvas canvas, Tk_Item *itemPtr, 222 Display *display); 223 224static void DisplaySpectrogram(Tk_Canvas canvas, Tk_Item *itemPtr, 225 Display *display, Drawable dst, 226 int x, int y, int width, int height); 227 228static void ScaleSpectrogram(Tk_Canvas canvas, Tk_Item *itemPtr, 229 double originX, double originY, 230 double scaleX, double scaleY); 231 232static int SpectrogramCoords(Tcl_Interp *interp, Tk_Canvas canvas, 233 Tk_Item *itemPtr, int argc, char **argv); 234 235static int SpectrogramToArea(Tk_Canvas canvas, Tk_Item *itemPtr, 236 double *rectPtr); 237 238static double SpectrogramToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, 239 double *coordPtr); 240 241static int SpectrogramToPS(Tcl_Interp *interp, Tk_Canvas canvas, 242 Tk_Item *itemPtr, int prepass); 243 244static void TranslateSpectrogram(Tk_Canvas canvas, Tk_Item *itemPtr, 245 double deltaX, double deltaY); 246 247static int ComputeSpeg(SnackItemInfo *siPtr, int nfft); 248 249static void DrawSpeg(SnackItemInfo *siPtr, Display* display, 250 GC gc, int width, int height, int x, int w, int pos); 251 252/* 253 * Spectrogram item type 254 */ 255 256Tk_ItemType snackSpectrogramType = { 257 "spectrogram", 258 sizeof(SpectrogramItem), 259 CreateSpectrogram, 260 configSpecs, 261 ConfigureSpectrogram, 262 SpectrogramCoords, 263 DeleteSpectrogram, 264 DisplaySpectrogram, 265 0, 266 SpectrogramToPoint, 267 SpectrogramToArea, 268 SpectrogramToPS, 269 ScaleSpectrogram, 270 TranslateSpectrogram, 271 (Tk_ItemIndexProc *) NULL, 272 (Tk_ItemCursorProc *) NULL, 273 (Tk_ItemSelectionProc *) NULL, 274 (Tk_ItemInsertProc *) NULL, 275 (Tk_ItemDCharsProc *) NULL, 276 (Tk_ItemType *) NULL 277}; 278 279static int 280CreateSpectrogram(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, 281 int argc, char **argv) 282{ 283 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 284 Tk_Window tkwin = Tk_CanvasTkwin(canvas); 285 286 if (argc < 2) { 287 Tcl_AppendResult(interp, "wrong # args: should be \"", 288 Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", 289 itemPtr->typePtr->name, " x y ?opts?\"", (char *) NULL); 290 return TCL_ERROR; 291 } 292 293 spegPtr->canvas = canvas; 294 spegPtr->anchor = TK_ANCHOR_NW; 295 spegPtr->newSoundName = NULL; 296 spegPtr->soundName = NULL; 297 spegPtr->sound = NULL; 298 spegPtr->height = 128; 299 spegPtr->width = 378; 300 spegPtr->startSmp = 0; 301 spegPtr->endSmp = -1; 302 spegPtr->ssmp = 0; 303 spegPtr->esmp = -1; 304 spegPtr->id = 0; 305 spegPtr->mode = CONF_WIDTH; 306 spegPtr->bright = 0.0; 307 spegPtr->contrast = 0.0; 308 spegPtr->si.fftlen = 256; 309 spegPtr->si.winlen = 128; 310 spegPtr->si.spacing = 64.0; 311 spegPtr->preemph = 0.97; 312 spegPtr->si.frame[0] = (short *) ckalloc(2*FRAMESIZE); 313 spegPtr->si.nfrms = 1; 314 spegPtr->si.frlen = FRAMESIZE; 315 spegPtr->si.RestartPos = 0; 316 spegPtr->si.fftmax = -10000; 317 spegPtr->si.fftmin = 10000; 318 spegPtr->si.debug = 1; 319 spegPtr->si.hamwin = (float *) ckalloc(NMAX * sizeof(float)); 320 spegPtr->si.BufPos = 0; 321 spegPtr->si.abmax = 0.0f; 322 spegPtr->si.bright = 60.0; 323 spegPtr->si.contrast = 2.3; 324 spegPtr->si.pixpsec = 250.0; 325 spegPtr->si.gridTspacing = 0.0; 326 spegPtr->si.gridFspacing = 0; 327 spegPtr->channelstr = NULL; 328 spegPtr->si.channel = -1; 329 spegPtr->si.channelSet = -1; 330 spegPtr->si.nchannels = 1; 331 spegPtr->si.ncolors = 0; 332 spegPtr->si.xcolor = NULL; 333 spegPtr->si.pixmap = None; 334 spegPtr->si.gridcolor = None; 335 spegPtr->si.depth = Tk_Depth(tkwin); 336 spegPtr->si.visual = Tk_Visual(tkwin); 337 spegPtr->si.pixelmap = NULL; 338 spegPtr->si.display = Tk_Display(tkwin); 339 spegPtr->topFrequency = 0.0; 340 spegPtr->si.xUnderSamp = 1.0; 341 spegPtr->si.xTot = 0; 342 spegPtr->infft = 0; 343 spegPtr->si.doneSpeg = 0; 344 spegPtr->si.validStart = 0; 345 spegPtr->progressCmd = NULL; 346 spegPtr->si.cmdPtr = NULL; 347 spegPtr->si.windowType = SNACK_DEFAULT_SPEGWINTYPE; 348 spegPtr->si.windowTypeSet = SNACK_DEFAULT_SPEGWINTYPE; 349 spegPtr->windowTypeStr = NULL; 350 spegPtr->interp = interp; 351 352 /* spegPtr->si.computing = 0;*/ 353 354 if (spegPtr->si.frame[0] == NULL) { 355 Tcl_AppendResult(interp, "Couldn't allocate fft buffer!", NULL); 356 return TCL_ERROR; 357 } 358 359 if (spegPtr->si.hamwin == NULL) { 360 Tcl_AppendResult(interp, "Couldn't allocate analysis window buffer!", 361 NULL); 362 ckfree((char *) spegPtr->si.frame[0]); 363 return TCL_ERROR; 364 } 365 366 if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &spegPtr->x) != TCL_OK) 367 || (Tk_CanvasGetCoord(interp, canvas, argv[1], &spegPtr->y) != TCL_OK)) 368 return TCL_ERROR; 369 370 if (ConfigureSpectrogram(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { 371 DeleteSpectrogram(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); 372 return TCL_ERROR; 373 } 374 return TCL_OK; 375} 376 377static int 378SpectrogramCoords(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, 379 int argc, char **argv) 380{ 381 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 382 char xc[TCL_DOUBLE_SPACE], yc[TCL_DOUBLE_SPACE]; 383 384 if (argc == 0) { 385 Tcl_PrintDouble(interp, spegPtr->x, xc); 386 Tcl_PrintDouble(interp, spegPtr->y, yc); 387 Tcl_AppendResult(interp, xc, " ", yc, (char *) NULL); 388 } else if (argc == 2) { 389 if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &spegPtr->x) != TCL_OK) || 390 (Tk_CanvasGetCoord(interp, canvas, argv[1], &spegPtr->y) != TCL_OK)) { 391 return TCL_ERROR; 392 } 393 ComputeSpectrogramBbox(canvas, spegPtr); 394 } else { 395 char buf[80]; 396 397 sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc); 398 Tcl_SetResult(interp, buf, TCL_VOLATILE); 399 400 return TCL_ERROR; 401 } 402 return TCL_OK; 403} 404 405static void 406UpdateSpeg(ClientData clientData, int flag) 407{ 408 SpectrogramItem *spegPtr = (SpectrogramItem *) clientData; 409 Sound *s = spegPtr->sound; 410 int nfft = 0; 411 412 if (spegPtr->si.debug > 1) Snack_WriteLogInt(" Enter UpdateSpeg", flag); 413 414 if (spegPtr->canvas == NULL) return; 415 416 if (flag == SNACK_DESTROY_SOUND) { 417 spegPtr->sound = NULL; 418 if (spegPtr->id) Snack_RemoveCallback(s, spegPtr->id); 419 spegPtr->id = 0; 420 return; 421 } 422 423 Tk_CanvasEventuallyRedraw(spegPtr->canvas, 424 spegPtr->header.x1, spegPtr->header.y1, 425 spegPtr->header.x2, spegPtr->header.y2); 426 427 spegPtr->si.blocks = s->blocks; 428 spegPtr->si.BufPos = s->length; 429 spegPtr->si.storeType = s->storeType; 430 431 if ((flag == SNACK_MORE_SOUND) || (spegPtr->endSmp < 0)) { 432 spegPtr->esmp = spegPtr->si.BufPos - 1; 433 } 434 435 if (spegPtr->endSmp > 0) 436 spegPtr->esmp = spegPtr->endSmp; 437 /* 438 if (spegPtr->endSmp < 0) 439 spegPtr->esmp = spegPtr->si.BufPos - 1; 440 */ 441 if (spegPtr->esmp > spegPtr->si.BufPos - 1) 442 spegPtr->esmp = spegPtr->si.BufPos - 1; 443 444 if (spegPtr->endSmp > spegPtr->si.BufPos - 1) 445 spegPtr->esmp = spegPtr->si.BufPos - 1; 446 447 spegPtr->ssmp = spegPtr->startSmp; 448 449 if (spegPtr->ssmp > spegPtr->esmp) 450 spegPtr->ssmp = spegPtr->esmp; 451 452 spegPtr->si.channel = spegPtr->si.channelSet; 453 if (spegPtr->si.nchannels == 1) { 454 spegPtr->si.channel = 0; 455 } 456 457 if (flag == SNACK_NEW_SOUND) { 458 spegPtr->si.samprate = s->samprate; 459 spegPtr->si.encoding = s->encoding; 460 spegPtr->si.nchannels = s->nchannels; 461 spegPtr->si.abmax = s->abmax; 462 spegPtr->si.fftmax = -10000; 463 spegPtr->si.fftmin = 10000; 464 spegPtr->si.RestartPos = spegPtr->ssmp; 465 spegPtr->si.nfft = 0; 466 spegPtr->si.xTot = 0; 467 } 468 469 if (spegPtr->topFrequency <= 0.0) { 470 spegPtr->si.topfrequency = spegPtr->si.samprate / 2.0; 471 } else if (spegPtr->topFrequency > spegPtr->si.samprate / 2.0) { 472 spegPtr->si.topfrequency = spegPtr->si.samprate / 2.0; 473 } else { 474 spegPtr->si.topfrequency = spegPtr->topFrequency; 475 } 476 477 if (flag == SNACK_NEW_SOUND && spegPtr->mode == CONF_WIDTH) { 478 spegPtr->infft = (int)((spegPtr->esmp - spegPtr->ssmp) /spegPtr->si.spacing); 479 nfft = (int)(((spegPtr->esmp - spegPtr->ssmp) 480 - spegPtr->si.fftlen / 2) / spegPtr->si.spacing); 481 } else if (flag == SNACK_NEW_SOUND && spegPtr->mode == CONF_PPS){ 482 spegPtr->infft = (int)((spegPtr->esmp - spegPtr->ssmp) / spegPtr->si.spacing); 483 nfft = (int)(((spegPtr->esmp - spegPtr->ssmp) 484 - spegPtr->si.fftlen / 2) / spegPtr->si.spacing); 485 } else if (flag == SNACK_NEW_SOUND && spegPtr->mode == CONF_WIDTH_PPS) { 486 spegPtr->ssmp = (int) (spegPtr->esmp - spegPtr->width * 487 spegPtr->si.samprate / spegPtr->si.pixpsec); 488 spegPtr->si.RestartPos = spegPtr->ssmp; 489 spegPtr->infft = (int)((spegPtr->esmp - spegPtr->ssmp) / 490 spegPtr->si.spacing); 491 nfft = (int)(((spegPtr->esmp - spegPtr->ssmp) 492 - spegPtr->si.fftlen / 2) / spegPtr->si.spacing); 493 } else { 494 spegPtr->infft = (int)(s->length / spegPtr->si.spacing); 495 nfft = (int)((s->length - spegPtr->si.RestartPos 496 - spegPtr->si.fftlen / 2) / spegPtr->si.spacing); 497 } 498 499 spegPtr->si.validStart = s->validStart; 500 501 if (nfft > 0) { 502 int n = ComputeSpeg(&spegPtr->si, nfft); 503 if (n < 0) return; 504 spegPtr->si.RestartPos += (int)(n * spegPtr->si.spacing); 505 506 if (spegPtr->mode == CONF_WIDTH) { 507 if (spegPtr->esmp != spegPtr->ssmp) { 508 spegPtr->si.pixpsec = (float) spegPtr->width * spegPtr->si.samprate / 509 (spegPtr->esmp - spegPtr->ssmp); 510 } 511 spegPtr->si.xUnderSamp = (float) spegPtr->infft / spegPtr->width; 512 DrawSpeg(&spegPtr->si, spegPtr->si.display, spegPtr->copyGC, 513 spegPtr->width, spegPtr->height, 0, spegPtr->width, 0); 514 } 515 else if (spegPtr->mode == CONF_PPS) { 516 spegPtr->width = (int)((spegPtr->esmp - spegPtr->ssmp) * 517 spegPtr->si.pixpsec / spegPtr->si.samprate); 518 if (spegPtr->width > 32767) { 519 spegPtr->width = 32767; 520 } 521 if (spegPtr->si.pixmap != None) { 522 Tk_FreePixmap(spegPtr->si.display, spegPtr->si.pixmap); 523 spegPtr->si.pixmap = None; 524 } 525 if (spegPtr->si.pixmap == None) { 526 if (spegPtr->width > 0) { 527 Tk_Window w = Tk_CanvasTkwin(spegPtr->canvas); 528 529 spegPtr->oldwidth = spegPtr->width; 530 spegPtr->oldheight = spegPtr->height; 531 spegPtr->si.pixmap = Tk_GetPixmap(Tk_Display(w), 532 RootWindow(Tk_Display(w), Tk_ScreenNumber(w)), 533 spegPtr->width, spegPtr->height, Tk_Depth(w)); 534 } 535 } 536 DrawSpeg(&spegPtr->si, spegPtr->si.display, spegPtr->copyGC, 537 spegPtr->width, spegPtr->height, 0, spegPtr->width, 0); 538 } 539 else if (spegPtr->mode == CONF_WIDTH_PPS) { 540 int virtx = (int) (spegPtr->si.nfft / spegPtr->si.xUnderSamp); 541 int dx = virtx - (int)((spegPtr->si.nfft - n) / spegPtr->si.xUnderSamp); 542 spegPtr->ssmp = (int) (spegPtr->esmp - spegPtr->width * 543 spegPtr->si.samprate / spegPtr->si.pixpsec); 544 545 XCopyArea(spegPtr->si.display, spegPtr->si.pixmap, spegPtr->si.pixmap, 546 spegPtr->copyGC, dx, 0, spegPtr->width - dx, spegPtr->height, 547 0, 0); 548 DrawSpeg(&spegPtr->si, spegPtr->si.display, spegPtr->copyGC, 549 spegPtr->width, spegPtr->height, spegPtr->width - dx, dx, 550 spegPtr->si.nfft - n - 1); 551 } 552 } 553 554 ComputeSpectrogramBbox(spegPtr->canvas, spegPtr); 555 556 Tk_CanvasEventuallyRedraw(spegPtr->canvas, 557 spegPtr->header.x1, spegPtr->header.y1, 558 spegPtr->header.x2, spegPtr->header.y2); 559 560 if (spegPtr->si.debug > 1) { 561 Snack_WriteLogInt(" Exit UpdateSpeg", spegPtr->width); 562 } 563} 564 565static int 566ConfigureSpectrogram(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, 567 int argc, char **argv, int flags) 568{ 569 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 570 Sound *s = spegPtr->sound; 571 Tk_Window tkwin = Tk_CanvasTkwin(canvas); 572 XGCValues gcValues; 573 int doCompute = 0; 574 int i, j; 575 576 if (argc == 0) return TCL_OK; 577 578 /* if (spegPtr->si.computing) return TCL_OK;*/ 579 580 if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, 581 (CONST84 char **)argv, 582 (char *) spegPtr, flags) != TCL_OK) return TCL_ERROR; 583 584 if (spegPtr->si.debug > 1) Snack_WriteLog(" Enter ConfigureSpeg\n"); 585 586 for (i = 0; configSpecs[i].type != TK_CONFIG_END; i++) { 587 for (j = 0; j < argc; j += 2) { 588 if (strncmp(argv[j], configSpecs[i].argvName, strlen(argv[j])) == 0) { 589 configSpecs[i].specFlags |= TK_CONFIG_OPTION_SPECIFIED; 590 break; 591 } 592 } 593 } 594 595#if defined(MAC) || defined(MAC_OSX_TCL) 596 for (i = 0; i < argc; i++) { 597 int l = strlen(argv[i]); 598 if (l && strncmp(argv[i], "-anchor", l) == 0) { 599 i++; 600 if (strcmp(argv[i], "ne") == 0) { 601 spegPtr->anchor = 1; 602 } else if (strcmp(argv[i], "nw") == 0) { 603 spegPtr->anchor = 7; 604 } else if (strcmp(argv[i], "n") == 0) { 605 spegPtr->anchor = 0; 606 } else if (strcmp(argv[i], "e") == 0) { 607 spegPtr->anchor = 2; 608 } else if (strcmp(argv[i], "se") == 0) { 609 spegPtr->anchor = 3; 610 } else if (strcmp(argv[i], "sw") == 0) { 611 spegPtr->anchor = 5; 612 } else if (strcmp(argv[i], "s") == 0) { 613 spegPtr->anchor = 4; 614 } else if (strcmp(argv[i], "w") == 0) { 615 spegPtr->anchor = 6; 616 } else if (strncmp(argv[i], "center", strlen(argv[i])) == 0) { 617 spegPtr->anchor = 8; 618 } 619 break; 620 } 621 } 622#endif 623 624 if (CheckFFTlen(interp, spegPtr->si.fftlen) != TCL_OK) return TCL_ERROR; 625 626 if (CheckWinlen(interp, spegPtr->si.winlen, spegPtr->si.fftlen) != TCL_OK) 627 return TCL_ERROR; 628 629 if (OptSpecified(OPTION_SOUND)) { 630 if (spegPtr->newSoundName == NULL) { 631 spegPtr->sound = NULL; 632 if (spegPtr->id) Snack_RemoveCallback(s, spegPtr->id); 633 spegPtr->id = 0; 634 spegPtr->si.BufPos = 0; 635 doCompute = 1; 636 } else { 637 if ((s = Snack_GetSound(interp, spegPtr->newSoundName)) == NULL) { 638 return TCL_ERROR; 639 } 640 if (s->storeType == SOUND_IN_CHANNEL) { 641 Tcl_AppendResult(interp, spegPtr->newSoundName, 642 " can not be linked to a channel", (char *) NULL); 643 return TCL_ERROR; 644 } 645 if (s->storeType == SOUND_IN_FILE) { 646 s->itemRefCnt++; 647 } 648 spegPtr->sound = s; 649 if (spegPtr->soundName == NULL) { 650 spegPtr->soundName = ckalloc(strlen(spegPtr->newSoundName)+1); 651 strcpy(spegPtr->soundName, spegPtr->newSoundName); 652 } 653 if (strcmp(spegPtr->soundName, spegPtr->newSoundName) != 0) { 654 Sound *t = Snack_GetSound(interp, spegPtr->soundName); 655 ckfree(spegPtr->soundName); 656 spegPtr->soundName = ckalloc(strlen(spegPtr->newSoundName)+1); 657 strcpy(spegPtr->soundName, spegPtr->newSoundName); 658 spegPtr->ssmp = 0; 659 spegPtr->esmp = -1; 660 Snack_RemoveCallback(t, spegPtr->id); 661 spegPtr->id = 0; 662 } 663 if (!spegPtr->id) 664 spegPtr->id = Snack_AddCallback(s, UpdateSpeg, (int *)spegPtr); 665 spegPtr->si.blocks = s->blocks; 666 spegPtr->si.BufPos = s->length; 667 spegPtr->si.samprate = s->samprate; 668 spegPtr->si.encoding = s->encoding; 669 spegPtr->si.nchannels = s->nchannels; 670 spegPtr->si.abmax = s->abmax; 671 spegPtr->si.storeType = s->storeType; 672 spegPtr->si.sound = spegPtr->sound; 673 doCompute = 1; 674 } 675 } 676 677 spegPtr->copyGC = Tk_GetGC(tkwin, 0, &gcValues); 678 679 spegPtr->esmp = spegPtr->endSmp; 680 681 if (spegPtr->endSmp < 0) 682 spegPtr->esmp = spegPtr->si.BufPos - 1; 683 684 if (spegPtr->endSmp > spegPtr->si.BufPos - 1) 685 spegPtr->esmp = spegPtr->si.BufPos - 1; 686 687 if (spegPtr->startSmp > spegPtr->endSmp && spegPtr->endSmp >= 0) 688 spegPtr->startSmp = spegPtr->endSmp; 689 690 if (spegPtr->startSmp < 0) 691 spegPtr->startSmp = 0; 692 693 spegPtr->ssmp = spegPtr->startSmp; 694 695 if (spegPtr->ssmp > spegPtr->esmp) 696 spegPtr->ssmp = spegPtr->esmp; 697 698 spegPtr->si.preemph = (float) spegPtr->preemph; 699 700 if (OptSpecified(OPTION_START)) { 701 doCompute = 1; 702 } 703 704 if (OptSpecified(OPTION_END)) { 705 doCompute = 1; 706 } 707 708 if (OptSpecified(OPTION_WINLEN)) { 709 doCompute = 1; 710 } 711 712 if (OptSpecified(OPTION_FFTLEN)) { 713 doCompute = 1; 714 } 715 716 if (OptSpecified(OPTION_PIXPSEC) && OptSpecified(OPTION_WIDTH)) { 717 spegPtr->mode = CONF_WIDTH_PPS; 718 } 719 else if (OptSpecified(OPTION_PIXPSEC)) { 720 spegPtr->mode = CONF_PPS; 721 } 722 else if (OptSpecified(OPTION_WIDTH)) { 723 spegPtr->mode = CONF_WIDTH; 724 } 725 726 if (spegPtr->mode == CONF_WIDTH_PPS) { 727 if (OptSpecified(OPTION_END) && !OptSpecified(OPTION_START)) { 728 spegPtr->ssmp = (int) (spegPtr->esmp - spegPtr->width * 729 spegPtr->si.samprate / spegPtr->si.pixpsec); 730 } else { 731 spegPtr->esmp = (int) (spegPtr->ssmp + spegPtr->width * 732 spegPtr->si.samprate / spegPtr->si.pixpsec); 733 if (spegPtr->esmp > spegPtr->si.BufPos - 1) { 734 spegPtr->esmp = spegPtr->si.BufPos - 1; 735 } 736 } 737 doCompute = 1; 738 } 739 else if (spegPtr->mode == CONF_PPS) { 740 spegPtr->width = (int)((spegPtr->esmp - spegPtr->ssmp) * 741 spegPtr->si.pixpsec / spegPtr->si.samprate); 742 } 743 else if (spegPtr->mode == CONF_WIDTH) { 744 if (spegPtr->esmp != spegPtr->ssmp) { 745 spegPtr->si.pixpsec = (float) spegPtr->width * spegPtr->si.samprate / 746 (spegPtr->esmp - spegPtr->ssmp); 747 } 748 } 749 750 if (spegPtr->width > 32767) { 751 spegPtr->width = 32767; 752 spegPtr->esmp = (int) (spegPtr->ssmp + spegPtr->width * 753 spegPtr->si.samprate / spegPtr->si.pixpsec); 754 } 755 756 if (OptSpecified(OPTION_HEIGHT)) { 757 } 758 759 if (OptSpecified(OPTION_BRIGHTNESS)) { 760 if (spegPtr->bright > 100.0) { 761 spegPtr->bright = 100.0; 762 } else if (spegPtr->bright < -100.0) { 763 spegPtr->bright = -100.0; 764 } 765 spegPtr->si.bright = spegPtr->bright * 0.3 + 60.0; 766 } 767 768 if (OptSpecified(OPTION_CONTRAST)) { 769 if (spegPtr->contrast > 100.0) { 770 spegPtr->contrast = 100.0; 771 } else if (spegPtr->contrast < -100.0) { 772 spegPtr->contrast = -100.0; 773 } 774 if (spegPtr->contrast >= 0.0) { 775 spegPtr->si.contrast = 2.3 + spegPtr->contrast * 0.04; 776 } else { 777 spegPtr->si.contrast = 2.3 + spegPtr->contrast * 0.023; 778 } 779 } 780 781 if (spegPtr->topFrequency <= 0.0) { 782 spegPtr->si.topfrequency = spegPtr->si.samprate / 2.0; 783 } else if (spegPtr->topFrequency > spegPtr->si.samprate / 2.0) { 784 spegPtr->si.topfrequency = spegPtr->si.samprate / 2.0; 785 } else { 786 spegPtr->si.topfrequency = spegPtr->topFrequency; 787 } 788 789 if (OptSpecified(OPTION_CHANNEL)) { 790 if (GetChannel(interp, spegPtr->channelstr, spegPtr->si.nchannels, 791 &spegPtr->si.channelSet) != TCL_OK) { 792 return TCL_ERROR; 793 } 794 doCompute = 1; 795 } 796 spegPtr->si.channel = spegPtr->si.channelSet; 797 if (spegPtr->si.nchannels == 1) { 798 spegPtr->si.channel = 0; 799 } 800 801 /* if (OptSpecified(OPTION_PROGRESS)) { 802 spegPtr->si.cmdPtr = Tcl_NewStringObj(spegPtr->progressCmd, -1); 803 Tcl_IncrRefCount(spegPtr->si.cmdPtr); 804 }*/ 805 806 if (OptSpecified(OPTION_WINTYPE)) { 807 if (GetWindowType(interp, spegPtr->windowTypeStr, 808 &spegPtr->si.windowTypeSet) 809 != TCL_OK) { 810 return TCL_ERROR; 811 } 812 doCompute = 1; 813 } 814 spegPtr->si.windowType = spegPtr->si.windowTypeSet; 815 816 if (doCompute) { 817 int nfft, n; 818 819 spegPtr->si.nfft = 0; 820 spegPtr->si.spacing = (float)(spegPtr->si.samprate / spegPtr->si.pixpsec); 821 nfft = (int)((spegPtr->esmp - spegPtr->ssmp) / spegPtr->si.spacing); 822 spegPtr->si.xUnderSamp = 1.0; 823 spegPtr->si.RestartPos = spegPtr->ssmp; 824 spegPtr->si.fftmax = -10000; 825 spegPtr->si.fftmin = 10000; 826 spegPtr->si.ssmp = spegPtr->ssmp; 827 828 n = ComputeSpeg(&spegPtr->si, nfft); 829 830 if (n < 0) return TCL_OK; 831 spegPtr->infft = nfft; 832 } 833 834 if (spegPtr->si.pixmap != None && 835 (spegPtr->width != spegPtr->oldwidth || 836 spegPtr->height != spegPtr->oldheight)) { 837 Tk_FreePixmap(spegPtr->si.display, spegPtr->si.pixmap); 838 spegPtr->si.pixmap = None; 839 } 840 if (spegPtr->si.pixmap == None) { 841 if (spegPtr->width > 0 && spegPtr->height > 0) { 842 spegPtr->oldwidth = spegPtr->width; 843 spegPtr->oldheight = spegPtr->height; 844 spegPtr->si.pixmap = Tk_GetPixmap(Tk_Display(tkwin), 845 RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)), 846 spegPtr->width, spegPtr->height, Tk_Depth(tkwin)); 847 } 848 } 849 850 if (spegPtr->mode == CONF_WIDTH_PPS) { 851 if (spegPtr->esmp != spegPtr->ssmp) { 852 spegPtr->si.xUnderSamp = spegPtr->infft / 853 ((spegPtr->esmp - spegPtr->ssmp) 854 * (float) spegPtr->si.pixpsec / spegPtr->si.samprate); 855 } 856 } 857 else if (spegPtr->mode == CONF_PPS) { 858 if (spegPtr->width > 0) { 859 spegPtr->si.xUnderSamp = (float) spegPtr->infft / spegPtr->width; 860 } 861 } 862 else if (spegPtr->mode == CONF_WIDTH) { 863 if (spegPtr->width > 0) { 864 spegPtr->si.xUnderSamp = (float) spegPtr->infft / spegPtr->width; 865 } 866 } 867 868 spegPtr->si.xTot = 0; 869 DrawSpeg(&spegPtr->si, Tk_Display(tkwin), spegPtr->copyGC, 870 spegPtr->width, spegPtr->height, 0, spegPtr->width, 0); 871 ComputeSpectrogramBbox(canvas, spegPtr); 872 873 for (i = 0; configSpecs[i].type != TK_CONFIG_END; i++) { 874 configSpecs[i].specFlags &= ~TK_CONFIG_OPTION_SPECIFIED; 875 } 876 877 if (spegPtr->si.debug > 1) Snack_WriteLog(" Exit ConfigureSpeg\n"); 878 879 return TCL_OK; 880} 881 882static void 883DeleteSpectrogram(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display) 884{ 885 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 886 int i; 887 888 if ((spegPtr->id) && 889 (Snack_GetSound(spegPtr->interp, spegPtr->soundName) != NULL)) { 890 Snack_RemoveCallback(spegPtr->sound, spegPtr->id); 891 } 892 893 if (spegPtr->soundName != NULL) ckfree(spegPtr->soundName); 894 895 if (spegPtr->si.hamwin != NULL) ckfree((char *) spegPtr->si.hamwin); 896 897 for (i = 0; i < spegPtr->si.nfrms; i++) { 898 ckfree((char *)spegPtr->si.frame[i]); 899 } 900 901 for (i = 0; i < spegPtr->si.ncolors; i++) { 902 Tk_FreeColor(spegPtr->si.xcolor[i]); 903 } 904 905 if (spegPtr->si.gridcolor != NULL) Tk_FreeColor(spegPtr->si.gridcolor); 906 907 if (spegPtr->si.pixmap != None) { 908 Tk_FreePixmap(spegPtr->si.display, spegPtr->si.pixmap); 909 } 910 911 if (spegPtr->sound != NULL) { 912 if (spegPtr->sound->storeType == SOUND_IN_FILE) { 913 spegPtr->sound->itemRefCnt--; 914 } 915 } 916} 917 918static void 919ComputeSpectrogramBbox(Tk_Canvas canvas, SpectrogramItem *spegPtr) 920{ 921 int width = spegPtr->width; 922 int height = spegPtr->height; 923 int x = (int) (spegPtr->x + ((spegPtr->x >= 0) ? 0.5 : - 0.5)); 924 int y = (int) (spegPtr->y + ((spegPtr->y >= 0) ? 0.5 : - 0.5)); 925 926 switch (spegPtr->anchor) { 927 case TK_ANCHOR_N: 928 x -= width/2; 929 break; 930 case TK_ANCHOR_NE: 931 x -= width; 932 break; 933 case TK_ANCHOR_E: 934 x -= width; 935 y -= height/2; 936 break; 937 case TK_ANCHOR_SE: 938 x -= width; 939 y -= height; 940 break; 941 case TK_ANCHOR_S: 942 x -= width/2; 943 y -= height; 944 break; 945 case TK_ANCHOR_SW: 946 y -= height; 947 break; 948 case TK_ANCHOR_W: 949 y -= height/2; 950 break; 951 case TK_ANCHOR_NW: 952 break; 953 case TK_ANCHOR_CENTER: 954 x -= width/2; 955 y -= height/2; 956 break; 957 } 958 959 spegPtr->header.x1 = x; 960 spegPtr->header.y1 = y; 961 spegPtr->header.x2 = x + width; 962 spegPtr->header.y2 = y + height; 963} 964 965static void 966DisplaySpectrogram(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, 967 Drawable drawable, int x, int y, int width, int height) 968{ 969 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 970 short drawableX, drawableY; 971 int xcoord = 0; 972 973 if (spegPtr->si.debug > 1) Snack_WriteLogInt(" Enter DisplaySpeg", width); 974 975 if (spegPtr->width == 0 || spegPtr->height == 0) return; 976 /* if (spegPtr->si.computing) return;*/ 977 978 Tk_CanvasDrawableCoords(canvas, (double) spegPtr->header.x1, 979 (double) spegPtr->header.y1, &drawableX, &drawableY); 980 981 if (x < spegPtr->header.x1) { 982 xcoord = 0; 983 } else { 984 xcoord = x - spegPtr->header.x1; 985 } 986 if (width > spegPtr->width) { 987 width = spegPtr->width; 988 } 989 990 XCopyArea(display, spegPtr->si.pixmap, drawable, spegPtr->copyGC, xcoord, 0, 991 width, spegPtr->height, drawableX+xcoord, drawableY); 992 993 if (spegPtr->si.debug > 1) Snack_WriteLog(" Exit DisplaySpeg\n"); 994} 995 996static double 997SpectrogramToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *coordPtr) 998{ 999 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 1000 double dx = 0.0, dy = 0.0; 1001 double x1 = spegPtr->header.x1; 1002 double y1 = spegPtr->header.y1; 1003 double x2 = spegPtr->header.x2; 1004 double y2 = spegPtr->header.y2; 1005 1006 if (coordPtr[0] < x1) 1007 dx = x1 - coordPtr[0]; 1008 else if (coordPtr[0] > x2) 1009 dx = coordPtr[0] - x2; 1010 1011 if (coordPtr[1] < y1) 1012 dy = y1 - coordPtr[1]; 1013 else if (coordPtr[1] > y2) 1014 dy = coordPtr[1] - y2; 1015 1016 return hypot(dx, dy); 1017} 1018 1019static int 1020SpectrogramToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr) 1021{ 1022 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 1023 1024 if ((rectPtr[2] <= spegPtr->header.x1) || 1025 (rectPtr[0] >= spegPtr->header.x2) || 1026 (rectPtr[3] <= spegPtr->header.y1) || 1027 (rectPtr[1] >= spegPtr->header.y2)) 1028 return -1; 1029 1030 if ((rectPtr[0] <= spegPtr->header.x1) && 1031 (rectPtr[1] <= spegPtr->header.y1) && 1032 (rectPtr[2] >= spegPtr->header.x2) && 1033 (rectPtr[3] >= spegPtr->header.y2)) 1034 return 1; 1035 1036 return 0; 1037} 1038 1039static void 1040ScaleSpectrogram(Tk_Canvas canvas, Tk_Item *itemPtr, double ox, double oy, 1041 double sx, double sy) 1042{ 1043 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 1044 1045 spegPtr->x = ox + sx * (spegPtr->x - ox); 1046 spegPtr->y = oy + sy * (spegPtr->y - oy); 1047 1048 spegPtr->width = (int) (sx * spegPtr->width); 1049 spegPtr->height = (int) (sy * spegPtr->height); 1050 1051 if (spegPtr->si.BufPos > 0) 1052 spegPtr->si.pixpsec = spegPtr->width * spegPtr->si.samprate / 1053 (spegPtr->esmp - spegPtr->ssmp); 1054 1055 ComputeSpectrogramBbox(canvas, spegPtr); 1056} 1057 1058static void 1059TranslateSpectrogram(Tk_Canvas canvas, Tk_Item *itemPtr, double dx, double dy) 1060{ 1061 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 1062 1063 spegPtr->x += dx; 1064 spegPtr->y += dy; 1065 ComputeSpectrogramBbox(canvas, spegPtr); 1066} 1067 1068#define FFTBUF2(i) *(spegPtr->si.frame[(i)>>18] + ((i)&(FRAMESIZE-1))) 1069 1070static int 1071SpectrogramToPS(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, 1072 int prepass) 1073{ 1074 SpectrogramItem *spegPtr = (SpectrogramItem *) itemPtr; 1075 char buffer[100]; 1076 int x, y, i, j, noColor = 1; 1077 int nbins = spegPtr->si.fftlen / 2; 1078 int height = 2 * spegPtr->height; 1079 int width = 2 * spegPtr->width; 1080 int nfft = (int)(((spegPtr->esmp - spegPtr->ssmp)) / spegPtr->si.spacing); 1081 short v[NMAX + 1]; 1082 unsigned char *imageR, *imageG, *imageB; 1083 1084 /* if (width == 0 || height == 0) return TCL_OK;*/ 1085 1086 for (i = 0; i < spegPtr->si.ncolors; i++) { 1087 if ((spegPtr->si.xcolor[i]->red != spegPtr->si.xcolor[i]->green) || 1088 (spegPtr->si.xcolor[i]->red != spegPtr->si.xcolor[i]->blue)) { 1089 noColor = 0; 1090 } 1091 } 1092 if ((spegPtr->si.gridcolor->red != spegPtr->si.gridcolor->green) || 1093 (spegPtr->si.gridcolor->red != spegPtr->si.gridcolor->blue)) { 1094 noColor = 0; 1095 } 1096 1097 if ((imageR = (unsigned char *) ckalloc(width * height)) == NULL) 1098 return TCL_ERROR; 1099 if ((imageG = (unsigned char *) ckalloc(width * height)) == NULL) 1100 return TCL_ERROR; 1101 if ((imageB = (unsigned char *) ckalloc(width * height)) == NULL) 1102 return TCL_ERROR; 1103 1104 for (i = 0; i < width; i++) { 1105 int top = (int) ((1.0 - (spegPtr->si.topfrequency / 1106 (spegPtr->si.samprate/2))) * nbins); 1107 float yscale = (float) (nbins - top)/ height; 1108 float xscale = (float) (nfft - 1) / width; 1109 float k = (float) (spegPtr->si.contrast * spegPtr->si.ncolors / 1110 (spegPtr->si.fftmax - spegPtr->si.fftmin)); 1111 float fx = xscale * i; 1112 int ix = (int) fx; 1113 float deltax = fx - ix; 1114 int p = ix * nbins; 1115 int q = (ix + 1) * nbins; 1116 1117 for (j = 0; j < nbins; j++) { 1118 1119 if (nfft >= width) { /* subsample in x direction */ 1120 v[j] = (short) (k * (FFTBUF2(p) - spegPtr->si.fftmin - spegPtr->si.bright)); 1121 p++; 1122 } else { /* interpolate in x direction */ 1123 v[j] = (short) (k * ((FFTBUF2(p) - spegPtr->si.fftmin - spegPtr->si.bright) + 1124 deltax * (FFTBUF2(q) - FFTBUF2(p)))); 1125 p++; q++; 1126 } 1127 } 1128 v[nbins] = v[nbins - 1]; 1129 for (j = 0; j < height; j++) { 1130 int c; 1131 float fy = yscale * j; 1132 int iy = (int) fy; 1133 1134 if (height <= nbins) /* subsample in y direction */ 1135 c = v[iy]; 1136 else /* interpolate in y direction */ 1137 c = (int) (v[iy] + (fy - iy) * (v[iy + 1] - v[iy])); 1138 1139 if (c >= spegPtr->si.ncolors) { 1140 c = spegPtr->si.ncolors - 1; 1141 } 1142 if (c < 0) { 1143 c = 0; 1144 } 1145 1146 imageR[i + width * (height - j - 1)] = spegPtr->si.xcolor[c]->red >> 8; 1147 imageG[i + width * (height - j - 1)] = spegPtr->si.xcolor[c]->green >> 8; 1148 imageB[i + width * (height - j - 1)] = spegPtr->si.xcolor[c]->blue >> 8; 1149 } 1150 } 1151 1152 if ((spegPtr->si.gridFspacing > 0) && (spegPtr->si.gridTspacing > 0.0)) { 1153 float i, j; 1154 float di = (float) (spegPtr->si.pixpsec * spegPtr->si.gridTspacing); 1155 float dj = (float) ((float) height / (spegPtr->si.topfrequency / 1156 (float) spegPtr->si.gridFspacing)); 1157 int k = 0; 1158 1159 for (j = (float) height - dj; j > 0.0; j -= dj) { 1160 for (i = di; i < (float) width; i += di) { 1161 for (k = -5; k <= 5; k++) { 1162 imageR[(int) (i+k) + width * (int) j] = spegPtr->si.gridcolor->red >> 8; 1163 imageG[(int) (i+k) + width * (int) j] = spegPtr->si.gridcolor->green >> 8; 1164 imageB[(int) (i+k) + width * (int) j] = spegPtr->si.gridcolor->blue >> 8; 1165 imageR[(int) i + width * (int) (j+k)] = spegPtr->si.gridcolor->red >> 8; 1166 imageG[(int) i + width * (int) (j+k)] = spegPtr->si.gridcolor->green >> 8; 1167 imageB[(int) i + width * (int) (j+k)] = spegPtr->si.gridcolor->blue >> 8; 1168 } 1169 } 1170 } 1171 1172 } else if (spegPtr->si.gridFspacing > 0) { 1173 float i, j; 1174 float dj = (float) ((float) height / (spegPtr->si.topfrequency / 1175 (float) spegPtr->si.gridFspacing)); 1176 1177 for (i = 0.0; i < (float) width; i++) { 1178 for (j = (float) height - dj; j > 0.0; j -= dj) { 1179 imageR[(int) i + width * (int) j] = spegPtr->si.gridcolor->red >> 8; 1180 imageG[(int) i + width * (int) j] = spegPtr->si.gridcolor->green >> 8; 1181 imageB[(int) i + width * (int) j] = spegPtr->si.gridcolor->blue >> 8; 1182 } 1183 } 1184 } else if (spegPtr->si.gridTspacing > 0.0) { 1185 float i, j; 1186 float di = (float) (spegPtr->si.pixpsec * spegPtr->si.gridTspacing); 1187 1188 for (i = di; i < (float) width; i += di) { 1189 for (j = 0.0; j < (float) height; j++) { 1190 imageR[(int) i + width * (int) j] = spegPtr->si.gridcolor->red >> 8; 1191 imageG[(int) i + width * (int) j] = spegPtr->si.gridcolor->green >> 8; 1192 imageB[(int) i + width * (int) j] = spegPtr->si.gridcolor->blue >> 8; 1193 } 1194 } 1195 } 1196 1197 Tcl_AppendResult(interp, "%% SPEG BEGIN\n", (char *) NULL); 1198 1199 sprintf(buffer, "/pix %d string def\n%d %f translate\n", width, 1200 spegPtr->header.x1, Tk_CanvasPsY(canvas,(double)spegPtr->header.y2)); 1201 Tcl_AppendResult(interp, buffer, (char *) NULL); 1202 1203 sprintf(buffer, "%d %d scale\n", width/2, height/2); 1204 Tcl_AppendResult(interp, buffer, (char *) NULL); 1205 1206 sprintf(buffer, "%d %d 8\n", width, height); 1207 Tcl_AppendResult(interp, buffer, (char *) NULL); 1208 1209 sprintf(buffer, "[%d 0 0 %d 0 %d]\n", width, -height, height); 1210 Tcl_AppendResult(interp, buffer, (char *) NULL); 1211 1212 if (noColor) { 1213 Tcl_AppendResult(interp, "{currentfile pix readhexstring pop}\nimage\n", 1214 (char *) NULL); 1215 1216 for (y = 0; y < height; y++) { 1217 for (x = 0; x < width; x++) { 1218 sprintf(buffer, "%.2x", imageR[x + width * y]); 1219 Tcl_AppendResult(interp, buffer, (char *) NULL); 1220 } 1221 Tcl_AppendResult(interp, "\n", (char *) NULL); 1222 } 1223 } else { 1224 Tcl_AppendResult(interp, "{currentfile pix readhexstring pop}\n", 1225 "false 3 colorimage\n", (char *) NULL); 1226 1227 for (y = 0; y < height; y++) { 1228 for (x = 0; x < width; x++) { 1229 sprintf(buffer, "%.2x%.2x%.2x", imageR[x + width * y], 1230 imageG[x + width * y], imageB[x + width * y]); 1231 Tcl_AppendResult(interp, buffer, (char *) NULL); 1232 } 1233 Tcl_AppendResult(interp, "\n", (char *) NULL); 1234 } 1235 } 1236 1237 Tcl_AppendResult(interp, "%% SPEG END\n", (char *) NULL); 1238 1239 ckfree((char *) imageR); 1240 ckfree((char *) imageG); 1241 ckfree((char *) imageB); 1242 1243 return TCL_OK; 1244} 1245 1246#define FFTBUF(i) *(siPtr->frame[(i)>>18] + ((i)&(FRAMESIZE-1))) 1247#define LAGOM 16384.0f 1248 1249static int 1250ComputeSpeg(SnackItemInfo *siPtr, int nfft) 1251{ 1252 int i = 0, j; 1253 float spacing = siPtr->spacing; 1254 int fftlen = siPtr->fftlen; 1255 int winlen = siPtr->winlen; 1256 int fftmax = siPtr->fftmax; 1257 int fftmin = siPtr->fftmin; 1258 float preemph = siPtr->preemph; 1259 int RestartPos = siPtr->RestartPos - siPtr->validStart; 1260 int encoding = siPtr->encoding; 1261 int storeType = siPtr->storeType; 1262 int ret = nfft; 1263 int flag = 0; 1264 float g = 1.0; 1265 SnackLinkedFileInfo info; 1266 1267 if (siPtr->debug > 2) Snack_WriteLogInt(" Enter ComputeSpeg", nfft); 1268 1269 if (storeType != SOUND_IN_MEMORY) { 1270 if (OpenLinkedFile(siPtr->sound, &info) != TCL_OK) { 1271 return(0); 1272 } 1273 } 1274 1275 if (winlen > fftlen) /* should not happen */ 1276 winlen = fftlen; 1277 1278 Snack_InitFFT(fftlen); 1279 Snack_InitWindow(siPtr->hamwin, winlen, fftlen, siPtr->windowType); 1280 1281 siPtr->doneSpeg = 0; 1282 /* siPtr->computing = 1;*/ 1283 1284 while (siPtr->frlen <= ((nfft + siPtr->nfft) * fftlen / 2)) { 1285 if ((siPtr->frame[siPtr->nfrms] = (short *) ckalloc(2*FRAMESIZE)) == NULL) 1286 return 0; 1287 siPtr->frlen += FRAMESIZE; 1288 if (siPtr->debug > 3) { 1289 Snack_WriteLogInt(" Alloced frame", siPtr->nfrms); 1290 } 1291 siPtr->nfrms++; 1292 } 1293 1294 if (siPtr->abmax > 0.0 && siPtr->abmax < LAGOM) { 1295 g = LAGOM / siPtr->abmax; 1296 } 1297 if (encoding == LIN8OFFSET || encoding == LIN8) { 1298 if (g == 1.0 && storeType != SOUND_IN_MEMORY) { 1299 g = 256.0; 1300 } 1301 } 1302 1303 /* if (siPtr->cmdPtr != NULL) { 1304 Snack_ProgressCallback(siPtr->cmdPtr, siPtr->sound->interp, 1305 "Computing spectrogram", 0.0); 1306 }*/ 1307 1308 for (j = 0; j < nfft; j++) { 1309 if ((RestartPos + (int)(j * spacing) - fftlen / 2) >= 0 && 1310 (RestartPos + (int)(j * spacing) + fftlen - winlen / 2 + 1311 siPtr->nchannels) < siPtr->BufPos) { 1312 1313 if (storeType == SOUND_IN_MEMORY) { 1314 if (siPtr->nchannels == 1 || siPtr->channel != -1) { 1315 int p = (RestartPos + (int)(j * spacing) - winlen / 2) * 1316 siPtr->nchannels + siPtr->channel; 1317 1318 for (i = 0; i < fftlen; i++) { 1319 xfft[i] = (float) ((FSAMPLE(siPtr, p + siPtr->nchannels) 1320 - preemph * FSAMPLE(siPtr, p)) * 1321 siPtr->hamwin[i]) * g; 1322 p += siPtr->nchannels; 1323 } 1324 flag = 1; 1325 } else { 1326 int c; 1327 1328 for (i = 0; i < fftlen; i++) { 1329 xfft[i] = 0.0; 1330 } 1331 for (c = 0; c < siPtr->nchannels; c++) { 1332 int p = (RestartPos + (int)(j * spacing) - winlen / 2) * 1333 siPtr->nchannels + c; 1334 1335 for (i = 0; i < fftlen; i++) { 1336 xfft[i] += (float) ((FSAMPLE(siPtr, p + siPtr->nchannels) 1337 - preemph * FSAMPLE(siPtr, p)) 1338 * siPtr->hamwin[i]) * g; 1339 p += siPtr->nchannels; 1340 } 1341 flag = 1; 1342 } 1343 for (i = 0; i < fftlen; i++) { 1344 xfft[i] /= siPtr->nchannels; 1345 } 1346 } 1347 } else { /* storeType != SOUND_IN_MEMORY */ 1348 if (siPtr->nchannels == 1 || siPtr->channel != -1) { 1349 int p = (RestartPos + (int)(j * spacing) - winlen / 2) * 1350 siPtr->nchannels + siPtr->channel; 1351 1352 for (i = 0; i < fftlen; i++) { 1353 xfft[i] = (float) ((GetSample(&info, p + siPtr->nchannels) 1354 - preemph * GetSample(&info, p)) * 1355 siPtr->hamwin[i]) * g; 1356 p += siPtr->nchannels; 1357 } 1358 flag = 1; 1359 } else { 1360 int c; 1361 1362 for (i = 0; i < fftlen; i++) { 1363 xfft[i] = 0.0; 1364 } 1365 for (c = 0; c < siPtr->nchannels; c++) { 1366 int p = (RestartPos + (int)(j * spacing) - winlen / 2) * 1367 siPtr->nchannels + c; 1368 1369 for (i = 0; i < fftlen; i++) { 1370 xfft[i] += (float) ((GetSample(&info, p + siPtr->nchannels) 1371 - preemph * GetSample(&info, p)) 1372 * siPtr->hamwin[i]) * g; 1373 p += siPtr->nchannels; 1374 } 1375 flag = 1; 1376 } 1377 for (i = 0; i < fftlen; i++) { 1378 xfft[i] /= siPtr->nchannels; 1379 } 1380 } 1381 } 1382 } else { 1383 if (flag) ret--; 1384 for (i = 0; i < fftlen; i++) xfft[i] = (float) 0.0; 1385 } 1386 1387 Snack_DBPowerSpectrum(xfft); 1388 1389 for (i = 0; i < fftlen / 2; i++) { 1390 short tmp = (short) (xfft[i] +.5); 1391 int ind = (j + siPtr->nfft) * fftlen / 2 + i; 1392 /* 1393 if (siPtr->debug > 2 && i==0) Snack_WriteLogInt(" in", tmp); 1394 if (siPtr->debug > 2 && i==0) Snack_WriteLogInt(" hm", (int)xfft[i]); 1395 */ 1396#if !defined(WIN) 1397 if (tmp == 0 && (int)xfft[i] < -200) { 1398 tmp = fftmin; 1399 } 1400#endif 1401 FFTBUF(ind) = tmp; 1402 if (tmp < fftmin) fftmin = tmp; 1403 if (tmp > fftmax) fftmax = tmp; 1404 } 1405 /* Tcl_DoOneEvent(TCL_DONT_WAIT);*/ 1406 if (siPtr->doneSpeg) return(-1); 1407 /* if ((siPtr->cmdPtr != NULL) && ((j % 100) == (100-1))) { 1408 Snack_ProgressCallback(siPtr->cmdPtr, siPtr->sound->interp, 1409 "Computing spectrogram", (double) j/nfft); 1410 }*/ 1411 } /* for...*/ 1412 siPtr->doneSpeg = 1; 1413 siPtr->fftmax = fftmax; 1414 siPtr->fftmin = fftmin; 1415 siPtr->nfft += ret; 1416 1417 if (storeType != SOUND_IN_MEMORY) { 1418 CloseLinkedFile(&info); 1419 } 1420 1421 /* if (siPtr->cmdPtr != NULL) { 1422 Snack_ProgressCallback(siPtr->cmdPtr, siPtr->sound->interp, 1423 "Computing spectrogram", 1.0); 1424 } 1425 siPtr->computing = 0;*/ 1426 1427 if (siPtr->debug > 2) { 1428 Snack_WriteLogInt(" Exit ComputeSpeg", siPtr->fftmin); 1429 } 1430 1431 return ret; 1432} 1433 1434#if defined(MAC) || defined(MAC_OSX_TCL) 1435int MacPutPixel(XImage *image, int x, int y, unsigned long pixel) 1436{ 1437 /* 1438 * Define "NBBY" (number of bits per byte) if it's not already defined. 1439 */ 1440 1441#ifndef NBBY 1442# define NBBY 8 1443#endif 1444 1445 unsigned char *destPtr = (unsigned char *)&(image->data[(y * 1446 image->bytes_per_line) + ((x * image->bits_per_pixel) / NBBY)]); 1447 1448 if (image->bits_per_pixel == 32) { 1449 destPtr[0] = 0; 1450 destPtr[1] = (unsigned char) ((pixel >> 16) & 0xff); 1451 destPtr[2] = (unsigned char) ((pixel >> 8) & 0xff); 1452 destPtr[3] = (unsigned char) (pixel & 0xff); 1453 } 1454 return 0; 1455} 1456#endif 1457 1458#define MAX_PIXELS 65536 1459 1460static void 1461DrawSpeg(SnackItemInfo *siPtr, Display* disp, GC gc, int width, int height, 1462 int drawX, int drawW, int fpos) 1463{ 1464 int i, j, len, nCols, xStart = drawX, xEnd, doWidth, bytesPerLine; 1465 short v[NMAX + 1]; 1466 int nbins = siPtr->fftlen / 2; 1467 XImage *ximage; 1468 unsigned char *linePtr, *bytePtr; 1469 unsigned long *pixelmap = siPtr->pixelmap; 1470 unsigned long gridpixel = siPtr->gridcolor->pixel; 1471 int ncolors = siPtr->ncolors; 1472 int depth = siPtr->depth; 1473 1474 if (siPtr->debug > 2) Snack_WriteLogInt(" Enter DrawSpeg", drawW); 1475 1476 if (height == 0) return; 1477 1478 if (siPtr->pixelmap != NULL && siPtr->gridcolor != None) { 1479 siPtr->pixelmap[siPtr->ncolors] = siPtr->gridcolor->pixel; 1480 } 1481 1482 if (siPtr->fftmax == siPtr->fftmin) siPtr->fftmax++; 1483 1484 if (siPtr->nfft >= 0) { 1485 nCols = (MAX_PIXELS + height - 1) / height; 1486 if (nCols < 1) { 1487 nCols = 1; 1488 } 1489 if (nCols > drawW) { 1490 nCols = drawW; 1491 } 1492 1493 ximage = XCreateImage(disp, siPtr->visual, depth, ZPixmap, 0, 1494 (char *) NULL, nCols, height, 32, 0); 1495 if (ximage == NULL) return; 1496#if defined(MAC) || defined(MAC_OSX_TCL) 1497 ximage->f.put_pixel = MacPutPixel; 1498#endif 1499 1500 if (depth >= 24) { 1501 len = (nCols + 3) * height * depth / 6; 1502 } else { 1503 len = (nCols + 3) * height * depth / 8; 1504 } 1505 1506 ximage->data = ckalloc(len); 1507 1508 if (ximage->data == NULL) { 1509 XFree((char *) ximage); 1510 return; 1511 } 1512 bytesPerLine = ((ximage->bits_per_pixel * nCols + 31) >> 3) & ~3; 1513 doWidth = drawW; 1514 1515 for (; doWidth > 0; doWidth -= nCols) { 1516 float xscale = siPtr->xUnderSamp; 1517 int fftmin = siPtr->fftmin; 1518 double offset = siPtr->bright + fftmin; 1519 float k = (float) (siPtr->contrast * siPtr->ncolors / 1520 (siPtr->fftmax - fftmin)); 1521 if (nCols > doWidth) { 1522 nCols = doWidth; 1523 } 1524 xEnd = xStart + nCols; 1525 for (i = xStart; i < xEnd; i++) { 1526 float yscale = ((float)siPtr->topfrequency * nbins / 1527 (siPtr->samprate / 2)) / height; 1528 float fx = xscale * i; 1529 int ix = (int) fx; 1530 float deltax = fx - ix; 1531 int p = (ix + fpos) * nbins; 1532 int q = p + nbins; 1533 1534 if (drawX > 0) { 1535 p = (ix - (int)(xscale * xStart) + fpos) * nbins; 1536 q = p + nbins; 1537 } 1538 1539 if ((p / nbins) < 0 || (p / nbins) >= siPtr->nfft) { 1540 for (j = 0; j < height; j++) { 1541#if !defined(WIN) && !defined(MAC) && !defined(MAC_OSX_TCL) 1542 XPutPixel(ximage, (int) i - xStart, (int) j, pixelmap[0]); 1543#else 1544 if (depth == 8) { 1545 XPutPixel(ximage, (int) i - xStart, (int) j, 0); 1546 } else { 1547 XPutPixel(ximage, (int) i - xStart, (int) j, pixelmap[0]); 1548 } 1549#endif 1550 } 1551 continue; 1552 } 1553 1554 linePtr = (unsigned char *) (ximage->data + i - xStart + bytesPerLine * (height-1)); 1555 1556 bytePtr = linePtr; 1557 1558 if (siPtr->nfft >= width) { /* subsample in x direction */ 1559 for (j = 0; j < nbins; j++) { 1560 v[j] = (short) (k * (FFTBUF(p) - offset)); 1561 p++; 1562 } 1563 } else { /* interpolate in x direction */ 1564 for (j = 0; j < nbins; j++) { 1565 short fftp = FFTBUF(p); 1566 v[j] = (short) (k * ((fftp - offset) + 1567 deltax * (FFTBUF(q) - fftp))); 1568 p++; q++; 1569 } 1570 } 1571 v[nbins] = v[nbins - 1]; 1572 for (j = 0; j < height; j++) { 1573 int c; 1574 float fy = yscale * j; 1575 int iy = (int) fy; 1576 1577 if (height <= nbins) /* subsample in y direction */ 1578 c = v[iy]; 1579 else /* interpolate in y direction */ 1580 c = (int) (v[iy] + (fy - iy) * (v[iy + 1] - v[iy])); 1581 1582 if (c >= ncolors) { 1583 c = ncolors - 1; 1584 } 1585 if (c < 0) { 1586 c = 0; 1587 } 1588 1589 switch (depth) { 1590 case 8: 1591#if !defined(WIN) && !defined(MAC) && !defined(MAC_OSX_TCL) 1592 *bytePtr = (unsigned char) pixelmap[c]; 1593#else 1594 *bytePtr = (unsigned char) c; 1595#endif 1596 break; 1597 1598 default: 1599 XPutPixel(ximage, i - xStart, height - j - 1, pixelmap[c]); 1600 } 1601 bytePtr -= bytesPerLine; 1602 } 1603 } 1604 1605 if ((siPtr->gridFspacing > 0) && (siPtr->gridTspacing > 0.0)) { 1606 float i, j; 1607 float di = (float) siPtr->pixpsec * (float) siPtr->gridTspacing; 1608 float dj = (height / ((float)siPtr->topfrequency / siPtr->gridFspacing)); 1609 int k = 0; 1610 int xleft = width - siPtr->xTot - drawW; 1611 int xcoord; 1612 1613 for (i = xleft + di; i < (float) width; i += di) { 1614 for (k = -5; k <= 5; k++) { 1615 if ((int)(i+k) >= xStart && (int)(i+k) < xEnd) { 1616 1617 xcoord = (int) (i+k) - xStart; 1618 for (j = (float) height - dj; j > 0.0; j -= dj) { 1619#if !defined(WIN) && !defined(MAC) && !defined(MAC_OSX_TCL) 1620 XPutPixel(ximage, xcoord, (int) j, gridpixel); 1621#else 1622 if (depth == 8) { 1623 XPutPixel(ximage, xcoord, (int) j, ncolors); 1624 } else { 1625 XPutPixel(ximage, xcoord, (int) j, gridpixel); 1626 } 1627#endif 1628 } 1629 } 1630 } 1631 if ((int) i >= xStart && (int) i < xEnd) { 1632 for (j = (float) height - dj; j > 0.0; j -= dj) { 1633 for (k = -5; k <= 5; k++) { 1634 if ((int)(j+k) >= 0 && (int)(j+k) < height) { 1635#if !defined(WIN) && !defined(MAC) && !defined(MAC_OSX_TCL) 1636 XPutPixel(ximage, (int) i - xStart, (int) (j+k), gridpixel); 1637#else 1638 if (depth == 8) { 1639 XPutPixel(ximage, (int) i - xStart, (int) (j+k), ncolors); 1640 } else { 1641 XPutPixel(ximage, (int) i - xStart, (int) (j+k),gridpixel); 1642 } 1643#endif 1644 } 1645 } 1646 } 1647 } 1648 } 1649 } else if (siPtr->gridFspacing > 0) { 1650 float i, j; 1651 float dj = (height / ((float)siPtr->topfrequency/siPtr->gridFspacing)); 1652 1653 for (i = 0.0; i < (float) width; i++) { 1654 if (i >= xStart && i < xEnd) { 1655 for (j = (float) height - dj; j > 0.0; j -= dj) { 1656#if !defined(WIN) && !defined(MAC) && !defined(MAC_OSX_TCL) 1657 XPutPixel(ximage, (int) i - xStart, (int) j, gridpixel); 1658#else 1659 if (depth == 8) { 1660 XPutPixel(ximage, (int) i - xStart, (int) j, ncolors); 1661 } else { 1662 XPutPixel(ximage, (int) i - xStart, (int) j, gridpixel); 1663 } 1664#endif 1665 } 1666 } 1667 } 1668 } else if (siPtr->gridTspacing > 0.0) { 1669 float i, j; 1670 float di = (float) siPtr->pixpsec * (float) siPtr->gridTspacing; 1671 int xleft = width - siPtr->xTot - drawW; 1672 1673 for (i = xleft + di; i < (float) width; i += di) { 1674 if (i >= xStart && i < xEnd) { 1675 for (j = 0.0; j < (float) height; j++) { 1676#if !defined(WIN) && !defined(MAC) && !defined(MAC_OSX_TCL) 1677 XPutPixel(ximage, (int) i - xStart, (int) j, gridpixel); 1678#else 1679 if (depth == 8) { 1680 XPutPixel(ximage, (int) i - xStart, (int) j, ncolors); 1681 } else { 1682 XPutPixel(ximage, (int) i - xStart, (int) j, gridpixel); 1683 } 1684#endif 1685 } 1686 } 1687 } 1688 } 1689 TkPutImage(siPtr->pixelmap, siPtr->ncolors + 1, disp, siPtr->pixmap, 1690 gc, ximage, 0, 0, xStart, 0, nCols, height); 1691 xStart = xEnd; 1692 } 1693 ckfree(ximage->data); 1694 XFree((char *) ximage); 1695 } 1696 1697 if (drawX == 0) { 1698 siPtr->xTot = 0; 1699 } else { 1700 siPtr->xTot += drawW; 1701 } 1702 1703 if (siPtr->debug > 2) Snack_WriteLog(" Exit Drawspeg\n"); 1704} 1705 1706static int 1707ParseColorMap(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, 1708 CONST84 char *value, char *recordPtr, int offset) 1709{ 1710 SpectrogramItem *spegPtr = (SpectrogramItem *) recordPtr; 1711 int argc, i; 1712 CONST84 char **argv = NULL; 1713 1714 if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { 1715 Tcl_ResetResult(interp); 1716 Tcl_AppendResult(interp, "bad color map \"", value, 1717 "\": must be list with at least two colors", 1718 (char *) NULL); 1719 return TCL_ERROR; 1720 } 1721 1722 if (argc == 1) { 1723 Tcl_ResetResult(interp); 1724 Tcl_AppendResult(interp, "bad color map \"", value, 1725 "\": must be list with at least two colors", 1726 (char *) NULL); 1727 if (argv != NULL) { 1728 ckfree((char *) argv); 1729 } 1730 return TCL_ERROR; 1731 } 1732 1733 for (i = 0; i < spegPtr->si.ncolors; i++) { 1734 Tk_FreeColor(spegPtr->si.xcolor[i]); 1735 } 1736 1737 if (argc == 0) { 1738 spegPtr->si.ncolors = NDEFCOLS; 1739 } else { 1740 spegPtr->si.ncolors = argc; 1741 } 1742 1743 spegPtr->si.xcolor = (XColor **) ckalloc(spegPtr->si.ncolors * sizeof(XColor*)); 1744 1745 if (spegPtr->si.xcolor == NULL) { 1746 Tcl_ResetResult(interp); 1747 Tcl_AppendResult(interp, "Not enough memory to allocate colormap", NULL); 1748 if (argv != NULL) { 1749 ckfree((char *) argv); 1750 } 1751 return TCL_ERROR; 1752 } 1753 1754 spegPtr->si.pixelmap = (unsigned long *) ckalloc((spegPtr->si.ncolors + 1) * sizeof(unsigned long)); 1755 1756 if (spegPtr->si.pixelmap == NULL) { 1757 ckfree((char *) spegPtr->si.xcolor); 1758 Tcl_ResetResult(interp); 1759 Tcl_AppendResult(interp, "Not enough memory to allocate pixelmap", NULL); 1760 if (argv != NULL) { 1761 ckfree((char *) argv); 1762 } 1763 return TCL_ERROR; 1764 } 1765 1766 if (argc == 0) { 1767 for (i = 0; i < spegPtr->si.ncolors; i++) { 1768 XColor xcol; 1769 1770 xcol.flags = DoRed | DoGreen | DoBlue; 1771 xcol.red = 65535 - (i * 65535 / (spegPtr->si.ncolors - 1)); 1772 xcol.green = 65535 - (i * 65535 / (spegPtr->si.ncolors - 1)); 1773 xcol.blue = 65535 - (i * 65535 / (spegPtr->si.ncolors - 1)); 1774 spegPtr->si.xcolor[i] = Tk_GetColorByValue(Tk_MainWindow(interp), &xcol); 1775 spegPtr->si.pixelmap[i] = spegPtr->si.xcolor[i]->pixel; 1776 } 1777 } else { 1778 for (i = 0; i < spegPtr->si.ncolors; i++) { 1779 spegPtr->si.xcolor[i] = Tk_GetColor(interp, Tk_MainWindow(interp), argv[i]); 1780 if (spegPtr->si.xcolor[i] == NULL) { 1781 ckfree((char *) spegPtr->si.xcolor); 1782 ckfree((char *) spegPtr->si.pixelmap); 1783 Tcl_ResetResult(interp); 1784 Tcl_AppendResult(interp, "unknown color name \"", argv[i], 1785 "\"", (char *) NULL); 1786 if (argv != NULL) { 1787 ckfree((char *) argv); 1788 } 1789 return TCL_ERROR; 1790 } 1791 spegPtr->si.pixelmap[i] = spegPtr->si.xcolor[i]->pixel; 1792 } 1793 } 1794 1795 ckfree((char *) argv); 1796 1797 return TCL_OK; 1798} 1799 1800static char* 1801PrintColorMap(ClientData clientData, Tk_Window tkwin, char *recordPtr, 1802 int offset, Tcl_FreeProc **freeProcPtr) 1803{ 1804 SpectrogramItem *spegPtr = (SpectrogramItem *) recordPtr; 1805 char *buffer; 1806 int i, j = 0; 1807 1808 *freeProcPtr = TCL_DYNAMIC; 1809 buffer = (char *) ckalloc(spegPtr->si.ncolors * 20); 1810 for (i = 0; i < spegPtr->si.ncolors; i++) { 1811 j += (int) sprintf(&buffer[j], "%s ", Tk_NameOfColor(spegPtr->si.xcolor[i])); 1812 } 1813 sprintf(&buffer[j], "\n"); 1814 return buffer; 1815} 1816