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#include <math.h> 27#define USE_OLD_CANVAS /* To keep Tk8.3 happy */ 28#include "tk.h" 29#include "jkCanvItems.h" 30#include <string.h> 31 32/* 33 * Wave item structure 34 */ 35 36typedef struct WaveItem { 37 38 Tk_Item header; 39 Tk_Canvas canvas; 40 double x, y; 41 Tk_Anchor anchor; 42 double *x0; 43 double *y0; 44 double *x1; 45 double *y1; 46 XColor *fg; 47 Pixmap fillStipple; 48 GC gc; 49 char *newSoundName; 50 char *soundName; 51 Sound *sound; 52 int channel; 53 int channelSet; 54 int nchannels; 55 int samprate; 56 int encoding; 57 float **blocks; 58 int bufPos; 59 double limit; 60 int subSample; 61 double pixpsec; 62 int height; 63 int width; 64 int widthSet; 65 int startSmp; 66 int endSmp; 67 int ssmp; 68 int esmp; 69 int zeroLevel; 70 int frame; 71 int id; 72 int mode; 73 int subSampleInt; 74 char *channelStr; 75 int debug; 76 int storeType; 77 char *preCompFile; 78 struct WaveItem *preWI; 79 Sound *preSound; 80 int preCompInvalid; 81 int validStart; 82 char *progressCmd; 83 Tcl_Obj *cmdPtr; 84 Tcl_Interp *interp; 85 int trimstart; 86 float maxv; 87 float minv; 88 int remove; /* remove for 2.1 */ 89 90} WaveItem; 91 92Tk_CustomOption waveTagsOption = { (Tk_OptionParseProc *) NULL, 93 (Tk_OptionPrintProc *) NULL, 94 (ClientData) NULL }; 95 96typedef enum { 97 OPTION_ANCHOR, 98 OPTION_TAGS, 99 OPTION_SOUND, 100 OPTION_HEIGHT, 101 OPTION_WIDTH, 102 OPTION_PIXPSEC, 103 OPTION_START, 104 OPTION_END, 105 OPTION_FILL, 106 OPTION_STIPPLE, 107 OPTION_ZEROLEVEL, 108 OPTION_FRAME, 109 OPTION_LIMIT, 110 OPTION_SUBSAMPLE, 111 OPTION_CHANNEL, 112 OPTION_PRECOMPWAVE, 113 OPTION_PROGRESS, 114 OPTION_TRIMSTART 115} ConfigSpec; 116 117static Tk_ConfigSpec configSpecs[] = { 118 119 {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, 120 "nw", Tk_Offset(WaveItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, 121 122 {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, 123 (char *) NULL, 0, TK_CONFIG_NULL_OK, &waveTagsOption}, 124 125 {TK_CONFIG_STRING, "-sound", (char *) NULL, (char *) NULL, 126 "", Tk_Offset(WaveItem, newSoundName), TK_CONFIG_NULL_OK}, 127 128 {TK_CONFIG_INT, "-height", (char *) NULL, (char *) NULL, 129 "100", Tk_Offset(WaveItem, height), 0}, 130 131 {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, 132 "378", Tk_Offset(WaveItem, widthSet), 0}, 133 134 {TK_CONFIG_DOUBLE, "-pixelspersecond", "pps", (char *) NULL, 135 "250.0", Tk_Offset(WaveItem, pixpsec), 0}, 136 137 {TK_CONFIG_INT, "-start", (char *) NULL, (char *) NULL, 138 "0", Tk_Offset(WaveItem, startSmp), 0}, 139 140 {TK_CONFIG_INT, "-end", (char *) NULL, (char *) NULL, 141 "-1", Tk_Offset(WaveItem, endSmp), 0}, 142 143 {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, 144 "black", Tk_Offset(WaveItem, fg), TK_CONFIG_NULL_OK}, 145 146 {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, 147 (char *) NULL, Tk_Offset(WaveItem, fillStipple), TK_CONFIG_NULL_OK}, 148 149 {TK_CONFIG_BOOLEAN, "-zerolevel", "zerolevel", (char *) NULL, 150 "yes", Tk_Offset(WaveItem, zeroLevel), TK_CONFIG_NULL_OK}, 151 152 {TK_CONFIG_BOOLEAN, "-frame", (char *) NULL, (char *) NULL, 153 "no", Tk_Offset(WaveItem, frame), TK_CONFIG_NULL_OK}, 154 155 {TK_CONFIG_DOUBLE, "-limit", (char *) NULL, (char *) NULL, 156 "-1.0", Tk_Offset(WaveItem, limit), 0}, 157 158 {TK_CONFIG_INT, "-subsample", (char *) NULL, (char *) NULL, 159 "1", Tk_Offset(WaveItem, subSampleInt), TK_CONFIG_NULL_OK}, 160 161 {TK_CONFIG_STRING, "-channel", (char *) NULL, (char *) NULL, 162 "-1", Tk_Offset(WaveItem, channelStr), TK_CONFIG_NULL_OK}, 163 164 {TK_CONFIG_STRING, "-shapefile", (char *) NULL, (char *) NULL, 165 "", Tk_Offset(WaveItem, preCompFile), TK_CONFIG_NULL_OK}, 166 167 {TK_CONFIG_STRING, "-progress", (char *) NULL, (char *) NULL, 168 "", Tk_Offset(WaveItem, progressCmd), TK_CONFIG_NULL_OK}, 169 170 {TK_CONFIG_INT, "-trimstart", (char *) NULL, (char *) NULL, 171 "0", Tk_Offset(WaveItem, trimstart), 0}, 172 173 /* To be removed for 2.1 */ 174 {TK_CONFIG_INT, "-tround", (char *) NULL, (char *) NULL, 175 "0", Tk_Offset(WaveItem, remove), 0}, 176 177 {TK_CONFIG_INT, "-debug", (char *) NULL, (char *) NULL, 178 "0", Tk_Offset(WaveItem, debug), 0}, 179 180 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, 181 (char *) NULL, 0, 0} 182 183}; 184 185/* 186 * Protos 187 */ 188 189 static void ComputeWaveBbox(Tk_Canvas canvas, WaveItem *wavePtr); 190 191 static int ComputeWaveCoords(Tk_Item *itemPtr); 192 193 static int ConfigureWave(Tcl_Interp *interp, Tk_Canvas canvas, 194 Tk_Item *itemPtr, int argc, 195 char **argv, int flags); 196 197 static int CreateWave(Tcl_Interp *interp, Tk_Canvas canvas, 198 struct Tk_Item *itemPtr, 199 int argc, char **argv); 200 201 static void DeleteWave(Tk_Canvas canvas, Tk_Item *itemPtr, 202 Display *display); 203 204 static void DisplayWave(Tk_Canvas canvas, Tk_Item *itemPtr, 205 Display *display, Drawable dst, 206 int x, int y, int width, int height); 207 208 static void ScaleWave(Tk_Canvas canvas, Tk_Item *itemPtr, 209 double originX, double originY, 210 double scaleX, double scaleY); 211 212 static void TranslateWave(Tk_Canvas canvas, Tk_Item *itemPtr, 213 double deltaX, double deltaY); 214 215 static int WaveCoords(Tcl_Interp *interp, Tk_Canvas canvas, 216 Tk_Item *itemPtr, int argc, char **argv); 217 218 static int WaveToArea(Tk_Canvas canvas, Tk_Item *itemPtr, 219 double *rectPtr); 220 221 static double WaveToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, 222 double *coords); 223 224 static int WaveToPS(Tcl_Interp *interp, Tk_Canvas canvas, 225 Tk_Item *itemPtr, int prepass); 226 227/* 228 * Wave item type 229 */ 230 231Tk_ItemType snackWaveType = { 232 "waveform", 233 sizeof(WaveItem), 234 CreateWave, 235 configSpecs, 236 ConfigureWave, 237 WaveCoords, 238 DeleteWave, 239 DisplayWave, 240 0, 241 WaveToPoint, 242 WaveToArea, 243 WaveToPS, 244 ScaleWave, 245 TranslateWave, 246 (Tk_ItemIndexProc *) NULL, 247 (Tk_ItemCursorProc *) NULL, 248 (Tk_ItemSelectionProc *) NULL, 249 (Tk_ItemInsertProc *) NULL, 250 (Tk_ItemDCharsProc *) NULL, 251 (Tk_ItemType *) NULL 252}; 253 254static int 255CreateWave(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, 256 int argc, char **argv) 257{ 258 WaveItem *wavePtr = (WaveItem *) itemPtr; 259 260 if (argc < 2) { 261 Tcl_AppendResult(interp, "wrong # args: should be \"", 262 Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", 263 itemPtr->typePtr->name, " x y ?opts?\"", (char *) NULL); 264 return TCL_ERROR; 265 } 266 267 wavePtr->canvas = canvas; 268 wavePtr->anchor = TK_ANCHOR_NW; 269 wavePtr->x0 = NULL; 270 wavePtr->y0 = NULL; 271 wavePtr->x1 = NULL; 272 wavePtr->y1 = NULL; 273 wavePtr->fg = None; 274 wavePtr->fillStipple = None; 275 wavePtr->gc = None; 276 wavePtr->newSoundName = NULL; 277 wavePtr->soundName = NULL; 278 wavePtr->sound = NULL; 279 wavePtr->pixpsec = 250.0; 280 wavePtr->height = 100; 281 wavePtr->width = -1; 282 wavePtr->widthSet = 378; 283 wavePtr->startSmp = 0; 284 wavePtr->endSmp = -1; 285 wavePtr->ssmp = 0; 286 wavePtr->esmp = -1; 287 wavePtr->id = 0; 288 wavePtr->mode = CONF_WIDTH; 289 wavePtr->zeroLevel = 1; 290 wavePtr->frame = 0; 291 wavePtr->channelStr = NULL; 292 wavePtr->channel = -1; 293 wavePtr->channelSet = -1; 294 wavePtr->nchannels = 1; 295 wavePtr->samprate = 16000; 296 wavePtr->encoding = LIN16; 297 wavePtr->bufPos = 0; 298 wavePtr->limit = -1.0; 299 wavePtr->subSampleInt = 1; 300 wavePtr->subSample = 1; 301 wavePtr->preCompFile = NULL; 302 wavePtr->preSound = NULL; 303 wavePtr->preWI = NULL; 304 wavePtr->preCompInvalid = 0; 305 wavePtr->validStart = 0; 306 wavePtr->progressCmd = NULL; 307 wavePtr->cmdPtr = NULL; 308 wavePtr->interp = interp; 309 wavePtr->trimstart = 0; 310 wavePtr->maxv = 0.0f; 311 wavePtr->minv = 0.0f; 312 wavePtr->debug = 0; 313 wavePtr->x = 0; 314 wavePtr->y = 0; 315 316 if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &wavePtr->x) != TCL_OK) || 317 (Tk_CanvasGetCoord(interp, canvas, argv[1], &wavePtr->y) != TCL_OK)) 318 return TCL_ERROR; 319 320 if (ConfigureWave(interp, canvas, itemPtr, argc-2, argv+2, 0) == TCL_OK) 321 return TCL_OK; 322 323 DeleteWave(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); 324 return TCL_ERROR; 325} 326 327static void 328WaveMaxMin(WaveItem *wavePtr, SnackLinkedFileInfo *info, int start, int stop, 329 float *maxi, float *mini) 330{ 331 int i, j, allFlag = 0; 332 float maxval = -8388608.0, minval = 8388607.0, val; 333 int nchan = wavePtr->nchannels, chan = wavePtr->channel; 334 int inc = nchan * wavePtr->subSample; 335 336 if (start < 0 || stop > wavePtr->bufPos - 1 || stop == 0 || 337 (wavePtr->blocks[0] == NULL && wavePtr->storeType == SOUND_IN_MEMORY)) { 338 if (wavePtr->encoding == LIN8OFFSET) { 339 *maxi = 128.0; 340 *mini = 128.0; 341 } else { 342 *maxi = 0.0; 343 *mini = 0.0; 344 } 345 return; 346 } 347 if (chan == -1) { 348 allFlag = 1; 349 chan = 0; 350 } 351 352 start = start * wavePtr->nchannels + chan; 353 stop = stop * wavePtr->nchannels + chan + wavePtr->nchannels - 1; 354 355 for (i = start; i <= stop; i += inc) { 356 if (wavePtr->storeType == SOUND_IN_MEMORY) { 357 val = FSAMPLE(wavePtr, i); 358 if (allFlag) { 359 for (j = 1; j < nchan; j++) { 360 val += FSAMPLE(wavePtr, i + j); 361 } 362 val = val / nchan; 363 } 364 } else { 365 val = GetSample(info, i); 366 if (allFlag) { 367 for (j = 1; j < nchan; j++) { 368 val += GetSample(info, i + j); 369 } 370 val = val / nchan; 371 } 372 } 373 if (val > maxval) { 374 maxval = val; 375 } 376 if (val < minval) { 377 minval = val; 378 } 379 } 380 if (wavePtr->limit > 0.0) { 381 if (maxval > wavePtr->limit) { 382 maxval = (float) wavePtr->limit; 383 } 384 if (minval < -wavePtr->limit) { 385 minval = (float) -wavePtr->limit; 386 } 387 } 388 *maxi = maxval; 389 *mini = minval; 390} 391 392static int 393WaveCoords(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, 394 char **argv) 395{ 396 WaveItem *wPtr = (WaveItem *) itemPtr; 397 char xc[TCL_DOUBLE_SPACE], yc[TCL_DOUBLE_SPACE]; 398 399 if (argc == 0) { 400 Tcl_PrintDouble(interp, wPtr->x, xc); 401 Tcl_PrintDouble(interp, wPtr->y, yc); 402 Tcl_AppendResult(interp, xc, " ", yc, (char *) NULL); 403 } else if (argc == 2) { 404 if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &wPtr->x) != TCL_OK) || 405 (Tk_CanvasGetCoord(interp, canvas, argv[1], &wPtr->y) != TCL_OK)) { 406 return TCL_ERROR; 407 } 408 ComputeWaveBbox(canvas, wPtr); 409 } else { 410 char buf[80]; 411 412 sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc); 413 Tcl_SetResult(interp, buf, TCL_VOLATILE); 414 415 return TCL_ERROR; 416 } 417 418 return TCL_OK; 419} 420 421/*#define WIDEWAVE 100000*/ 422 423static int 424ComputeWaveCoords(Tk_Item *itemPtr) 425{ 426 WaveItem *wavePtr = (WaveItem *) itemPtr; 427 int i = 0; 428 float maxv, minv, abmax; 429 int yh = wavePtr->height / 2; 430 int nPoints = wavePtr->width; 431 SnackLinkedFileInfo info; 432 Tcl_Interp *interp; 433 int usePre = 0; 434 435 if (wavePtr->debug > 1) Snack_WriteLog(" Enter ComputeWaveCoords\n"); 436 437 if (wavePtr->x0 != NULL) { 438 ckfree((char *) wavePtr->x0); 439 } 440 if (wavePtr->y0 != NULL) { 441 ckfree((char *) wavePtr->y0); 442 } 443 if (wavePtr->x1 != NULL) { 444 ckfree((char *) wavePtr->x1); 445 } 446 if (wavePtr->y1 != NULL) { 447 ckfree((char *) wavePtr->y1); 448 } 449 wavePtr->x0 = (double *) ckalloc(sizeof(double) * nPoints); 450 wavePtr->y0 = (double *) ckalloc(sizeof(double) * nPoints); 451 wavePtr->x1 = (double *) ckalloc(sizeof(double) * nPoints); 452 wavePtr->y1 = (double *) ckalloc(sizeof(double) * nPoints); 453 454 if (wavePtr->sound == NULL) { 455 for (i = 0; i < nPoints; i++) { 456 wavePtr->x0[i] = (double) i; 457 wavePtr->y0[i] = (double) yh; 458 wavePtr->x1[i] = (double) i; 459 wavePtr->y1[i] = (double) yh; 460 } 461 return TCL_OK; 462 } 463 464 maxv = wavePtr->sound->maxsamp; 465 minv = wavePtr->sound->minsamp; 466 abmax = wavePtr->sound->abmax; 467 interp = wavePtr->sound->interp; 468 469 if (wavePtr->preCompFile != NULL && wavePtr->sound->readStatus != READ) { 470 char *type = NULL; 471 472 if (wavePtr->preSound != NULL) { 473 wavePtr->preSound->fcname = NULL; 474 Snack_DeleteSound(wavePtr->preSound); 475 } 476 wavePtr->preSound = Snack_NewSound(200, LIN8, wavePtr->sound->nchannels); 477 if (wavePtr->preSound != NULL) { 478 wavePtr->preSound->fcname = wavePtr->preCompFile; 479 type = LoadSound(wavePtr->preSound, interp, NULL, 0, -1); 480 if (wavePtr->preWI != NULL) ckfree((char *)wavePtr->preWI); 481 wavePtr->preWI = (WaveItem *) ckalloc(sizeof(WaveItem)); 482 if (wavePtr->preWI != NULL) { 483 wavePtr->preWI->nchannels = wavePtr->preSound->nchannels; 484 wavePtr->preWI->channel = 0; 485 wavePtr->preWI->subSample = 1; 486 wavePtr->preWI->bufPos = wavePtr->preSound->length; 487 wavePtr->preWI->blocks = wavePtr->preSound->blocks; 488 wavePtr->preWI->storeType = SOUND_IN_MEMORY; 489 wavePtr->preWI->encoding = LIN8; 490 wavePtr->preWI->limit = wavePtr->limit; 491 } 492 } 493 494 if ((type == NULL || wavePtr->preCompInvalid) && wavePtr->preSound!=NULL) { 495 496 /* Compute and store wave */ 497 498 int nStore = (int) (200.0 * wavePtr->sound->length 499 / wavePtr->sound->samprate); 500 int j; 501 int tmp = wavePtr->channel; 502 503 maxv = 0.0f; 504 minv = 0.0f; 505 if (wavePtr->debug > 2) Snack_WriteLog(" Saving computed waveform\n"); 506 wavePtr->preCompInvalid = 0; 507 Snack_ResizeSoundStorage(wavePtr->preSound, nStore); 508 wavePtr->preSound->length = nStore; 509 if (wavePtr->cmdPtr != NULL) { 510 Snack_ProgressCallback(wavePtr->cmdPtr, interp, 511 "Computing waveform", 0.0); 512 } 513 514 if (wavePtr->storeType != SOUND_IN_MEMORY) { 515 if (OpenLinkedFile(wavePtr->sound, &info) != TCL_OK) { 516 for (i = 0; i < nPoints; i++) { 517 wavePtr->x0[i] = (double) i; 518 wavePtr->y0[i] = (double) yh; 519 wavePtr->x1[i] = (double) i; 520 wavePtr->y1[i] = (double) yh; 521 } 522 if (wavePtr->cmdPtr != NULL) { 523 Snack_ProgressCallback(wavePtr->cmdPtr, interp, 524 "Computing waveform", 1.0); 525 } 526 return TCL_OK; 527 } 528 } 529 for (i = 0; i < nStore / 2; i++) { 530 for (j = 0; j < wavePtr->sound->nchannels; j++) { 531 float fraq = (float) wavePtr->sound->length / (nStore / 2); 532 int start = (int) (i * fraq); 533 int stop = (int) ((i+1) * fraq); 534 float wtop, wbot; 535 536 wavePtr->channel = j; 537 WaveMaxMin(wavePtr, &info, start, stop, &wtop, &wbot); 538 539 if (maxv < wtop) maxv = wtop; 540 if (minv > wbot) minv = wbot; 541 542 switch (wavePtr->encoding) { 543 case LIN16: 544 case MULAW: 545 case ALAW: 546 wtop = wtop / 256.0f; 547 wbot = wbot / 256.0f; 548 break; 549 case LIN24: 550 wtop = wtop / 65536.0f; 551 wbot = wbot / 65536.0f; 552 break; 553 case LIN32: 554 wtop = wtop / 16777216.0f; 555 wbot = wbot / 16777216.0f; 556 break; 557 case SNACK_FLOAT: 558 wtop = (wtop / abmax) * 128.0f; 559 wbot = (wbot / abmax) * 128.0f; 560 break; 561 case LIN8OFFSET: 562 wtop -= 128.0f; 563 wbot -= 128.0f; 564 break; 565 case LIN8: 566 break; 567 } 568 Snack_SetSample(wavePtr->preSound, j, i*2, (char) wtop); 569 Snack_SetSample(wavePtr->preSound, j, i*2+1, (char) wbot); 570 if (j == 0 && (wavePtr->cmdPtr != NULL) && ((i % 1000) == 999)) { 571 int res = Snack_ProgressCallback(wavePtr->cmdPtr, interp, 572 "Computing waveform", (double) i/(nStore/2)); 573 if (res != TCL_OK) { 574 if (wavePtr->debug > 2) { 575 Snack_WriteLog(" Aborting ComputeWaveCoords\n"); 576 } 577 for (;i < nStore / 2; i++) { 578 for (j = 0; j < wavePtr->sound->nchannels; j++) { 579 Snack_SetSample(wavePtr->preSound, j, i*2, (char) 0); 580 Snack_SetSample(wavePtr->preSound, j, i*2+1, (char) 0); 581 } 582 } 583 break; 584 } 585 } 586 } 587 } 588 if (wavePtr->cmdPtr != NULL) { 589 Snack_ProgressCallback(wavePtr->cmdPtr, interp, 590 "Computing waveform", 1.0); 591 } 592 if (SaveSound(wavePtr->preSound, interp, wavePtr->preCompFile, NULL, 593 0, NULL, 0, wavePtr->preSound->length, AIFF_STRING) == 594 TCL_ERROR) { 595 if (wavePtr->debug > 2) Snack_WriteLog(" Failed saving waveform\n"); 596 wavePtr->preCompFile = NULL; 597 } 598 wavePtr->preWI->bufPos = wavePtr->preSound->length; 599 wavePtr->preWI->blocks = wavePtr->preSound->blocks; 600 if (wavePtr->storeType != SOUND_IN_MEMORY) { 601 CloseLinkedFile(&info); 602 } 603 wavePtr->channel = tmp; 604 } 605 606 if (wavePtr->preSound != NULL && wavePtr->preWI != NULL) { 607 608 /* Use precomputed wave */ 609 610 float left = ((float) wavePtr->ssmp / wavePtr->sound->length) * 611 wavePtr->preSound->length; 612 float right = ((float) wavePtr->esmp / wavePtr->sound->length) * 613 wavePtr->preSound->length; 614 float fraq = (right - left) / (nPoints * 2); 615 616 if (fraq > 1.0) { 617 usePre = 1; 618 switch (wavePtr->encoding) { 619 case LIN16: 620 case MULAW: 621 case ALAW: 622 maxv = maxv / 256.0f; 623 minv = minv / 256.0f; 624 break; 625 case LIN24: 626 maxv = maxv / 65536.0f; 627 minv = minv / 65536.0f; 628 break; 629 case LIN32: 630 maxv = maxv / 16777216.0f; 631 minv = minv / 16777216.0f; 632 break; 633 case SNACK_FLOAT: 634 maxv = (maxv / abmax) * 128.0f; 635 minv = (minv / abmax) * 128.0f; 636 break; 637 case LIN8OFFSET: 638 maxv -= 128.0f; 639 minv -= 128.0f; 640 break; 641 case LIN8: 642 break; 643 } 644 645 if (wavePtr->debug > 2) { 646 Snack_WriteLog(" Using precomputed waveform\n"); 647 } 648 649 wavePtr->preWI->channel = wavePtr->channel; 650 for (i = 0; i < nPoints; i++) { 651 int start = (int) (left + 2*(i * fraq)); 652 int stop = (int) (left + 2*(i+1)*fraq); 653 float wtop, wbot; 654 655 WaveMaxMin(wavePtr->preWI, NULL, start, stop, &wtop, &wbot); 656 657 if (maxv < wtop) maxv = wtop; 658 if (minv > wbot) minv = wbot; 659 660 wavePtr->x0[i] = i; 661 wavePtr->x1[i] = i; 662 if (i > 0 && wavePtr->y1[i-1] <= wtop) { 663 wavePtr->y0[i] = wtop; 664 wavePtr->y1[i] = wbot; 665 } else { 666 wavePtr->y0[i] = wbot; 667 wavePtr->y1[i] = wtop; 668 } 669 } 670 671 if (wavePtr->encoding == LIN8OFFSET) { 672 maxv += 128.0f; 673 minv += 128.0f; 674 } 675 } else { 676 usePre = 0; 677 } 678 } 679 } 680 681 if (!usePre) { 682 683 if (wavePtr->debug > 2) { 684 Snack_WriteLog(" Default waveform computation\n"); 685 } 686 687 if (wavePtr->storeType != SOUND_IN_MEMORY) { 688 if (OpenLinkedFile(wavePtr->sound, &info) != TCL_OK) { 689 for (i = 0; i < nPoints; i++) { 690 wavePtr->x0[i] = (double) i; 691 wavePtr->y0[i] = (double) yh; 692 wavePtr->x1[i] = (double) i; 693 wavePtr->y1[i] = (double) yh; 694 } 695 return TCL_OK; 696 } 697 } 698 699 for (i = 0; i < nPoints; i++) { 700 float fraq = (float) (wavePtr->esmp - wavePtr->ssmp) / nPoints; 701 int start = wavePtr->ssmp + (int) (i * fraq) - wavePtr->validStart; 702 int stop = wavePtr->ssmp + (int) ((i+1) * fraq) - wavePtr->validStart; 703 float wtop, wbot; 704 705 if (wavePtr->trimstart == 1) { 706 start = (int)(wavePtr->subSample*ceil((float)start/wavePtr->subSample)); 707 } 708 709 WaveMaxMin(wavePtr, &info, start, stop, &wtop, &wbot); 710 711 if (maxv < wtop) maxv = wtop; 712 if (minv > wbot) minv = wbot; 713 714 if (wavePtr->encoding == LIN8OFFSET) { 715 wtop -= 128.0f; 716 wbot -= 128.0f; 717 } 718 719 wavePtr->x0[i] = i; 720 wavePtr->x1[i] = i; 721 if (i > 0 && wavePtr->y1[i-1] <= wtop) { 722 wavePtr->y0[i] = wtop; 723 wavePtr->y1[i] = wbot; 724 } else { 725 wavePtr->y0[i] = wbot; 726 wavePtr->y1[i] = wtop; 727 } 728 } 729 if (wavePtr->storeType != SOUND_IN_MEMORY) { 730 CloseLinkedFile(&info); 731 } 732 } 733 734 if (maxv > wavePtr->sound->maxsamp) { 735 wavePtr->sound->maxsamp = maxv; 736 } 737 if (minv < wavePtr->sound->minsamp) { 738 wavePtr->sound->minsamp = minv; 739 } 740 741 if (wavePtr->limit > 0) { 742 maxv = (float) wavePtr->limit; 743 minv = (float) -wavePtr->limit; 744 } 745 if (wavePtr->encoding == LIN8OFFSET) { 746 maxv -= 128.0f; 747 minv -= 128.0f; 748 } 749 750 wavePtr->maxv = maxv; 751 wavePtr->minv = minv; 752 753 ComputeWaveBbox(wavePtr->canvas, wavePtr); 754 755 if (usePre) { 756 switch (wavePtr->encoding) { 757 case LIN16: 758 case MULAW: 759 case ALAW: 760 maxv = maxv * 256.0f; 761 minv = minv * 256.0f; 762 break; 763 case LIN24: 764 maxv = maxv * 65536.0f; 765 minv = minv * 65536.0f; 766 break; 767 case LIN32: 768 maxv = maxv / 16777216.0f; 769 minv = minv / 16777216.0f; 770 break; 771 case SNACK_FLOAT: 772 maxv = maxv / 128.0f; 773 minv = minv / 128.0f; 774 break; 775 case LIN8OFFSET: 776 maxv += 128.0f; 777 minv += 128.0f; 778 break; 779 case LIN8: 780 break; 781 } 782 if (maxv > wavePtr->sound->maxsamp) { 783 wavePtr->sound->maxsamp = maxv; 784 } 785 if (minv < wavePtr->sound->minsamp) { 786 wavePtr->sound->minsamp = minv; 787 } 788 } 789 790 if (wavePtr->debug > 1) Snack_WriteLog(" Exit ComputeWaveCoords\n"); 791 792 return TCL_OK; 793} 794 795#define NSAMPLES 100000 796 797static void 798UpdateWave(ClientData clientData, int flag) 799{ 800 WaveItem *wavePtr = (WaveItem *) clientData; 801 Sound *s = wavePtr->sound; 802 803 if (wavePtr->debug > 1) Snack_WriteLogInt(" Enter UpdateWave", flag); 804 805 if (wavePtr->canvas == NULL || wavePtr->sound == NULL) return; 806 807 if (flag == SNACK_DESTROY_SOUND) { 808 wavePtr->sound = NULL; 809 if (wavePtr->id) Snack_RemoveCallback(s, wavePtr->id); 810 wavePtr->id = 0; 811 return; 812 } 813 814 Tk_CanvasEventuallyRedraw(wavePtr->canvas, 815 wavePtr->header.x1, wavePtr->header.y1, 816 wavePtr->header.x2, wavePtr->header.y2); 817 818 wavePtr->blocks = s->blocks; 819 wavePtr->bufPos = s->length; 820 wavePtr->storeType = s->storeType; 821 822 if ((flag == SNACK_MORE_SOUND) || (wavePtr->endSmp < 0)) { 823 wavePtr->esmp = wavePtr->bufPos - 1; 824 } 825 826 if (wavePtr->esmp > wavePtr->bufPos - 1) 827 wavePtr->esmp = wavePtr->bufPos - 1; 828 829 if (wavePtr->endSmp > 0) 830 wavePtr->esmp = wavePtr->endSmp; 831 832 if (wavePtr->endSmp > wavePtr->bufPos - 1) 833 wavePtr->esmp = wavePtr->bufPos - 1; 834 835 wavePtr->ssmp = wavePtr->startSmp; 836 837 if (wavePtr->ssmp > wavePtr->esmp) 838 wavePtr->ssmp = wavePtr->esmp; 839 840 wavePtr->samprate = s->samprate; 841 wavePtr->encoding = s->encoding; 842 wavePtr->nchannels = s->nchannels; 843 844 wavePtr->channel = wavePtr->channelSet; 845 if (wavePtr->nchannels == 1) { 846 wavePtr->channel = 0; 847 } 848 849 if (wavePtr->mode == CONF_WIDTH) { 850 if (wavePtr->esmp != wavePtr->ssmp) { 851 wavePtr->pixpsec = (double) wavePtr->width * wavePtr->samprate / 852 (wavePtr->esmp - wavePtr->ssmp); 853 } 854 } 855 else if (wavePtr->mode == CONF_PPS) { 856 857 wavePtr->width = (int)((wavePtr->esmp - wavePtr->ssmp) * 858 wavePtr->pixpsec / wavePtr->samprate/* + 0.5*/); 859 } 860 else if (wavePtr->mode == CONF_WIDTH_PPS) { 861 wavePtr->ssmp = (int) (wavePtr->esmp - wavePtr->width * 862 wavePtr->samprate / wavePtr->pixpsec); 863 } 864 865 if (wavePtr->subSampleInt == 0) { 866 if (wavePtr->esmp - wavePtr->ssmp > NSAMPLES) { 867 wavePtr->subSample = (wavePtr->esmp - wavePtr->ssmp) / NSAMPLES; 868 } else { 869 wavePtr->subSample = 1; 870 } 871 } else { 872 wavePtr->subSample = wavePtr->subSampleInt; 873 } 874 875 wavePtr->preCompInvalid = 1; 876 wavePtr->validStart = s->validStart; 877 878 if (ComputeWaveCoords((Tk_Item *)wavePtr) != TCL_OK) { 879 return; 880 } 881 Tk_CanvasEventuallyRedraw(wavePtr->canvas, 882 wavePtr->header.x1, wavePtr->header.y1, 883 wavePtr->header.x2, wavePtr->header.y2); 884 885 if (wavePtr->debug > 1) { 886 Snack_WriteLogInt(" Exit UpdateWave", wavePtr->width); 887 } 888} 889 890static int 891ConfigureWave(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, 892 int argc, char **argv, int flags) 893{ 894 WaveItem *wavePtr = (WaveItem *) itemPtr; 895 Sound *s = wavePtr->sound; 896 Tk_Window tkwin = Tk_CanvasTkwin(canvas); 897 XGCValues gcValues; 898 GC newGC; 899 unsigned long mask; 900 int doCompute = 0, oldMode; 901 int i, j; 902 903 if (argc == 0) return TCL_OK; 904 905 if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, 906 (CONST84 char **)argv, 907 (char *) wavePtr, flags) != TCL_OK) return TCL_ERROR; 908 909 if (wavePtr->debug > 1) Snack_WriteLog(" Enter ConfigureWave\n"); 910 911 for (i = 0; configSpecs[i].type != TK_CONFIG_END; i++) { 912 for (j = 0; j < argc; j += 2) { 913 if (strncmp(argv[j], configSpecs[i].argvName, strlen(argv[j])) == 0) { 914 configSpecs[i].specFlags |= TK_CONFIG_OPTION_SPECIFIED; 915 break; 916 } 917 } 918 } 919 920#if defined(MAC) 921 for (i = 0; i < argc; i++) { 922 if (strncmp(argv[i], "-anchor", strlen(argv[i])) == 0) { 923 i++; 924 if (strcmp(argv[i], "ne") == 0) { 925 wavePtr->anchor = 1; 926 } else if (strcmp(argv[i], "nw") == 0) { 927 wavePtr->anchor = 7; 928 } else if (strcmp(argv[i], "n") == 0) { 929 wavePtr->anchor = 0; 930 } else if (strcmp(argv[i], "e") == 0) { 931 wavePtr->anchor = 2; 932 } else if (strcmp(argv[i], "se") == 0) { 933 wavePtr->anchor = 3; 934 } else if (strcmp(argv[i], "sw") == 0) { 935 wavePtr->anchor = 5; 936 } else if (strcmp(argv[i], "s") == 0) { 937 wavePtr->anchor = 4; 938 } else if (strcmp(argv[i], "w") == 0) { 939 wavePtr->anchor = 6; 940 } else if (strncmp(argv[i], "center", strlen(argv[i])) == 0) { 941 wavePtr->anchor = 8; 942 } 943 break; 944 } 945 } 946#endif 947 948 if (OptSpecified(OPTION_SOUND)) { 949 if (wavePtr->newSoundName == NULL) { 950 wavePtr->sound = NULL; 951 if (wavePtr->id) Snack_RemoveCallback(s, wavePtr->id); 952 wavePtr->id = 0; 953 } else { 954 if ((s = Snack_GetSound(interp, wavePtr->newSoundName)) == NULL) { 955 return TCL_ERROR; 956 } 957 if (s->storeType == SOUND_IN_CHANNEL) { 958 Tcl_AppendResult(interp, wavePtr->newSoundName, 959 " can not be linked to a channel", (char *) NULL); 960 return TCL_ERROR; 961 } 962 if (s->storeType == SOUND_IN_FILE) { 963 s->itemRefCnt++; 964 } 965 wavePtr->sound = s; 966 if (wavePtr->soundName == NULL) { 967 wavePtr->soundName = ckalloc(strlen(wavePtr->newSoundName)+1); 968 strcpy(wavePtr->soundName, wavePtr->newSoundName); 969 } 970 if (strcmp(wavePtr->soundName, wavePtr->newSoundName) != 0) { 971 Sound *t = Snack_GetSound(interp, wavePtr->soundName); 972 ckfree(wavePtr->soundName); 973 wavePtr->soundName = ckalloc(strlen(wavePtr->newSoundName)+1); 974 strcpy(wavePtr->soundName, wavePtr->newSoundName); 975 wavePtr->width = 0; 976 wavePtr->ssmp = 0; 977 wavePtr->esmp = -1; 978 Snack_RemoveCallback(t, wavePtr->id); 979 wavePtr->id = 0; 980 } 981 982 if (!wavePtr->id) 983 wavePtr->id = Snack_AddCallback(s, UpdateWave, (int *)wavePtr); 984 985 wavePtr->blocks = s->blocks; 986 wavePtr->bufPos = s->length; 987 wavePtr->samprate = s->samprate; 988 wavePtr->encoding = s->encoding; 989 wavePtr->nchannels = s->nchannels; 990 wavePtr->storeType = s->storeType; 991 } 992 doCompute = 1; 993 } 994 wavePtr->esmp = wavePtr->endSmp; 995 996 if (wavePtr->endSmp < 0) 997 wavePtr->esmp = wavePtr->bufPos - 1; 998 999 if (wavePtr->endSmp > wavePtr->bufPos - 1) 1000 wavePtr->esmp = wavePtr->bufPos - 1; 1001 1002 if (wavePtr->startSmp > wavePtr->endSmp && wavePtr->endSmp >= 0) 1003 wavePtr->startSmp = wavePtr->endSmp; 1004 1005 if (wavePtr->startSmp < 0) 1006 wavePtr->startSmp = 0; 1007 1008 wavePtr->ssmp = wavePtr->startSmp; 1009 1010 if (wavePtr->ssmp > wavePtr->esmp) 1011 wavePtr->ssmp = wavePtr->esmp; 1012 1013 if (OptSpecified(OPTION_START)) { 1014 doCompute = 1; 1015 } 1016 1017 if (OptSpecified(OPTION_END)) { 1018 doCompute = 1; 1019 } 1020 1021 if (OptSpecified(OPTION_LIMIT)) { 1022 doCompute = 1; 1023 } 1024 1025 if (OptSpecified(OPTION_SUBSAMPLE)) { 1026 doCompute = 1; 1027 } 1028 1029 oldMode = wavePtr->mode; 1030 if (OptSpecified(OPTION_PIXPSEC) && OptSpecified(OPTION_WIDTH)) { 1031 wavePtr->mode = CONF_WIDTH_PPS; 1032 doCompute = 1; 1033 } 1034 else if (OptSpecified(OPTION_PIXPSEC)) { 1035 wavePtr->mode = CONF_PPS; 1036 doCompute = 1; 1037 } 1038 else if (OptSpecified(OPTION_WIDTH)) { 1039 wavePtr->mode = CONF_WIDTH; 1040 } 1041 1042 if (oldMode != wavePtr->mode) { 1043 doCompute = 1; 1044 } 1045 1046 if (wavePtr->width != wavePtr->widthSet) { 1047 wavePtr->width = wavePtr->widthSet; 1048 doCompute = 1; 1049 } 1050 1051 if (wavePtr->mode == CONF_WIDTH_PPS) { 1052 if (OptSpecified(OPTION_END) && !OptSpecified(OPTION_START)) { 1053 wavePtr->ssmp = (int) (wavePtr->esmp - wavePtr->width * 1054 wavePtr->samprate / wavePtr->pixpsec); 1055 } else { 1056 wavePtr->esmp = (int) (wavePtr->ssmp + wavePtr->width * 1057 wavePtr->samprate / wavePtr->pixpsec); 1058 } 1059 } 1060 else if (wavePtr->mode == CONF_PPS) { 1061 wavePtr->width = (int)((wavePtr->esmp - wavePtr->ssmp) * 1062 wavePtr->pixpsec / wavePtr->samprate/* + 0.5*/); 1063 } 1064 else if (wavePtr->mode == CONF_WIDTH) { 1065 if (wavePtr->esmp != wavePtr->ssmp) { 1066 wavePtr->pixpsec = (double) wavePtr->width * wavePtr->samprate / 1067 (wavePtr->esmp - wavePtr->ssmp); 1068 } 1069 } 1070 1071 if (OptSpecified(OPTION_PRECOMPWAVE)) { 1072 wavePtr->preCompInvalid = 0; 1073 doCompute = 1; 1074 } 1075 1076 if (OptSpecified(OPTION_CHANNEL)) { 1077 if (GetChannel(interp, wavePtr->channelStr, wavePtr->nchannels, 1078 &wavePtr->channelSet) != TCL_OK) { 1079 return TCL_ERROR; 1080 } 1081 doCompute = 1; 1082 } 1083 wavePtr->channel = wavePtr->channelSet; 1084 if (wavePtr->nchannels == 1) { 1085 wavePtr->channel = 0; 1086 } 1087 1088 if (OptSpecified(OPTION_PROGRESS)) { 1089 if (wavePtr->progressCmd != NULL) { 1090 wavePtr->cmdPtr = Tcl_NewStringObj(wavePtr->progressCmd, -1); 1091 Tcl_IncrRefCount(wavePtr->cmdPtr); 1092 } else { 1093 if (wavePtr->cmdPtr != NULL) { 1094 Tcl_DecrRefCount(wavePtr->cmdPtr); 1095 wavePtr->cmdPtr = NULL; 1096 } 1097 } 1098 } 1099 1100 if (wavePtr->subSampleInt == 0) { 1101 if (wavePtr->esmp - wavePtr->ssmp > NSAMPLES) { 1102 wavePtr->subSample = (wavePtr->esmp - wavePtr->ssmp) / NSAMPLES; 1103 } else { 1104 wavePtr->subSample = 1; 1105 } 1106 } else { 1107 wavePtr->subSample = wavePtr->subSampleInt; 1108 } 1109 1110 if (wavePtr->trimstart == 1 && wavePtr->width > 0) { 1111 int len = wavePtr->esmp - wavePtr->ssmp; 1112 double fraq = (double) len / wavePtr->width; 1113 1114 if (fraq > 0.0) { 1115 wavePtr->ssmp = (int) (fraq * floor(wavePtr->ssmp/fraq)); 1116 wavePtr->esmp = wavePtr->ssmp + len; 1117 } 1118 if (wavePtr->esmp > wavePtr->bufPos - 1) 1119 wavePtr->esmp = wavePtr->bufPos - 1; 1120 } 1121 1122 1123 if (wavePtr->fg == NULL) { 1124 newGC = None; 1125 } else { 1126 gcValues.foreground = wavePtr->fg->pixel; 1127 gcValues.line_width = 1; 1128 mask = GCForeground|GCLineWidth; 1129 if (wavePtr->fillStipple != None) { 1130 gcValues.stipple = wavePtr->fillStipple; 1131 gcValues.fill_style = FillStippled; 1132 mask |= GCStipple|GCFillStyle; 1133 } 1134 newGC = Tk_GetGC(tkwin, mask, &gcValues); 1135 gcValues.line_width = 0; 1136 } 1137 if (wavePtr->gc != None) { 1138 Tk_FreeGC(Tk_Display(tkwin), wavePtr->gc); 1139 } 1140 wavePtr->gc = newGC; 1141 1142 ComputeWaveBbox(canvas, wavePtr); 1143 1144 if (doCompute) { 1145 if (ComputeWaveCoords(itemPtr) != TCL_OK) { 1146 return TCL_ERROR; 1147 } 1148 } 1149 1150 for (i = 0; configSpecs[i].type != TK_CONFIG_END; i++) { 1151 configSpecs[i].specFlags &= ~TK_CONFIG_OPTION_SPECIFIED; 1152 } 1153 1154 if (wavePtr->debug > 1) 1155 Snack_WriteLogInt(" Exit ConfigureWave", wavePtr->width); 1156 1157 return TCL_OK; 1158} 1159 1160static void 1161DeleteWave(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display) 1162{ 1163 WaveItem *wavePtr = (WaveItem *) itemPtr; 1164 1165 if ((wavePtr->id) && 1166 (Snack_GetSound(wavePtr->interp, wavePtr->soundName) != NULL)) { 1167 Snack_RemoveCallback(wavePtr->sound, wavePtr->id); 1168 } 1169 1170 if (wavePtr->soundName != NULL) ckfree(wavePtr->soundName); 1171 1172 if (wavePtr->x0 != NULL) ckfree((char *) wavePtr->x0); 1173 if (wavePtr->y0 != NULL) ckfree((char *) wavePtr->y0); 1174 if (wavePtr->x1 != NULL) ckfree((char *) wavePtr->x1); 1175 if (wavePtr->y1 != NULL) ckfree((char *) wavePtr->y1); 1176 1177 if (wavePtr->fg != NULL) Tk_FreeColor(wavePtr->fg); 1178 1179 if (wavePtr->fillStipple != None) Tk_FreeBitmap(display, wavePtr->fillStipple); 1180 1181 if (wavePtr->gc != None) Tk_FreeGC(display, wavePtr->gc); 1182 1183 if (wavePtr->preWI != NULL) ckfree((char *)wavePtr->preWI); 1184 1185 if (wavePtr->preSound != NULL) Snack_DeleteSound(wavePtr->preSound); 1186 1187 if (wavePtr->sound != NULL) { 1188 if (wavePtr->sound->storeType == SOUND_IN_FILE) { 1189 wavePtr->sound->itemRefCnt--; 1190 } 1191 } 1192 1193 if (wavePtr->cmdPtr != NULL) Tcl_DecrRefCount(wavePtr->cmdPtr); 1194} 1195 1196static void 1197ComputeWaveBbox(Tk_Canvas canvas, WaveItem *wavePtr) 1198{ 1199 int width = wavePtr->width; 1200 int height = wavePtr->height; 1201 int x = (int) (wavePtr->x + ((wavePtr->x >= 0) ? 0.5 : - 0.5)); 1202 int y = (int) (wavePtr->y + ((wavePtr->y >= 0) ? 0.5 : - 0.5)); 1203 1204 switch (wavePtr->anchor) { 1205 case TK_ANCHOR_N: 1206 x -= width/2; 1207 break; 1208 case TK_ANCHOR_NE: 1209 x -= width; 1210 break; 1211 case TK_ANCHOR_E: 1212 x -= width; 1213 y -= height/2; 1214 break; 1215 case TK_ANCHOR_SE: 1216 x -= width; 1217 y -= height; 1218 break; 1219 case TK_ANCHOR_S: 1220 x -= width/2; 1221 y -= height; 1222 break; 1223 case TK_ANCHOR_SW: 1224 y -= height; 1225 break; 1226 case TK_ANCHOR_W: 1227 y -= height/2; 1228 break; 1229 case TK_ANCHOR_NW: 1230 break; 1231 case TK_ANCHOR_CENTER: 1232 x -= width/2; 1233 y -= height/2; 1234 break; 1235 } 1236 1237 wavePtr->header.x1 = x; 1238 wavePtr->header.y1 = y; 1239 wavePtr->header.x2 = x + width; 1240 wavePtr->header.y2 = y + height; 1241} 1242 1243static void 1244DisplayWave(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, 1245 Drawable drawable, int x, int y, int width, int height) 1246{ 1247 WaveItem *wavePtr = (WaveItem *) itemPtr; 1248 int i; 1249 int xo = wavePtr->header.x1; 1250 int yo = wavePtr->header.y1; 1251 int ym = wavePtr->height / 2; 1252 int dx = max(x - xo, 0); 1253 float scale = 1000000.0f; 1254 XPoint fpts[5]; 1255 1256 if (wavePtr->debug > 1) Snack_WriteLogInt(" Enter DisplayWave", width); 1257 1258 if (wavePtr->height == 0) return; 1259 1260 if (wavePtr->gc == None) return; 1261 1262 if (wavePtr->fillStipple != None) 1263 Tk_CanvasSetStippleOrigin(canvas, wavePtr->gc); 1264 1265 if (wavePtr->height > 2) { 1266 scale = 2 * ((wavePtr->maxv > -wavePtr->minv) 1267 ? wavePtr->maxv : 1268 -wavePtr->minv) / (float)(wavePtr->height - 2); 1269 } 1270 if (scale < 0.00001f) { 1271 scale = 0.00001f; 1272 } 1273 1274 if (dx + width > wavePtr->width) { 1275 width = wavePtr->width - dx; 1276 } 1277 if (dx > 0) { 1278 dx--; 1279 if (width < wavePtr->width - dx) width++; 1280 if (width < wavePtr->width - dx) width++; 1281 } 1282 for (i = dx; i < dx + width; i++) { 1283 Tk_CanvasDrawableCoords(canvas, xo + wavePtr->x0[i], 1284 yo + ym - wavePtr->y0[i] / scale, 1285 &fpts[0].x, &fpts[0].y); 1286 Tk_CanvasDrawableCoords(canvas, xo + wavePtr->x1[i], 1287 yo + ym - wavePtr->y1[i] / scale, 1288 &fpts[1].x, &fpts[1].y); 1289 Tk_CanvasDrawableCoords(canvas, xo + wavePtr->x1[i]+1, 1290 yo + ym - wavePtr->y1[i] / scale, 1291 &fpts[2].x, &fpts[2].y); 1292 XDrawLines(display, drawable, wavePtr->gc, fpts, 3, CoordModeOrigin); 1293 } 1294 1295 if (wavePtr->zeroLevel) { 1296 Tk_CanvasDrawableCoords(canvas, (double) xo, 1297 (double) (yo + wavePtr->height / 2), 1298 &fpts[0].x, &fpts[0].y); 1299 Tk_CanvasDrawableCoords(canvas, (double) (xo + wavePtr->width - 1), 1300 (double) (yo + wavePtr->height / 2), 1301 &fpts[1].x, &fpts[1].y); 1302 XDrawLines(display, drawable, wavePtr->gc, fpts, 2, CoordModeOrigin); 1303 } 1304 1305 if (wavePtr->frame) { 1306 Tk_CanvasDrawableCoords(canvas, (double) xo, (double) yo, 1307 &fpts[0].x, &fpts[0].y); 1308 Tk_CanvasDrawableCoords(canvas, (double) (xo + wavePtr->width - 1), 1309 (double) yo, 1310 &fpts[1].x, &fpts[1].y); 1311 Tk_CanvasDrawableCoords(canvas, (double) (xo + wavePtr->width - 1), 1312 (double) (yo + wavePtr->height - 1), 1313 &fpts[2].x, &fpts[2].y); 1314 Tk_CanvasDrawableCoords(canvas, (double) xo, 1315 (double) (yo + wavePtr->height - 1), 1316 &fpts[3].x, &fpts[3].y); 1317 Tk_CanvasDrawableCoords(canvas, (double) xo, (double) yo, 1318 &fpts[4].x, &fpts[4].y); 1319 XDrawLines(display, drawable, wavePtr->gc, fpts, 5, CoordModeOrigin); 1320 } 1321 1322 if (wavePtr->debug > 1) Snack_WriteLog(" Exit DisplayWave\n"); 1323} 1324 1325static double 1326WaveToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *coords) 1327{ 1328 WaveItem *wavePtr = (WaveItem *) itemPtr; 1329 double dx = 0.0, dy = 0.0; 1330 double x1 = wavePtr->header.x1; 1331 double y1 = wavePtr->header.y1; 1332 double x2 = wavePtr->header.x2; 1333 double y2 = wavePtr->header.y2; 1334 1335 if (coords[0] < x1) 1336 dx = x1 - coords[0]; 1337 else if (coords[0] > x2) 1338 dx = coords[0] - x2; 1339 else 1340 dx = 0; 1341 1342 if (coords[1] < y1) 1343 dy = y1 - coords[1]; 1344 else if (coords[1] > y2) 1345 dy = coords[1] - y2; 1346 else 1347 dy = 0; 1348 1349 return hypot(dx, dy); 1350} 1351 1352static int 1353WaveToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr) 1354{ 1355 WaveItem *wavePtr = (WaveItem *) itemPtr; 1356 1357 if ((rectPtr[2] <= wavePtr->header.x1) || 1358 (rectPtr[0] >= wavePtr->header.x2) || 1359 (rectPtr[3] <= wavePtr->header.y1) || 1360 (rectPtr[1] >= wavePtr->header.y2)) 1361 return -1; 1362 1363 if ((rectPtr[0] <= wavePtr->header.x1) && 1364 (rectPtr[1] <= wavePtr->header.y1) && 1365 (rectPtr[2] >= wavePtr->header.x2) && 1366 (rectPtr[3] >= wavePtr->header.y2)) 1367 return 1; 1368 1369 return 0; 1370} 1371 1372static void 1373ScaleWave(Tk_Canvas canvas, Tk_Item *itemPtr, double ox, double oy, 1374 double sx, double sy) 1375{ 1376 WaveItem *wavePtr = (WaveItem *) itemPtr; 1377 double *x0 = wavePtr->x0; 1378 double *y0 = wavePtr->y0; 1379 double *x1 = wavePtr->x1; 1380 double *y1 = wavePtr->y1; 1381 int i; 1382 1383 for (i = 0; i < wavePtr->width; i++) { 1384 x0[i] = ox + sx * (x0[i] - ox); 1385 y0[i] = oy + sy * (y0[i] - oy); 1386 x1[i] = ox + sx * (x1[i] - ox); 1387 y1[i] = oy + sy * (y1[i] - oy); 1388 } 1389 wavePtr->width = (int) (sx * wavePtr->width) + 1; 1390 wavePtr->height = (int) (sy * wavePtr->height); 1391 if (wavePtr->bufPos > 0) 1392 wavePtr->pixpsec = (double) wavePtr->width * wavePtr->samprate / 1393 wavePtr->bufPos; 1394 1395 ComputeWaveBbox(canvas, wavePtr); 1396} 1397 1398static void 1399TranslateWave(Tk_Canvas canvas, Tk_Item *itemPtr, double dx, double dy) 1400{ 1401 WaveItem *wavePtr = (WaveItem *) itemPtr; 1402 1403 wavePtr->x += dx; 1404 wavePtr->y += dy; 1405 ComputeWaveBbox(canvas, wavePtr); 1406} 1407 1408static int 1409WaveToPS(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass) 1410{ 1411 WaveItem *wavePtr = (WaveItem *) itemPtr; 1412 double *x0 = wavePtr->x0; 1413 double *y0 = wavePtr->y0; 1414 double *x1 = wavePtr->x1; 1415 double *y1 = wavePtr->y1; 1416 int i; 1417 char buffer[100]; 1418 int xo = wavePtr->header.x1; 1419 int yo = wavePtr->header.y1; 1420 float scale = 1000000.0f; 1421 1422 if (wavePtr->fg == NULL) { 1423 return TCL_OK; 1424 } 1425 if (wavePtr->height > 2) { 1426 scale = 2 * ((wavePtr->maxv > -wavePtr->minv) 1427 ? wavePtr->maxv : 1428 -wavePtr->minv) / (float)(wavePtr->height - 2); 1429 } 1430 if (scale < 0.00001f) { 1431 scale = 0.00001f; 1432 } 1433 1434 Tcl_AppendResult(interp, "%% WAVE BEGIN\n", (char *) NULL); 1435 1436 for (i = 0; i < wavePtr->width; i++) { 1437 sprintf(buffer, 1438 "%.1f %.1f moveto\n%.1f %.1f lineto\n", 1439 x0[i] + xo, Tk_CanvasPsY(canvas, (double) 1440 (-y0[i]/scale + yo+ wavePtr->height / 2)), 1441 x1[i] + xo, Tk_CanvasPsY(canvas, (double) 1442 (-y1[i]/scale + yo+ wavePtr->height / 2))); 1443 Tcl_AppendResult(interp, buffer, (char *) NULL); 1444 if ((double)(wavePtr->esmp - wavePtr->ssmp)/wavePtr->width < 1.0) { 1445 sprintf(buffer, "%.1f %.1f lineto\n", 1446 x1[i] + xo + 1, Tk_CanvasPsY(canvas, (double) 1447 (-y1[i]/scale + yo+ wavePtr->height / 2))); 1448 Tcl_AppendResult(interp, buffer, (char *) NULL); 1449 } 1450 } 1451 1452 if (wavePtr->zeroLevel) { 1453 sprintf(buffer, "%.1f %.1f moveto\n", (double) xo, 1454 Tk_CanvasPsY(canvas, (double) (yo + wavePtr->height / 2))); 1455 Tcl_AppendResult(interp, buffer, (char *) NULL); 1456 1457 sprintf(buffer, "%.1f %.1f lineto\n", (double) xo + wavePtr->width - 1, 1458 Tk_CanvasPsY(canvas, (double) (yo + wavePtr->height / 2))); 1459 Tcl_AppendResult(interp, buffer, (char *) NULL); 1460 } 1461 1462 if (wavePtr->frame) { 1463 sprintf(buffer, "%.1f %.1f moveto\n", (double) xo, Tk_CanvasPsY(canvas, (double) yo)); 1464 Tcl_AppendResult(interp, buffer, (char *) NULL); 1465 1466 sprintf(buffer, "%.1f %.1f lineto\n", (double) xo + wavePtr->width - 1, 1467 Tk_CanvasPsY(canvas, (double) yo)); 1468 Tcl_AppendResult(interp, buffer, (char *) NULL); 1469 1470 sprintf(buffer, "%.1f %.1f lineto\n", (double) xo + wavePtr->width - 1, 1471 Tk_CanvasPsY(canvas, (double) (yo + wavePtr->height - 1))); 1472 Tcl_AppendResult(interp, buffer, (char *) NULL); 1473 1474 sprintf(buffer, "%.1f %.1f lineto\n", (double) xo, 1475 Tk_CanvasPsY(canvas, (double) (yo + wavePtr->height - 1))); 1476 Tcl_AppendResult(interp, buffer, (char *) NULL); 1477 1478 sprintf(buffer, "%.1f %.1f lineto\n", (double) xo, 1479 Tk_CanvasPsY(canvas, (double) yo)); 1480 Tcl_AppendResult(interp, buffer, (char *) NULL); 1481 } 1482 1483 Tcl_AppendResult(interp, "1 setlinewidth\n", (char *) NULL); 1484 Tcl_AppendResult(interp, "0 setlinecap\n0 setlinejoin\n", (char *) NULL); 1485 if (Tk_CanvasPsColor(interp, canvas, wavePtr->fg) != TCL_OK) { 1486 return TCL_ERROR; 1487 }; 1488 if (wavePtr->fillStipple != None) { 1489 Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); 1490 if (Tk_CanvasPsStipple(interp, canvas, wavePtr->fillStipple) != TCL_OK) { 1491 return TCL_ERROR; 1492 } 1493 } else { 1494 Tcl_AppendResult(interp, "stroke\n", (char *) NULL); 1495 } 1496 1497 Tcl_AppendResult(interp, "%% WAVE END\n", (char *) NULL); 1498 1499 return TCL_OK; 1500} 1501