home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / xdrum / part02 < prev    next >
Encoding:
Text File  |  1993-05-15  |  57.3 KB  |  2,037 lines

  1. Newsgroups: comp.sources.misc
  2. From: durian@advtech.uswest.com (Mike Durian)
  3. Subject: v37i049:  xdrum - create and edit drum patterns, Part02/02
  4. Message-ID: <1993May11.173934.1077@sparky.imd.sterling.com>
  5. X-Md4-Signature: 71dcda33937d43cd59ffa4aaa107a58b
  6. Date: Tue, 11 May 1993 17:39:34 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: durian@advtech.uswest.com (Mike Durian)
  10. Posting-number: Volume 37, Issue 49
  11. Archive-name: xdrum/part02
  12. Environment: X11, tcl, tk, tclm, BSD/386, Esix SysV, SunOS
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 2 (of 2)."
  21. # Contents:  xdrum-1.0/tkmGrid.c
  22. # Wrapped by durian@angeleys on Fri May  7 13:06:26 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'xdrum-1.0/tkmGrid.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'xdrum-1.0/tkmGrid.c'\"
  26. else
  27. echo shar: Extracting \"'xdrum-1.0/tkmGrid.c'\" \(54953 characters\)
  28. sed "s/^X//" >'xdrum-1.0/tkmGrid.c' <<'END_OF_FILE'
  29. X/*-
  30. X * Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  31. X *
  32. X * Redistribution and use in source and binary forms, with or without
  33. X * modification, are permitted provided that the following conditions
  34. X * are met:
  35. X * 1. Redistributions of source code must retain the above copyright
  36. X *    notice, this list of conditions and the following disclaimer.
  37. X * 2. Redistributions in binary form must reproduce the above copyright
  38. X *    notice, this list of conditions and the following disclaimer in the
  39. X *    documentation and/or other materials provided with the distribution.
  40. X * 3. All advertising materials mentioning features or use of this software
  41. X *    must display the following acknowledgement:
  42. X *    This product includes software developed by Michael B. Durian.
  43. X * 4. The name of the the Author may be used to endorse or promote 
  44. X *    products derived from this software without specific prior written 
  45. X *    permission.
  46. X *
  47. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  48. X * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  49. X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  50. X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  51. X * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  52. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  53. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  54. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  55. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  56. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  57. X * SUCH DAMAGE.
  58. X */
  59. X/*
  60. X * tkmGrid.c,v 1.8 1993/05/07 17:51:22 durian Exp
  61. X */
  62. X#include <stdio.h>
  63. X#include <stdlib.h>
  64. X#include <unistd.h>
  65. X#include <string.h>
  66. X#include "tk.h"
  67. X#include "tkm.h"
  68. X
  69. static char cvsid[] = "tkmGrid.c,v 1.8 1993/05/07 17:51:22 durian Exp";
  70. X
  71. X
  72. X/* the volumes of each quanta for a voice */
  73. typedef struct {
  74. X    short *volume;
  75. X} Voice;
  76. X
  77. X/* All the data a poor grid widget could ever want */
  78. typedef struct {
  79. X    Tk_Window tkwin;
  80. X    Display *display;
  81. X    Tcl_Interp *interp;
  82. X
  83. X    /* information about the grid */
  84. X    char **labels;
  85. X    char *labelStr;
  86. X    char *pitchStr;
  87. X    int *pitches;
  88. X    int numLabels;
  89. X    int levels;
  90. X    int oldLevels; /* so we know how many to free on reconfig */
  91. X    int beats;
  92. X    int measures;
  93. X    int quantization;
  94. X
  95. X    /* information on how to display the grid */
  96. X    Tk_3DBorder normalBorder;
  97. X    int borderWidth;
  98. X    int relief;
  99. X    XFontStruct *font;
  100. X    XColor *lineColor;
  101. X    XColor *measureColor;
  102. X    XColor *beatColor;
  103. X    XColor *fgColor;
  104. X    Tk_3DBorder *levelsBorder;
  105. X    GC textGC;
  106. X    GC lineGC;
  107. X    GC measureGC;
  108. X    GC beatGC;
  109. X    GC *vertLineColors;
  110. X    XSegment *vertLinePos;
  111. X    GC *horizLineColors;
  112. X    XSegment *horizLinePos;
  113. X    int boxWid;
  114. X    int boxHt;
  115. X    int totalBoxWid;
  116. X    int totalBoxHt;
  117. X    int lineThickness;
  118. X    int labelWidth;
  119. X    int padX;
  120. X    Voice *voices;
  121. X    int numHits;
  122. X    int *leftBearings;
  123. X    int *rightBearings;
  124. X    int width;
  125. X    int height;
  126. X    int resizedWidth;
  127. X    int resizedHeight;
  128. X
  129. X    /* for scrolling */
  130. X    int leftHit;
  131. X    int rightHit;
  132. X    int topLabel;
  133. X    int bottomLabel;
  134. X    char *xScrollCmd;
  135. X    char *yScrollCmd;
  136. X
  137. X    /* misc */
  138. X    Cursor cursor;
  139. X    int flags;
  140. X} DrumGrid;
  141. X
  142. static char *className = "DrumGrid";
  143. X
  144. X/* possible values for the flags variable */
  145. X#define REDRAW_PENDING (1 << 0)
  146. X#define UPDATE_XSCROLL (1 << 1)
  147. X#define UPDATE_YSCROLL (1 << 2)
  148. X
  149. X/* how to parse configuration specs */
  150. static Tk_ConfigSpec configSpecs[] = {
  151. X    {TK_CONFIG_COLOR, "-foreground",  "foreground", "Background",
  152. X        DEF_GRID_FG_COLOR, Tk_Offset(DrumGrid, fgColor),
  153. X        TK_CONFIG_COLOR_ONLY},
  154. X    {TK_CONFIG_COLOR, "-foreground",  "foreground", "Background",
  155. X        DEF_GRID_FG_MONO, Tk_Offset(DrumGrid, fgColor),
  156. X        TK_CONFIG_MONO_ONLY},
  157. X    {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL,
  158. X        (char *)NULL, 0, 0},
  159. X
  160. X    {TK_CONFIG_BORDER, "-background",  "background", "Background",
  161. X        DEF_GRID_NORMAL_BG_COLOR, Tk_Offset(DrumGrid, normalBorder),
  162. X        TK_CONFIG_COLOR_ONLY},
  163. X    {TK_CONFIG_BORDER, "-background",  "background", "Background",
  164. X        DEF_GRID_NORMAL_BG_MONO, Tk_Offset(DrumGrid, normalBorder),
  165. X        TK_CONFIG_MONO_ONLY},
  166. X    {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL,
  167. X        (char *)NULL, 0, 0},
  168. X
  169. X    {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  170. X        DEF_GRID_BORDER_WIDTH, Tk_Offset(DrumGrid, borderWidth), 0},
  171. X    {TK_CONFIG_SYNONYM, "-bw", "borderWidth", (char *)NULL,
  172. X        (char *)NULL, 0, 0},
  173. X
  174. X    {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  175. X        DEF_GRID_CURSOR, Tk_Offset(DrumGrid, cursor), TK_CONFIG_NULL_OK},
  176. X
  177. X    {TK_CONFIG_FONT, "-font", "font", "Font", DEF_GRID_FONT,
  178. X        Tk_Offset(DrumGrid, font), 0},
  179. X
  180. X    {TK_CONFIG_INT, "-height", "height", "Height", DEF_GRID_HEIGHT,
  181. X        Tk_Offset(DrumGrid, height), 0},
  182. X
  183. X    {TK_CONFIG_INT, "-width", "width", "Width", DEF_GRID_WIDTH,
  184. X        Tk_Offset(DrumGrid, width), 0},
  185. X
  186. X    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_GRID_RELIEF,
  187. X        Tk_Offset(DrumGrid, relief), 0},
  188. X
  189. X    {TK_CONFIG_STRING, "-labels", "labels", "Labels", DEF_GRID_LABELS,
  190. X        Tk_Offset(DrumGrid, labelStr), TK_CONFIG_NULL_OK},
  191. X
  192. X    {TK_CONFIG_STRING, "-pitches", "pitches", "Pitches", DEF_GRID_PITCHES,
  193. X        Tk_Offset(DrumGrid, pitchStr), TK_CONFIG_NULL_OK},
  194. X
  195. X    {TK_CONFIG_INT, "-levels", "levels", "Levels", DEF_GRID_LEVELS,
  196. X        Tk_Offset(DrumGrid, levels), 0},
  197. X
  198. X    {TK_CONFIG_INT, "-beats", "beats", "Beats", DEF_GRID_BEATS,
  199. X        Tk_Offset(DrumGrid, beats), 0},
  200. X
  201. X    {TK_CONFIG_INT, "-measures", "measures", "Measures", DEF_GRID_MEASURES,
  202. X        Tk_Offset(DrumGrid, measures), 0},
  203. X
  204. X    {TK_CONFIG_INT, "-quantization", "quantization", "Quantization",
  205. X        DEF_GRID_QUANTIZATION, Tk_Offset(DrumGrid, quantization), 0},
  206. X    {TK_CONFIG_SYNONYM, "-quant", "quantization", (char *)NULL,
  207. X        (char *)NULL, 0, 0},
  208. X
  209. X    {TK_CONFIG_INT, "-linethickness", "lineThickness", "LineThickness",
  210. X        DEF_GRID_LINETHICKNESS, Tk_Offset(DrumGrid, lineThickness), 0},
  211. X    {TK_CONFIG_SYNONYM, "-lt", "lineThickness", (char *)NULL,
  212. X        (char *)NULL, 0, 0},
  213. X
  214. X    {TK_CONFIG_INT, "-padx", "padX", "PadX", DEF_GRID_PADX,
  215. X        Tk_Offset(DrumGrid, padX), 0},
  216. X
  217. X    {TK_CONFIG_INT, "-boxwidth", "boxWidth", "BoxWidth", DEF_GRID_BOXWIDTH,
  218. X        Tk_Offset(DrumGrid, boxWid)},
  219. X    {TK_CONFIG_SYNONYM, "-bw", "boxWidth", (char *)NULL, (char *)NULL, 0,
  220. X        0},
  221. X
  222. X    {TK_CONFIG_INT, "-boxheight", "boxHeight", "BoxHeight",
  223. X        DEF_GRID_BOXHEIGHT, Tk_Offset(DrumGrid, boxHt)},
  224. X    {TK_CONFIG_SYNONYM, "-bh", "boxHeight", (char *)NULL, (char *)NULL, 0,
  225. X        0},
  226. X
  227. X    {TK_CONFIG_COLOR, "-linecolor", "lineColor", "LineColor",
  228. X        DEF_GRID_LINE_COLOR, Tk_Offset(DrumGrid, lineColor)},
  229. X    {TK_CONFIG_SYNONYM, "-lc", "lineColor", (char *)NULL, (char *)NULL,
  230. X        0, 0},
  231. X
  232. X    {TK_CONFIG_COLOR, "-measurecolor", "measureColor", "MeasureColor",
  233. X        DEF_GRID_MEASURE_COLOR, Tk_Offset(DrumGrid, measureColor)},
  234. X    {TK_CONFIG_SYNONYM, "-mc", "measureColor", (char *)NULL, (char *)NULL,
  235. X        0, 0},
  236. X
  237. X    {TK_CONFIG_COLOR, "-beatcolor", "beatColor", "BeatColor",
  238. X        DEF_GRID_BEAT_COLOR, Tk_Offset(DrumGrid, beatColor)},
  239. X    {TK_CONFIG_SYNONYM, "-bc", "beatColor", (char *)NULL, (char *)NULL,
  240. X        0, 0},
  241. X
  242. X    {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand",
  243. X        "ScrollCommand", DEF_GRID_SCROLL_COMMAND, Tk_Offset(DrumGrid,
  244. X        xScrollCmd)},
  245. X    {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand",
  246. X        "ScrollCommand", DEF_GRID_SCROLL_COMMAND, Tk_Offset(DrumGrid,
  247. X        yScrollCmd)},
  248. X
  249. X    {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL,
  250. X        0, 0}
  251. X};
  252. X
  253. static char *optString = "configure, down, label add, label remove, \
  254. label list, pitch get, pitch set, pitch list, up, volume get, volume set, \
  255. xview, xnearest, yview, ynearest";
  256. X
  257. static int AddLabel _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **));
  258. static int AllocateGridLines _ANSI_ARGS_((DrumGrid *));
  259. static void CalculateGridLines _ANSI_ARGS_((DrumGrid *));
  260. static void ChangeDrumGridLeft _ANSI_ARGS_((DrumGrid *, int));
  261. static void ChangeDrumGridTop _ANSI_ARGS_((DrumGrid *, int));
  262. static void ComputeDrumGridGeometry _ANSI_ARGS_((DrumGrid *));
  263. static int ConfigureDrumGrid _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int,
  264. X    char **, int));
  265. static void DecreaseVolume _ANSI_ARGS_((DrumGrid *, int, int));
  266. static void DestroyDrumGrid  _ANSI_ARGS_((ClientData));
  267. static void DisplayDrumGrid _ANSI_ARGS_((ClientData));
  268. static void DrawHit _ANSI_ARGS_((DrumGrid *, Pixmap, int, int, int));
  269. static void DrawLabels _ANSI_ARGS_((DrumGrid *, Pixmap));
  270. static void DrumGridEventProc _ANSI_ARGS_((ClientData, XEvent *));
  271. static int DrumGridWidgetCmd _ANSI_ARGS_((ClientData, Tcl_Interp *, int,
  272. X    char **));
  273. static void DrumGridUpdateXScroll _ANSI_ARGS_((DrumGrid *));
  274. static void DrumGridUpdateYScroll _ANSI_ARGS_((DrumGrid *));
  275. static void FitSize _ANSI_ARGS_((DrumGrid *));
  276. static int GetLabels _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **));
  277. static int GetPitch _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **));
  278. static int GetVolume _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **));
  279. static int HitRelief _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **, int));
  280. static void IncreaseVolume _ANSI_ARGS_((DrumGrid *, int, int));
  281. static int ListPitches _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **));
  282. static void MakeLabelStr _ANSI_ARGS_((DrumGrid *));
  283. static void MakePitchStr _ANSI_ARGS_((DrumGrid *));
  284. static int RemoveLabel _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **));
  285. static int SetPitch _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **));
  286. static int SetVolume _ANSI_ARGS_((Tcl_Interp *, DrumGrid *, int, char **));
  287. static int XToGrid _ANSI_ARGS_((DrumGrid *, int));
  288. static int YToGrid _ANSI_ARGS_((DrumGrid *, int));
  289. X
  290. X#ifdef TCL_MEM_DEBUG
  291. static char *Tclm_DbCkstrdup _ANSI_ARGS_((char *str));
  292. X#define ckstrdup(str) Tclm_DbCkstrdup(str)
  293. X#else
  294. X#define ckstrdup(str) strdup(str)
  295. X#endif
  296. X
  297. int
  298. Tk_DrumGridCmd(clientData, interp, argc, argv)
  299. X    ClientData clientData;
  300. X    Tcl_Interp *interp;
  301. X    int argc;
  302. X    char **argv;
  303. X{
  304. X    DrumGrid *dgPtr;
  305. X    Tk_Window tkwin = (Tk_Window) clientData;
  306. X    Tk_Window new;
  307. X
  308. X    if (argc < 2) {
  309. X        Tcl_AppendResult(interp, "wrong # args: should be \"",
  310. X            argv[0], " pathName ?options?\"", (char *)NULL);
  311. X        return (TCL_ERROR);
  312. X    }
  313. X
  314. X    if ((new = Tk_CreateWindowFromPath(interp, tkwin, argv[1],
  315. X        (char *)NULL)) == NULL)
  316. X        return (TCL_ERROR);
  317. X
  318. X    if ((dgPtr = (DrumGrid *)ckalloc(sizeof(DrumGrid))) == NULL) {
  319. X        Tcl_AppendResult(interp, "Out of memory for DrumGrid",
  320. X            (char *)NULL);
  321. X        return (TCL_ERROR);
  322. X    }
  323. X    
  324. X    dgPtr->tkwin = new;
  325. X    dgPtr->display = Tk_Display(new);
  326. X    dgPtr->interp = interp;
  327. X    dgPtr->labels = NULL;
  328. X    dgPtr->labelStr = NULL;
  329. X    dgPtr->pitchStr = NULL;
  330. X    dgPtr->pitches = NULL;
  331. X    dgPtr->numLabels = 0;
  332. X    dgPtr->levels = 0;
  333. X    dgPtr->oldLevels = 0;
  334. X    dgPtr->beats = 0;
  335. X    dgPtr->measures = 0;
  336. X    dgPtr->quantization = 0;
  337. X    dgPtr->normalBorder = NULL;
  338. X    dgPtr->borderWidth = 0;
  339. X    dgPtr->relief = TK_RELIEF_FLAT;
  340. X    dgPtr->font = NULL;
  341. X    dgPtr->lineColor = NULL;
  342. X    dgPtr->measureColor = NULL;
  343. X    dgPtr->beatColor = NULL;
  344. X    dgPtr->levelsBorder = NULL;
  345. X    dgPtr->fgColor = NULL;
  346. X    dgPtr->textGC = None;
  347. X    dgPtr->lineGC = None;
  348. X    dgPtr->measureGC = None;
  349. X    dgPtr->beatGC = None;
  350. X    dgPtr->levelsBorder = NULL;
  351. X    dgPtr->vertLineColors = NULL;
  352. X    dgPtr->vertLinePos = NULL;
  353. X    dgPtr->horizLineColors = NULL;
  354. X    dgPtr->horizLinePos = NULL;
  355. X    dgPtr->boxWid = 0;
  356. X    dgPtr->boxHt = 0;
  357. X    dgPtr->totalBoxWid = 0;
  358. X    dgPtr->totalBoxHt = 0;
  359. X    dgPtr->lineThickness = 0;
  360. X    dgPtr->labelWidth = 0;
  361. X    dgPtr->padX = 0;
  362. X    dgPtr->voices = NULL;
  363. X    dgPtr->numHits = 0;
  364. X    dgPtr->leftBearings = NULL;
  365. X    dgPtr->rightBearings = NULL;
  366. X    dgPtr->width = 0;
  367. X    dgPtr->height = 0;
  368. X    dgPtr->resizedWidth = -1;
  369. X    dgPtr->resizedHeight = -1;
  370. X    dgPtr->leftHit = 0;
  371. X    dgPtr->rightHit = 0;
  372. X    dgPtr->topLabel = 0;
  373. X    dgPtr->bottomLabel = 0;
  374. X    dgPtr->xScrollCmd = NULL;
  375. X    dgPtr->yScrollCmd = NULL;
  376. X    dgPtr->cursor = None;
  377. X    dgPtr->flags = 0;
  378. X
  379. X    Tk_SetClass(new, className);
  380. X
  381. X    Tk_CreateEventHandler(dgPtr->tkwin, ExposureMask | StructureNotifyMask,
  382. X        DrumGridEventProc, (ClientData)dgPtr);
  383. X
  384. X    Tcl_CreateCommand(interp, Tk_PathName(dgPtr->tkwin),
  385. X        DrumGridWidgetCmd, (ClientData)dgPtr, (void (*)())NULL);
  386. X
  387. X    if (ConfigureDrumGrid(interp, dgPtr, argc - 2, argv + 2, 0) !=
  388. X        TCL_OK) {
  389. X        Tk_DestroyWindow(dgPtr->tkwin);
  390. X        return (TCL_ERROR);
  391. X    }
  392. X
  393. X    interp->result = Tk_PathName(dgPtr->tkwin);
  394. X    return (TCL_OK);
  395. X}
  396. X
  397. static int
  398. ConfigureDrumGrid(interp, dgPtr, argc, argv, flags)
  399. X    Tcl_Interp *interp;
  400. X    DrumGrid *dgPtr;
  401. X    int argc;
  402. X    char **argv;
  403. X    int flags;
  404. X{
  405. X    XGCValues gcValues;
  406. X    GC newGC;
  407. X    long background;
  408. X    char **labels;
  409. X    char **pitches;
  410. X    char *chkPtr;
  411. X    char colorStr[20];
  412. X    int colorVal;
  413. X    int i;
  414. X    int j;
  415. X    int offset;
  416. X    int numPitches;
  417. X
  418. X    if (Tk_ConfigureWidget(interp, dgPtr->tkwin, configSpecs,
  419. X        argc, argv, (char *)dgPtr, flags) != TCL_OK)
  420. X        return (TCL_ERROR);
  421. X
  422. X    /* free anything that might already be here */
  423. X    if (dgPtr->labels != NULL) {
  424. X        for (i = 0; i < dgPtr->numLabels; i++)
  425. X            if (dgPtr->labels[i] != NULL)
  426. X                ckfree((char *)dgPtr->labels[i]);
  427. X        ckfree((char *)dgPtr->labels);
  428. X    }
  429. X
  430. X    /* free existing voice data */
  431. X    if (dgPtr->voices != NULL) {
  432. X        for (i = 0; i < dgPtr->numLabels; i++)
  433. X            if (dgPtr->voices[i].volume != NULL)
  434. X                ckfree(dgPtr->voices[i].volume);
  435. X        ckfree(dgPtr->voices);
  436. X        dgPtr->voices = NULL;
  437. X    }
  438. X
  439. X    /* parse out labels string */
  440. X    if (Tcl_SplitList(interp, dgPtr->labelStr, &dgPtr->numLabels,
  441. X        &labels) != TCL_OK)
  442. X        return (TCL_ERROR);
  443. X
  444. X    /* do our own alloction of labels so we can change them easier */
  445. X    if ((dgPtr->labels = (char **)ckalloc(sizeof(char *) *
  446. X        dgPtr->numLabels)) == NULL) {
  447. X        Tcl_AppendResult(interp, "Not enough memory for labels",
  448. X            (char *)NULL);
  449. X        ckfree((char *)labels);
  450. X        return (TCL_ERROR);
  451. X    }
  452. X    for (i = 0; i < dgPtr->numLabels; i++) {
  453. X        if ((dgPtr->labels[i] = ckstrdup(labels[i])) == NULL) {
  454. X            Tcl_AppendResult(interp, "Not enough memory to ",
  455. X               "copy a label", (char *)NULL);
  456. X            ckfree((char *)labels);
  457. X            return (TCL_ERROR);
  458. X        }
  459. X    }
  460. X    ckfree((char *)labels);
  461. X
  462. X    /* parse out the pitches */
  463. X    if (dgPtr->pitchStr == NULL)
  464. X        numPitches = 0;
  465. X    else {
  466. X        if (Tcl_SplitList(interp, dgPtr->pitchStr, &numPitches,
  467. X            &pitches) != TCL_OK)
  468. X            return (TCL_ERROR);
  469. X    }
  470. X
  471. X    if (dgPtr->pitches != NULL)
  472. X        ckfree(dgPtr->pitches);
  473. X
  474. X    if ((dgPtr->pitches = (int *)ckalloc(sizeof(int) * dgPtr->numLabels))
  475. X        == NULL) {
  476. X        Tcl_AppendResult(interp, "Not enough memory for pitch ",
  477. X            "values", (char *)NULL);
  478. X        ckfree((char *)pitches);
  479. X        return (TCL_ERROR);
  480. X    }
  481. X    for (i = 0; i < dgPtr->numLabels; i++) {
  482. X        if (i >= numPitches)
  483. X            dgPtr->pitches[i] = -1;
  484. X        else {
  485. X            dgPtr->pitches[i] = (int)strtol(pitches[i], &chkPtr,
  486. X                0);
  487. X            if (chkPtr == pitches[i]) {
  488. X                Tcl_AppendResult(interp, "Bad pitch value ",
  489. X                    pitches[i], (char *)NULL);
  490. X                ckfree((char *)pitches);
  491. X                return (TCL_ERROR);
  492. X            }
  493. X        }
  494. X    }
  495. X    ckfree((char *)pitches);
  496. X
  497. X    Tk_SetBackgroundFromBorder(dgPtr->tkwin, dgPtr->normalBorder);
  498. X
  499. X    background = Tk_3DBorderColor(dgPtr->normalBorder)->pixel;
  500. X
  501. X    /* set up text GC */
  502. X    gcValues.font = dgPtr->font->fid;
  503. X    gcValues.foreground = dgPtr->fgColor->pixel;
  504. X    gcValues.background = background;
  505. X    gcValues.graphics_exposures = False;
  506. X    newGC = Tk_GetGC(dgPtr->tkwin, GCForeground | GCBackground | GCFont
  507. X        | GCGraphicsExposures, &gcValues);
  508. X    if (dgPtr->textGC != None)
  509. X        Tk_FreeGC(dgPtr->display, dgPtr->textGC);
  510. X    dgPtr->textGC = newGC;
  511. X
  512. X    /* set up normal line GC */
  513. X    gcValues.function = GXcopy;
  514. X    gcValues.foreground = dgPtr->lineColor->pixel;
  515. X    gcValues.background = background;
  516. X    gcValues.line_style = LineSolid;
  517. X    gcValues.line_width = dgPtr->lineThickness;
  518. X    gcValues.graphics_exposures = False;
  519. X    newGC = Tk_GetGC(dgPtr->tkwin, GCFunction | GCForeground |
  520. X        GCBackground | GCLineStyle | GCLineWidth | GCGraphicsExposures,
  521. X        &gcValues);
  522. X    if (dgPtr->lineGC != None)
  523. X        Tk_FreeGC(dgPtr->display, dgPtr->lineGC);
  524. X    dgPtr->lineGC = newGC;
  525. X
  526. X    /* set up measure line GC */
  527. X    gcValues.function = GXcopy;
  528. X    gcValues.foreground = dgPtr->measureColor->pixel;
  529. X    gcValues.background = background;
  530. X    gcValues.line_style = LineSolid;
  531. X    gcValues.line_width = dgPtr->lineThickness;
  532. X    gcValues.graphics_exposures = False;
  533. X    newGC = Tk_GetGC(dgPtr->tkwin, GCFunction | GCForeground |
  534. X        GCBackground | GCLineStyle | GCLineWidth | GCGraphicsExposures,
  535. X        &gcValues);
  536. X    if (dgPtr->measureGC != None)
  537. X        Tk_FreeGC(dgPtr->display, dgPtr->measureGC);
  538. X    dgPtr->measureGC = newGC;
  539. X
  540. X    /* set up beat line GC */
  541. X    gcValues.function = GXcopy;
  542. X    gcValues.foreground = dgPtr->beatColor->pixel;
  543. X    gcValues.background = background;
  544. X    gcValues.line_style = LineSolid;
  545. X    gcValues.line_width = dgPtr->lineThickness;
  546. X    gcValues.graphics_exposures = False;
  547. X    newGC = Tk_GetGC(dgPtr->tkwin, GCFunction | GCForeground |
  548. X        GCBackground | GCLineStyle | GCLineWidth | GCGraphicsExposures,
  549. X        &gcValues);
  550. X    if (dgPtr->beatGC != None)
  551. X        Tk_FreeGC(dgPtr->display, dgPtr->beatGC);
  552. X    dgPtr->beatGC = newGC;
  553. X
  554. X    if (dgPtr->levelsBorder != NULL) {
  555. X        for (i = 0; i < dgPtr->oldLevels; i++)
  556. X            if (dgPtr->levelsBorder[i] != None)
  557. X                Tk_Free3DBorder(dgPtr->levelsBorder[i]);
  558. X        ckfree((char *)dgPtr->levelsBorder);
  559. X    }
  560. X
  561. X    if ((dgPtr->levelsBorder = (Tk_3DBorder *)ckalloc(sizeof(Tk_3DBorder)
  562. X        * dgPtr->levels)) == NULL) {
  563. X        Tcl_AppendResult(interp, "Not enough memory for level ",
  564. X            "Borders's", (char *)NULL);
  565. X        return (TCL_ERROR);
  566. X    }
  567. X
  568. X#define LEVEL_MIN 10000
  569. X    for (i = 0; i < dgPtr->levels; i++) {
  570. X        colorVal = ((0xffff - LEVEL_MIN) / dgPtr->levels) * i +
  571. X            LEVEL_MIN;
  572. X        sprintf(colorStr, "#%04x%04x%04x", colorVal, colorVal,
  573. X            colorVal);
  574. X
  575. X        if ((dgPtr->levelsBorder[i] = Tk_Get3DBorder(interp,
  576. X            dgPtr->tkwin, None, Tk_GetUid(colorStr))) == NULL) {
  577. X            Tcl_AppendResult(interp, "Couldn't level Border",
  578. X                (char *)NULL);
  579. X            return (TCL_ERROR);
  580. X        }
  581. X    }
  582. X
  583. X    dgPtr->oldLevels = dgPtr->levels;
  584. X
  585. X    /* fix quantization to be a multiple of 4 */
  586. X    if ((offset = dgPtr->quantization % 4) < 2)
  587. X        dgPtr->quantization -= offset;
  588. X    else
  589. X        dgPtr->quantization += 4 - offset;
  590. X
  591. X    dgPtr->numHits = dgPtr->beats * dgPtr->measures * dgPtr->quantization
  592. X        / 4;
  593. X
  594. X    /* make the voices */
  595. X    if (dgPtr->numLabels != 0)
  596. X    if ((dgPtr->voices = (Voice *)ckalloc(sizeof(Voice) * dgPtr->numLabels))
  597. X        == NULL) {
  598. X        Tcl_AppendResult(interp, "Not enough memory for voices",
  599. X            (char *)NULL);
  600. X        return (TCL_ERROR);
  601. X    }
  602. X
  603. X    /* make hits(quanta) inside voices */
  604. X    for (i = 0; i < dgPtr->numLabels; i++) {
  605. X        if ((dgPtr->voices[i].volume = (short *)ckalloc(dgPtr->numHits
  606. X             * sizeof(short))) == NULL) {
  607. X            Tcl_AppendResult(interp, "Not enough memory for ",
  608. X               "hits in voice", (char *)NULL);
  609. X            return (TCL_ERROR);
  610. X        }
  611. X        for (j = 0; j < dgPtr->numHits; j++)
  612. X            dgPtr->voices[i].volume[j] = 0;
  613. X    }
  614. X
  615. X    /* decide how the scroll region should look */
  616. X    dgPtr->leftHit = 0;
  617. X    dgPtr->topLabel = 0;
  618. X    if (dgPtr->resizedWidth != -1 && dgPtr->resizedHeight != -1)
  619. X        FitSize(dgPtr);
  620. X    else {
  621. X        if (dgPtr->width == 0)
  622. X            /* by default do one measure */
  623. X            dgPtr->rightHit = dgPtr->beats *
  624. X                dgPtr->quantization / 4 - 1;
  625. X        else
  626. X            dgPtr->rightHit = dgPtr->width - 1;
  627. X        if (dgPtr->height == 0)
  628. X            /* by default do them all */
  629. X            dgPtr->bottomLabel = dgPtr->numLabels - 1;
  630. X        else
  631. X            dgPtr->bottomLabel = dgPtr->height - 1;
  632. X    }
  633. X
  634. X    dgPtr->flags |= UPDATE_YSCROLL | UPDATE_XSCROLL;
  635. X
  636. X    /* make room for grid lines */
  637. X    if (AllocateGridLines(dgPtr) != TCL_OK)
  638. X        return (TCL_ERROR);
  639. X
  640. X    /* make room for bearings */
  641. X    if (dgPtr->leftBearings != NULL)
  642. X        ckfree(dgPtr->leftBearings);
  643. X    if ((dgPtr->leftBearings = (int *)ckalloc(sizeof(int) *
  644. X        dgPtr->numLabels)) == NULL) {
  645. X        Tcl_AppendResult(interp, "Not enough memory for leftbearings",
  646. X            (char *)NULL);
  647. X        return (TCL_ERROR);
  648. X    }
  649. X
  650. X    if (dgPtr->rightBearings != NULL)
  651. X        ckfree(dgPtr->rightBearings);
  652. X    if ((dgPtr->rightBearings = (int *)ckalloc(sizeof(int) *
  653. X        dgPtr->numLabels)) == NULL) {
  654. X        Tcl_AppendResult(interp, "Not enough memory for rightbearings",
  655. X            (char *)NULL);
  656. X        return (TCL_ERROR);
  657. X    }
  658. X
  659. X    /* calculate geometry */
  660. X    ComputeDrumGridGeometry(dgPtr);
  661. X
  662. X    /* display it */
  663. X    if (Tk_IsMapped(dgPtr->tkwin) && (!dgPtr->flags & REDRAW_PENDING)) {
  664. X        Tk_DoWhenIdle(DisplayDrumGrid, (ClientData)dgPtr);
  665. X        dgPtr->flags |= REDRAW_PENDING;
  666. X    }
  667. X
  668. X    return (TCL_OK);
  669. X}
  670. X
  671. static void
  672. DestroyDrumGrid (clientData)
  673. X    ClientData clientData;
  674. X{
  675. X    DrumGrid *dgPtr = (DrumGrid *)clientData;
  676. X    int i;
  677. X
  678. X    if (dgPtr->labels != NULL) {
  679. X        for (i = 0; i < dgPtr->numLabels; i++)
  680. X            if (dgPtr->labels[i] != NULL)
  681. X                ckfree((char *)dgPtr->labels[i]);
  682. X        ckfree((char *)dgPtr->labels);
  683. X    }
  684. X    if (dgPtr->labelStr != NULL)
  685. X        ckfree(dgPtr->labelStr);
  686. X    if (dgPtr->pitches != NULL)
  687. X        ckfree((char *)dgPtr->pitches);
  688. X    if (dgPtr->pitchStr != NULL)
  689. X        ckfree(dgPtr->pitchStr);
  690. X    if (dgPtr->normalBorder != NULL)
  691. X        Tk_Free3DBorder(dgPtr->normalBorder);
  692. X    if (dgPtr->font != NULL)
  693. X        Tk_FreeFontStruct(dgPtr->font);
  694. X    if (dgPtr->lineColor != NULL)
  695. X        Tk_FreeColor(dgPtr->lineColor);
  696. X    if (dgPtr->measureColor != NULL)
  697. X        Tk_FreeColor(dgPtr->measureColor);
  698. X    if (dgPtr->beatColor != NULL)
  699. X        Tk_FreeColor(dgPtr->beatColor);
  700. X    if (dgPtr->fgColor != NULL)
  701. X        Tk_FreeColor(dgPtr->fgColor);
  702. X    if (dgPtr->textGC != None)
  703. X        Tk_FreeGC(dgPtr->display, dgPtr->textGC);
  704. X    if (dgPtr->lineGC != None)
  705. X        Tk_FreeGC(dgPtr->display, dgPtr->lineGC);
  706. X    if (dgPtr->measureGC != None)
  707. X        Tk_FreeGC(dgPtr->display, dgPtr->measureGC);
  708. X    if (dgPtr->beatGC != None)
  709. X        Tk_FreeGC(dgPtr->display, dgPtr->beatGC);
  710. X    if (dgPtr->levelsBorder != NULL) {
  711. X        for (i = 0; i < dgPtr->oldLevels; i++)
  712. X            if (dgPtr->levelsBorder[i] != None)
  713. X                Tk_Free3DBorder(dgPtr->levelsBorder[i]);
  714. X        ckfree((char *)dgPtr->levelsBorder);
  715. X    }
  716. X    if (dgPtr->vertLineColors != NULL)
  717. X        ckfree((char *)dgPtr->vertLineColors);
  718. X    if (dgPtr->vertLinePos != NULL)
  719. X        ckfree((char *)dgPtr->vertLinePos);
  720. X    if (dgPtr->horizLineColors != NULL)
  721. X        ckfree((char *)dgPtr->horizLineColors);
  722. X    if (dgPtr->horizLinePos != NULL)
  723. X        ckfree((char *)dgPtr->horizLinePos);
  724. X    if (dgPtr->voices != NULL) {
  725. X        for (i = 0; i < dgPtr->numLabels; i++)
  726. X            if (dgPtr->voices[i].volume != NULL)
  727. X                ckfree((char *)dgPtr->voices[i].volume);
  728. X        ckfree((char *)dgPtr->voices);
  729. X    }
  730. X    if (dgPtr->leftBearings != NULL)
  731. X        ckfree((char *)dgPtr->leftBearings);
  732. X    if (dgPtr->rightBearings != NULL)
  733. X        ckfree((char *)dgPtr->rightBearings);
  734. X    if (dgPtr->xScrollCmd != NULL)
  735. X        ckfree(dgPtr->xScrollCmd);
  736. X    if (dgPtr->yScrollCmd != NULL)
  737. X        ckfree(dgPtr->yScrollCmd);
  738. X    if (dgPtr->cursor != None)
  739. X        Tk_FreeCursor(dgPtr->display, dgPtr->cursor);
  740. X}
  741. X
  742. static void
  743. DisplayDrumGrid(clientData)
  744. X    ClientData clientData;
  745. X{
  746. X    DrumGrid *dgPtr = (DrumGrid *)clientData;
  747. X    Tk_Window tkwin = dgPtr->tkwin;
  748. X    Pixmap pixmap;
  749. X    Tk_3DBorder border;
  750. X    int i;
  751. X    int j;
  752. X    int x;
  753. X    int y;
  754. X
  755. X    dgPtr->flags &= ~REDRAW_PENDING;
  756. X    if (dgPtr->flags & UPDATE_XSCROLL)
  757. X        DrumGridUpdateXScroll(dgPtr);
  758. X    if (dgPtr->flags & UPDATE_YSCROLL)
  759. X        DrumGridUpdateYScroll(dgPtr);
  760. X    dgPtr->flags &= ~(UPDATE_XSCROLL | UPDATE_YSCROLL);
  761. X    if (tkwin == NULL || !Tk_IsMapped(tkwin))
  762. X        return;
  763. X
  764. X    border = dgPtr->normalBorder;
  765. X    pixmap = XCreatePixmap(dgPtr->display, Tk_WindowId(tkwin),
  766. X        Tk_Width(tkwin), Tk_Height(tkwin),
  767. X        DefaultDepthOfScreen(Tk_Screen(tkwin)));
  768. X    Tk_Fill3DRectangle(dgPtr->display, pixmap, border, 0, 0,
  769. X        Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
  770. X
  771. X    /* horizontal lines */
  772. X    for (i = dgPtr->topLabel, j = 0; i <= dgPtr->bottomLabel + 1; i++, j++)
  773. X        XDrawSegments(dgPtr->display, pixmap,
  774. X            dgPtr->horizLineColors[i], &dgPtr->horizLinePos[j], 1);
  775. X
  776. X    /* vertical lines */
  777. X    /* always do line to left of labels */
  778. X    XDrawSegments(dgPtr->display, pixmap,
  779. X        dgPtr->vertLineColors[dgPtr->numHits + 1],
  780. X        &dgPtr->vertLinePos[dgPtr->rightHit - dgPtr->leftHit + 2], 1);
  781. X
  782. X    for (i = dgPtr->leftHit, j = 0; i <= dgPtr->rightHit + 1; i++, j++)
  783. X        XDrawSegments(dgPtr->display, pixmap,
  784. X            dgPtr->vertLineColors[i], &dgPtr->vertLinePos[j], 1);
  785. X
  786. X    DrawLabels(dgPtr, pixmap);
  787. X
  788. X    /* draw in hits */
  789. X    for (x = dgPtr->leftHit; x < dgPtr->rightHit + 1; x++)
  790. X        for (y = dgPtr->topLabel; y < dgPtr->bottomLabel + 1; y++)
  791. X            DrawHit(dgPtr, (Pixmap)pixmap, x, y, 0);
  792. X
  793. X    /* draw border */
  794. X    if (dgPtr->relief != TK_RELIEF_FLAT)
  795. X        Tk_Draw3DRectangle(dgPtr->display, pixmap, border, 0, 0,
  796. X            Tk_Width(tkwin), Tk_Height(tkwin), dgPtr->borderWidth,
  797. X            dgPtr->relief);
  798. X
  799. X    XCopyArea(dgPtr->display, pixmap, Tk_WindowId(tkwin),
  800. X        dgPtr->textGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0);
  801. X    XFreePixmap(dgPtr->display, pixmap);
  802. X}
  803. X
  804. static void
  805. DrawLabels(dgPtr, pixmap)
  806. X    DrumGrid *dgPtr;
  807. X    Pixmap pixmap;
  808. X{
  809. X    int i;
  810. X    int top;
  811. X    int x;
  812. X    int y;
  813. X
  814. X    top = dgPtr->borderWidth;
  815. X    for (i = dgPtr->topLabel; i < dgPtr->bottomLabel + 1; i++) {
  816. X        x = dgPtr->borderWidth + dgPtr->padX + dgPtr->leftBearings[i]
  817. X            + 1;
  818. X        y = top + (dgPtr->boxHt + dgPtr->font->ascent -
  819. X            dgPtr->font->descent) / 2;
  820. X        if (dgPtr->relief == TK_RELIEF_RAISED) {
  821. X            x--;
  822. X            y--;
  823. X        } else if (dgPtr->relief == TK_RELIEF_SUNKEN) {
  824. X            x++;
  825. X            y++;
  826. X        }
  827. X        XDrawString(dgPtr->display, pixmap,
  828. X            dgPtr->textGC, x, y, dgPtr->labels[i],
  829. X            strlen(dgPtr->labels[i]));
  830. X        top += dgPtr->boxHt;
  831. X    }
  832. X}
  833. X
  834. static void
  835. DrawHit(dgPtr, pixmap, x, y, depressed)
  836. X    DrumGrid *dgPtr;
  837. X    Pixmap pixmap;
  838. X    int x;
  839. X    int y;
  840. X    int depressed;
  841. X{
  842. X    int x_pos;
  843. X    int y_pos;
  844. X    int width;
  845. X    int height;
  846. X    int relief;
  847. X    int volume;
  848. X
  849. X    x_pos = dgPtr->labelWidth + dgPtr->borderWidth + (x - dgPtr->leftHit)
  850. X        * dgPtr->boxWid + dgPtr->lineThickness / 2;
  851. X    y_pos = dgPtr->borderWidth + (y - dgPtr->topLabel) * dgPtr->boxHt +
  852. X        dgPtr->lineThickness / 2;
  853. X
  854. X    width = dgPtr->boxWid - dgPtr->lineThickness;
  855. X    height = dgPtr->boxHt - dgPtr->lineThickness;
  856. X    volume = dgPtr->voices[y].volume[x];
  857. X    if (depressed)
  858. X        relief = TK_RELIEF_SUNKEN;
  859. X    else if (volume == 0)
  860. X        relief = TK_RELIEF_FLAT;
  861. X    else
  862. X        relief = TK_RELIEF_RAISED;
  863. X    Tk_Fill3DRectangle(dgPtr->display, pixmap,
  864. X        dgPtr->levelsBorder[volume], x_pos, y_pos, width, height,
  865. X        dgPtr->borderWidth, relief);
  866. X}
  867. X
  868. static void
  869. ComputeDrumGridGeometry(dgPtr)
  870. X    DrumGrid *dgPtr;
  871. X{
  872. X    XCharStruct bbox;
  873. X    int foo;
  874. X    int i;
  875. X    int width;
  876. X    int height;
  877. X    unsigned int labelWidth;
  878. X
  879. X    labelWidth = 0;
  880. X    for (i = 0; i < dgPtr->numLabels; i++) {
  881. X        XTextExtents(dgPtr->font, dgPtr->labels[i],
  882. X            strlen(dgPtr->labels[i]), &foo, &foo, &foo, &bbox);
  883. X        dgPtr->leftBearings[i] = bbox.lbearing;
  884. X        dgPtr->rightBearings[i] = bbox.rbearing;
  885. X        labelWidth = labelWidth > bbox.lbearing + bbox.rbearing ?
  886. X            labelWidth : bbox.lbearing + bbox.rbearing;
  887. X    }
  888. X    labelWidth += 2 * dgPtr->padX + 1;
  889. X    dgPtr->labelWidth = labelWidth;
  890. X
  891. X    width = labelWidth + (dgPtr->rightHit - dgPtr->leftHit + 1) *
  892. X        dgPtr->boxWid;
  893. X    height = (dgPtr->bottomLabel - dgPtr->topLabel + 1) * dgPtr->boxHt;
  894. X
  895. X    /* set up grid lines */
  896. X    CalculateGridLines(dgPtr);
  897. X
  898. X    Tk_GeometryRequest(dgPtr->tkwin, width + dgPtr->borderWidth * 2 + 2,
  899. X        height + dgPtr->borderWidth * 2 + 2);
  900. X    Tk_SetInternalBorder(dgPtr->tkwin, dgPtr->borderWidth);
  901. X}
  902. X
  903. static void
  904. CalculateGridLines(dgPtr)
  905. X    DrumGrid *dgPtr;
  906. X{
  907. X    GC *lineColorPtr;
  908. X    XSegment *linePosPtr;
  909. X    int hitsPerMeasure;
  910. X    int i;
  911. X
  912. X    lineColorPtr = dgPtr->vertLineColors;
  913. X    linePosPtr = dgPtr->vertLinePos;
  914. X    hitsPerMeasure = dgPtr->beats * dgPtr->quantization / 4;
  915. X
  916. X    for (i = 0; i < dgPtr->numHits + 1; i++, lineColorPtr++) {
  917. X        /* 1st and last lines are normal */
  918. X        if (i == 0 || i == dgPtr->numHits || i % (dgPtr->quantization
  919. X            / 4) != 0)
  920. X            *lineColorPtr = dgPtr->lineGC;
  921. X        else if (i % hitsPerMeasure == 0)
  922. X            *lineColorPtr = dgPtr->measureGC;
  923. X        else
  924. X            *lineColorPtr = dgPtr->beatGC;
  925. X    }
  926. X    for (i = 0; i <= dgPtr->rightHit - dgPtr->leftHit + 1; i++,
  927. X        linePosPtr++) {
  928. X        linePosPtr->x1 = linePosPtr->x2 = i * dgPtr->boxWid
  929. X            + dgPtr->labelWidth + dgPtr->borderWidth;
  930. X        linePosPtr->y1 = dgPtr->borderWidth;
  931. X        linePosPtr->y2 = dgPtr->boxHt * (dgPtr->bottomLabel -
  932. X            dgPtr->topLabel + 1) + dgPtr->borderWidth;
  933. X    }
  934. X
  935. X    /* line to the left of the labels */
  936. X    *lineColorPtr = dgPtr->lineGC;
  937. X    linePosPtr->x1 = linePosPtr->x2 = dgPtr->borderWidth;
  938. X    linePosPtr->y1 = dgPtr->borderWidth;
  939. X    linePosPtr->y2 = dgPtr->borderWidth + dgPtr->boxHt *
  940. X        (dgPtr->bottomLabel - dgPtr->topLabel + 1);
  941. X
  942. X    /* horizontal lines */
  943. X    lineColorPtr = dgPtr->horizLineColors;
  944. X    linePosPtr = dgPtr->horizLinePos;
  945. X    for (i = 0; i < dgPtr->numLabels + 1; i++, lineColorPtr++)
  946. X        *lineColorPtr = dgPtr->lineGC;
  947. X
  948. X    for (i = 0; i <= dgPtr->bottomLabel - dgPtr->topLabel + 1; i++,
  949. X        linePosPtr++) {
  950. X        linePosPtr->x1 = dgPtr->borderWidth;
  951. X        linePosPtr->x2 = dgPtr->boxWid * (dgPtr->rightHit -
  952. X            dgPtr->leftHit + 1) + dgPtr->labelWidth +
  953. X            dgPtr->borderWidth;
  954. X        linePosPtr->y1 = linePosPtr->y2 = i * dgPtr->boxHt
  955. X            + dgPtr->borderWidth;
  956. X    }
  957. X}
  958. X
  959. X
  960. static void
  961. DrumGridEventProc(clientData, eventPtr)
  962. X    ClientData clientData;
  963. X    XEvent *eventPtr;
  964. X{
  965. X    DrumGrid *dgPtr = (DrumGrid *)clientData;
  966. X    int num_boxes;
  967. X    int num_labels;
  968. X
  969. X    switch (eventPtr->type) {
  970. X    case Expose:
  971. X        if (eventPtr->xexpose.count == 0) {
  972. X            if ((dgPtr->tkwin != NULL) && !(dgPtr->flags &
  973. X                REDRAW_PENDING)) {
  974. X                Tk_DoWhenIdle(DisplayDrumGrid,
  975. X                    (ClientData)dgPtr);
  976. X                dgPtr->flags |= REDRAW_PENDING;
  977. X            }
  978. X        }
  979. X        break;
  980. X    case DestroyNotify:
  981. X        Tcl_DeleteCommand(dgPtr->interp, Tk_PathName(dgPtr->tkwin));
  982. X        dgPtr->tkwin = NULL;
  983. X        if (dgPtr->flags & REDRAW_PENDING)
  984. X            Tk_CancelIdleCall(DisplayDrumGrid, (ClientData)dgPtr);
  985. X        Tk_EventuallyFree((ClientData)dgPtr, DestroyDrumGrid);
  986. X        break;
  987. X    case ConfigureNotify:
  988. X        num_boxes = (Tk_Width(dgPtr->tkwin) - 2 -
  989. X            2 * dgPtr->borderWidth - dgPtr->labelWidth) /
  990. X            dgPtr->boxWid;
  991. X        num_labels = (Tk_Height(dgPtr->tkwin) - 2 -
  992. X            2 * dgPtr->borderWidth) / dgPtr->boxHt;
  993. X        dgPtr->resizedWidth = num_boxes;
  994. X        dgPtr->resizedHeight = num_labels;
  995. X        FitSize(dgPtr);
  996. X        if (AllocateGridLines(dgPtr) != TCL_OK)
  997. X            Tk_BackgroundError(dgPtr->interp);
  998. X        CalculateGridLines(dgPtr);
  999. X        dgPtr->flags |= UPDATE_XSCROLL | UPDATE_YSCROLL;
  1000. X        break;
  1001. X    }
  1002. X}
  1003. X
  1004. static int
  1005. XXToGrid(dgPtr, x)
  1006. X    DrumGrid *dgPtr;
  1007. X    int x;
  1008. X{
  1009. X    int gridX;
  1010. X
  1011. X    if (x < dgPtr->labelWidth + dgPtr->borderWidth || x > dgPtr->labelWidth
  1012. X        + (dgPtr->rightHit - dgPtr->leftHit + 1) * dgPtr->boxWid)
  1013. X        return (-1);
  1014. X    gridX = (x - dgPtr->labelWidth - dgPtr->borderWidth) / dgPtr->boxWid;
  1015. X    gridX += dgPtr->leftHit;
  1016. X    return (gridX);
  1017. X}
  1018. X
  1019. static int
  1020. YToGrid(dgPtr, y)
  1021. X    DrumGrid *dgPtr;
  1022. X    int y;
  1023. X{
  1024. X    int gridY;
  1025. X
  1026. X    if (y < dgPtr->borderWidth || y > dgPtr->borderWidth +
  1027. X        (dgPtr->bottomLabel - dgPtr->topLabel + 1) * dgPtr->boxHt)
  1028. X        return (-1);
  1029. X    gridY = (y - dgPtr->borderWidth) / dgPtr->boxHt;
  1030. X    gridY += dgPtr->topLabel;
  1031. X    return (gridY);
  1032. X}
  1033. X
  1034. X/*
  1035. X * IncreaseVolume and DecreaseVolume are no longer used now that
  1036. X * button bindings are done in the script.
  1037. static void
  1038. IncreaseVolume(dgPtr, x, y)
  1039. X    DrumGrid *dgPtr;
  1040. X    int x;
  1041. X    int y;
  1042. X{
  1043. X
  1044. X    dgPtr->voices[y].volume[x]++;
  1045. X    if (dgPtr->voices[y].volume[x] >= dgPtr->levels)
  1046. X        dgPtr->voices[y].volume[x] = dgPtr->levels - 1;
  1047. X    DrawHit(dgPtr, Tk_WindowId(dgPtr->tkwin), x, y, 0);
  1048. X}
  1049. X
  1050. static void
  1051. DecreaseVolume(dgPtr, x, y)
  1052. X    DrumGrid *dgPtr;
  1053. X    int x;
  1054. X    int y;
  1055. X{
  1056. X
  1057. X    dgPtr->voices[y].volume[x]--;
  1058. X    if (dgPtr->voices[y].volume[x] < 0)
  1059. X        dgPtr->voices[y].volume[x] = 0;
  1060. X    DrawHit(dgPtr, Tk_WindowId(dgPtr->tkwin), x, y, 0);
  1061. X}
  1062. X * end of comment out of IncreaseVolume and DecreaseVolume
  1063. X */
  1064. X
  1065. static int
  1066. DrumGridWidgetCmd(clientData, interp, argc, argv)
  1067. X    ClientData clientData;
  1068. X    Tcl_Interp *interp;
  1069. X    int argc;
  1070. X    char **argv;
  1071. X{
  1072. X    DrumGrid *dgPtr = (DrumGrid *)clientData;
  1073. X    int index;
  1074. X    int result;
  1075. X    int length;
  1076. X    int pos;
  1077. X    char c;
  1078. X
  1079. X    result = TCL_OK;
  1080. X
  1081. X    if (argc < 2) {
  1082. X        Tcl_AppendResult(interp, "Wrong # args: should be \"",
  1083. X            argv[0], " option ?arg arg ...?\"", (char *)NULL);
  1084. X        return (TCL_ERROR);
  1085. X    }
  1086. X    Tk_Preserve((ClientData)dgPtr);
  1087. X    c = argv[1][0];
  1088. X    length = strlen(argv[1]);
  1089. X    switch (c) {
  1090. X    case 'c':
  1091. X        if (strncmp(argv[1], "configure", length) == 0) {
  1092. X            if (argc == 2)
  1093. X                result = Tk_ConfigureInfo(interp,
  1094. X                    dgPtr->tkwin, configSpecs, (char *)dgPtr,
  1095. X                    (char *)NULL, 0);
  1096. X            else if (argc == 3)
  1097. X                result = Tk_ConfigureInfo(interp,
  1098. X                    dgPtr->tkwin, configSpecs, (char *)dgPtr,
  1099. X                    argv[2], 0);
  1100. X            else
  1101. X                result = ConfigureDrumGrid(interp, dgPtr,
  1102. X                    argc - 2, argv + 2, TK_CONFIG_ARGV_ONLY);
  1103. X        } else {
  1104. X            Tcl_AppendResult(interp, "bad option ", argv[1],
  1105. X                ": must be one of ", optString, (char *)NULL);
  1106. X            result = TCL_ERROR;
  1107. X        }
  1108. X        break;
  1109. X    case 'd':
  1110. X        if (strncmp(argv[1], "down", length) == 0) {
  1111. X            if (argc == 4)
  1112. X                result = HitRelief(interp, dgPtr, argc - 2,
  1113. X                    argv + 2, 1);
  1114. X            else {
  1115. X                Tcl_AppendResult(interp, "wrong # args: ",
  1116. X                    "should be \"", argv[0], " up x y\"",
  1117. X                    (char *)NULL);
  1118. X                result = TCL_ERROR;
  1119. X            }
  1120. X        } else {
  1121. X            Tcl_AppendResult(interp, "bad option ", argv[1],
  1122. X                ": must be one of ", optString, (char *)NULL);
  1123. X            result = TCL_ERROR;
  1124. X        }
  1125. X        break;
  1126. X    case 'l':
  1127. X        if (strncmp(argv[1], "label", length) == 0) {
  1128. X            length = strlen(argv[2]);
  1129. X            if (strncmp(argv[2], "add", length) == 0)
  1130. X                result = AddLabel(interp, dgPtr, argc - 3,
  1131. X                    argv + 3);
  1132. X            else if (strncmp(argv[2], "remove", length) == 0)
  1133. X                result = RemoveLabel(interp, dgPtr, argc - 3,
  1134. X                    argv + 3);
  1135. X            else if (strncmp(argv[2], "list", length) == 0)
  1136. X                result = GetLabels(interp, dgPtr, argc - 3,
  1137. X                    argv + 3);
  1138. X            else {
  1139. X                Tcl_AppendResult(interp, "bad option ",
  1140. X                    argv[2], ": must be add, remove or list",
  1141. X                    (char *)NULL);
  1142. X                result = TCL_ERROR;
  1143. X            }
  1144. X        } else {
  1145. X            Tcl_AppendResult(interp, "bad option ", argv[1],
  1146. X                ": must be one of ", optString, (char *)NULL);
  1147. X            result = TCL_ERROR;
  1148. X        }
  1149. X        break;
  1150. X    case 'p':
  1151. X        if (strncmp(argv[1], "pitch", length) == 0) {
  1152. X            length = strlen(argv[2]);
  1153. X            if (strncmp(argv[2], "get", length) == 0)
  1154. X                result = GetPitch(interp, dgPtr, argc - 3,
  1155. X                    argv + 3);
  1156. X            else if (strncmp(argv[2], "set", length) == 0)
  1157. X                result = SetPitch(interp, dgPtr, argc - 3,
  1158. X                    argv + 3);
  1159. X            else if (strncmp(argv[2], "list", length) == 0)
  1160. X                result = ListPitches(interp, dgPtr, argc - 3,
  1161. X                    argv + 3);
  1162. X            else {
  1163. X                Tcl_AppendResult(interp, "bad option ",
  1164. X                    argv[2], ": must be set, get or list",
  1165. X                    (char *)NULL);
  1166. X                result = TCL_ERROR;
  1167. X            }
  1168. X        } else {
  1169. X            Tcl_AppendResult(interp, "bad option ", argv[1],
  1170. X                ": must be one of ", optString, (char *)NULL);
  1171. X            result = TCL_ERROR;
  1172. X        }
  1173. X        break;
  1174. X    case 'u':
  1175. X        if (strncmp(argv[1], "up", length) == 0) {
  1176. X            if (argc == 4)
  1177. X                result = HitRelief(interp, dgPtr, argc - 2,
  1178. X                    argv + 2, 0);
  1179. X            else {
  1180. X                Tcl_AppendResult(interp, "wrong # args: ",
  1181. X                    "should be \"", argv[0], " up x y\"",
  1182. X                    (char *)NULL);
  1183. X                result = TCL_ERROR;
  1184. X            }
  1185. X        } else {
  1186. X            Tcl_AppendResult(interp, "bad option ", argv[1],
  1187. X                ": must be one of ", optString, (char *)NULL);
  1188. X            result = TCL_ERROR;
  1189. X        }
  1190. X        break;
  1191. X    case 'v':
  1192. X        if (strncmp(argv[1], "volume", length) == 0) {
  1193. X            length = strlen(argv[2]);
  1194. X            if (strncmp(argv[2], "get", length) == 0)
  1195. X                result = GetVolume(interp, dgPtr, argc - 3,
  1196. X                    argv + 3);
  1197. X            else if (strncmp(argv[2], "set", length) == 0)
  1198. X                result = SetVolume(interp, dgPtr, argc - 3,
  1199. X                    argv + 3);
  1200. X            else {
  1201. X                Tcl_AppendResult(interp, "bad option ",
  1202. X                    argv[2], ": must be set or get",
  1203. X                    (char *)NULL);
  1204. X                result = TCL_ERROR;
  1205. X            }
  1206. X        } else {
  1207. X            Tcl_AppendResult(interp, "bad option ", argv[1],
  1208. X                ": must be one of ", optString, (char *)NULL);
  1209. X            result = TCL_ERROR;
  1210. X        }
  1211. X        break;
  1212. X    case 'x':
  1213. X        if (strncmp(argv[1], "xview", length) == 0) {
  1214. X            if (argc < 2 || argc > 3) {
  1215. X                Tcl_AppendResult(interp, "wrong # args: ",
  1216. X                    "should be \"", argv[0], " xview ?index?\"",
  1217. X                    (char *)NULL);
  1218. X                result = TCL_ERROR;
  1219. X            } else if (argc == 2) {
  1220. X                sprintf(interp->result, "%d", dgPtr->leftHit);
  1221. X            } else if (argc == 3) {
  1222. X                if (Tcl_GetInt(interp, argv[2], &index)
  1223. X                    != TCL_OK)
  1224. X                    result = TCL_ERROR;
  1225. X                else
  1226. X                    ChangeDrumGridLeft(dgPtr, index);
  1227. X            }
  1228. X        } else if (strncmp(argv[1], "xnearest", length) == 0) {
  1229. X            if (argc != 3) {
  1230. X                Tcl_AppendResult(interp, "wrong # args: ",
  1231. X                    "should be \"", argv[0], " xnearest xpos\"",
  1232. X                    (char *)NULL);
  1233. X                result = TCL_ERROR;
  1234. X            } else {
  1235. X                if (Tcl_GetInt(interp, argv[2], &pos) !=
  1236. X                    TCL_OK)
  1237. X                    result = TCL_ERROR;
  1238. X                else
  1239. X                    sprintf(interp->result, "%d",
  1240. X                        XToGrid(dgPtr, pos));
  1241. X            }
  1242. X        } else {
  1243. X            Tcl_AppendResult(interp, "bad option ", argv[1],
  1244. X                ": must be one of ", optString, (char *)NULL);
  1245. X            result = TCL_ERROR;
  1246. X        }
  1247. X        break;
  1248. X    case 'y':
  1249. X        if (strncmp(argv[1], "yview", length) == 0) {
  1250. X            if (argc < 2 || argc > 3) {
  1251. X                Tcl_AppendResult(interp, "wrong # args: ",
  1252. X                    "should be \"", argv[0], " yview ?index?\"",
  1253. X                    (char *)NULL);
  1254. X                result = TCL_ERROR;
  1255. X            } else if (argc == 2) {
  1256. X                sprintf(interp->result, "%d", dgPtr->topLabel);
  1257. X            } else {
  1258. X                if (Tcl_GetInt(interp, argv[2], &index)
  1259. X                    != TCL_OK)
  1260. X                    result = TCL_ERROR;
  1261. X                else
  1262. X                    ChangeDrumGridTop(dgPtr, index);
  1263. X            }
  1264. X        } else if (strncmp(argv[1], "ynearest", length) == 0) {
  1265. X            if (argc != 3) {
  1266. X                Tcl_AppendResult(interp, "wrong # args: ",
  1267. X                    "should be \"", argv[0], " ynearest ypos\"",
  1268. X                    (char *)NULL);
  1269. X                result = TCL_ERROR;
  1270. X            } else {
  1271. X                if (Tcl_GetInt(interp, argv[2], &pos) !=
  1272. X                    TCL_OK)
  1273. X                    result = TCL_ERROR;
  1274. X                else
  1275. X                    sprintf(interp->result, "%d",
  1276. X                        YToGrid(dgPtr, pos));
  1277. X            }
  1278. X        } else {
  1279. X            Tcl_AppendResult(interp, "bad option ", argv[1],
  1280. X                ": must be one of ", optString, (char *)NULL);
  1281. X            result = TCL_ERROR;
  1282. X        }
  1283. X        break;
  1284. X    default:
  1285. X        Tcl_AppendResult(interp, "bad option ", argv[1],
  1286. X            ": must be one of ", optString, (char *)NULL);
  1287. X        result = TCL_ERROR;
  1288. X    }
  1289. X
  1290. X    Tk_Release((ClientData)dgPtr);
  1291. X    return (result);
  1292. X}
  1293. X
  1294. static int
  1295. GetVolume(interp, dgPtr, argc, argv)
  1296. X    Tcl_Interp *interp;
  1297. X    DrumGrid *dgPtr;
  1298. X    int argc;
  1299. X    char **argv;
  1300. X{
  1301. X    Tcl_Interp *temp_interp;
  1302. X    char foo[10];
  1303. X    int x;
  1304. X    int y;
  1305. X    char *chkPtr;
  1306. X
  1307. X    if (argc < 1 || argc > 2) {
  1308. X        Tcl_AppendResult(interp, "Must specify 'all' or x and y grid ",
  1309. X            "positions", (char *)NULL);
  1310. X        return (TCL_ERROR);
  1311. X    }
  1312. X
  1313. X    if (strcmp(argv[0], "all") == 0) {
  1314. X        temp_interp = Tcl_CreateInterp();
  1315. X        for (x = 0; x < dgPtr->numHits; x++) {
  1316. X            for (y = 0; y < dgPtr->numLabels; y++) {
  1317. X                sprintf(foo, "%d", dgPtr->voices[y].volume[x]);
  1318. X                Tcl_AppendElement(temp_interp, foo, 0);
  1319. X            }
  1320. X            Tcl_AppendElement(interp, temp_interp->result, 0);
  1321. X            Tcl_ResetResult(temp_interp);
  1322. X        }
  1323. X        Tcl_DeleteInterp(temp_interp);
  1324. X    } else {
  1325. X        x = (int)strtol(argv[0], &chkPtr, 0);
  1326. X        if (argv[0] == chkPtr || x >= dgPtr->numHits || x < 0) {
  1327. X            Tcl_AppendResult(interp, "Bad x grid position value ",
  1328. X                argv[0], (char *)NULL);
  1329. X            return (TCL_ERROR);
  1330. X        }
  1331. X
  1332. X        y = (int)strtol(argv[1], &chkPtr, 0);
  1333. X        if (argv[1] == chkPtr || y >= dgPtr->numLabels || y < 0) {
  1334. X            Tcl_AppendResult(interp, "Bad y grid position value ",
  1335. X                argv[1], (char *)NULL);
  1336. X            return (TCL_ERROR);
  1337. X        }
  1338. X
  1339. X        sprintf(interp->result, "%d", dgPtr->voices[y].volume[x]);
  1340. X    }
  1341. X    return (TCL_OK);
  1342. X}
  1343. X
  1344. static int
  1345. SetVolume(interp, dgPtr, argc, argv)
  1346. X    Tcl_Interp *interp;
  1347. X    DrumGrid *dgPtr;
  1348. X    int argc;
  1349. X    char **argv;
  1350. X{
  1351. X    int x;
  1352. X    int y;
  1353. X    int volume;
  1354. X    char *chkPtr;
  1355. X
  1356. X    if (argc != 3) {
  1357. X        Tcl_AppendResult(interp, "Must specify an x and y grid ",
  1358. X            "positions and a new volume", (char *)NULL);
  1359. X        return (TCL_ERROR);
  1360. X    }
  1361. X
  1362. X    x = (int)strtol(argv[0], &chkPtr, 0);
  1363. X    if (argv[0] == chkPtr || x >= dgPtr->numHits || x < 0) {
  1364. X        Tcl_AppendResult(interp, "Bad x grid position value ",
  1365. X            argv[0], (char *)NULL);
  1366. X        return (TCL_ERROR);
  1367. X    }
  1368. X
  1369. X    y = (int)strtol(argv[1], &chkPtr, 0);
  1370. X    if (argv[1] == chkPtr || y >= dgPtr->numLabels || y < 0) {
  1371. X        Tcl_AppendResult(interp, "Bad y grid position value ",
  1372. X            argv[1], (char *)NULL);
  1373. X        return (TCL_ERROR);
  1374. X    }
  1375. X
  1376. X    volume = (int)strtol(argv[2], &chkPtr, 0);
  1377. X    if (argv[2] == chkPtr) {
  1378. X        Tcl_AppendResult(interp, "Bad volume value ",
  1379. X            argv[2], (char *)NULL);
  1380. X        return (TCL_ERROR);
  1381. X    }
  1382. X
  1383. X    if (volume < 0)
  1384. X        volume = 0;
  1385. X    if (volume >= dgPtr->levels)
  1386. X        volume = dgPtr->levels - 1;
  1387. X    dgPtr->voices[y].volume[x] = volume;
  1388. X    DrawHit(dgPtr, Tk_WindowId(dgPtr->tkwin), x, y, 0);
  1389. X    sprintf(interp->result, "%d", volume);
  1390. X    return (TCL_OK);
  1391. X}
  1392. X
  1393. static int
  1394. GetPitch(interp, dgPtr, argc, argv)
  1395. X    Tcl_Interp *interp;
  1396. X    DrumGrid *dgPtr;
  1397. X    int argc;
  1398. X    char **argv;
  1399. X{
  1400. X    int y;
  1401. X    char *chkPtr;
  1402. X
  1403. X    if (argc != 1) {
  1404. X        Tcl_AppendResult(interp, "Must specify a y grid ",
  1405. X            "position", (char *)NULL);
  1406. X        return (TCL_ERROR);
  1407. X    }
  1408. X
  1409. X    y = (int)strtol(argv[0], &chkPtr, 0);
  1410. X    if (argv[0] == chkPtr || y >= dgPtr->numLabels || y < 0) {
  1411. X        Tcl_AppendResult(interp, "Bad y grid position value ",
  1412. X            argv[0], (char *)NULL);
  1413. X        return (TCL_ERROR);
  1414. X    }
  1415. X
  1416. X    sprintf(interp->result, "%d", dgPtr->pitches[y]);
  1417. X    return (TCL_OK);
  1418. X}
  1419. X
  1420. static int
  1421. SetPitch(interp, dgPtr, argc, argv)
  1422. X    Tcl_Interp *interp;
  1423. X    DrumGrid *dgPtr;
  1424. X    int argc;
  1425. X    char **argv;
  1426. X{
  1427. X    int y;
  1428. X    int pitch;
  1429. X    char *chkPtr;
  1430. X
  1431. X    if (argc != 2) {
  1432. X        Tcl_AppendResult(interp, "Must specify a y grid ",
  1433. X            "positions and a new pitch", (char *)NULL);
  1434. X        return (TCL_ERROR);
  1435. X    }
  1436. X
  1437. X    y = (int)strtol(argv[0], &chkPtr, 0);
  1438. X    if (argv[0] == chkPtr || y >= dgPtr->numLabels || y < 0) {
  1439. X        Tcl_AppendResult(interp, "Bad y grid position value ",
  1440. X            argv[1], (char *)NULL);
  1441. X        return (TCL_ERROR);
  1442. X    }
  1443. X
  1444. X    pitch = (int)strtol(argv[1], &chkPtr, 0);
  1445. X    if (argv[1] == chkPtr) {
  1446. X        Tcl_AppendResult(interp, "Bad pitch value ",
  1447. X            argv[1], (char *)NULL);
  1448. X        return (TCL_ERROR);
  1449. X    }
  1450. X
  1451. X    dgPtr->pitches[y] = pitch;
  1452. X    sprintf(interp->result, "%d", pitch);
  1453. X    return (TCL_OK);
  1454. X}
  1455. X
  1456. static int
  1457. HitRelief(interp, dgPtr, argc, argv, depressed)
  1458. X    Tcl_Interp *interp;
  1459. X    DrumGrid *dgPtr;
  1460. X    int argc;
  1461. X    char **argv;
  1462. X    int depressed;
  1463. X{
  1464. X    char *chk_ptr;
  1465. X    int x;
  1466. X    int y;
  1467. X
  1468. X    x = (int)strtol(argv[0], &chk_ptr, 0);
  1469. X    if (chk_ptr == argv[0]) {
  1470. X        Tcl_AppendResult(interp, "Bad x value: ", argv[0],
  1471. X            (char *)NULL);
  1472. X        return (TCL_ERROR);
  1473. X    }
  1474. X    y = (int)strtol(argv[1], &chk_ptr, 0);
  1475. X    if (chk_ptr == argv[1]) {
  1476. X        Tcl_AppendResult(interp, "Bad y value: ", argv[1],
  1477. X            (char *)NULL);
  1478. X        return (TCL_ERROR);
  1479. X    }
  1480. X    if (x < dgPtr->leftHit || x > dgPtr->rightHit) {
  1481. X        Tcl_AppendResult(interp, "bad x value - not on screen",
  1482. X            (char *)NULL);
  1483. X        return (TCL_ERROR);
  1484. X    }
  1485. X    if (y < dgPtr->topLabel || y > dgPtr->bottomLabel) {
  1486. X        Tcl_AppendResult(interp, "bad y value - not on screen",
  1487. X            (char *)NULL);
  1488. X        return (TCL_ERROR);
  1489. X    }
  1490. X    DrawHit(dgPtr, Tk_WindowId(dgPtr->tkwin), x, y, depressed);
  1491. X    return (TCL_OK);
  1492. X}
  1493. X
  1494. static int
  1495. AddLabel(interp, dgPtr, argc, argv)
  1496. X    Tcl_Interp *interp;
  1497. X    DrumGrid *dgPtr;
  1498. X    int argc;
  1499. X    char **argv;
  1500. X{
  1501. X    int height;
  1502. X    int i;
  1503. X    int j;
  1504. X
  1505. X    if (argc != 1) {
  1506. X        Tcl_AppendResult(interp, "Must specify a label name",
  1507. X            (char *)NULL);
  1508. X        return (TCL_ERROR);
  1509. X    }
  1510. X
  1511. X    if (dgPtr->labels == NULL) {
  1512. X        if ((dgPtr->labels = (char **)ckalloc(sizeof(char *) *
  1513. X            (dgPtr->numLabels + 1))) == NULL) {
  1514. X            Tcl_AppendResult(interp, "Not enough memory for ",
  1515. X                "for new label", (char *)NULL);
  1516. X            return (TCL_ERROR);
  1517. X        }
  1518. X    } else {
  1519. X        if ((dgPtr->labels = (char **)ckrealloc(dgPtr->labels,
  1520. X            sizeof(char *) * (dgPtr->numLabels + 1))) == NULL) {
  1521. X            Tcl_AppendResult(interp, "Not enough memory for ",
  1522. X                "for new label", (char *)NULL);
  1523. X            return (TCL_ERROR);
  1524. X        }
  1525. X    }
  1526. X    if ((dgPtr->labels[dgPtr->numLabels] = ckstrdup(argv[0])) == NULL) {
  1527. X        Tcl_AppendResult(interp, "Couldn't dup label name",
  1528. X            (char *)NULL);
  1529. X        return (TCL_ERROR);
  1530. X    }
  1531. X
  1532. X    /* new Voice */
  1533. X    if (dgPtr->voices == NULL) {
  1534. X        if ((dgPtr->voices = (Voice *)ckalloc(sizeof(Voice) *
  1535. X            dgPtr->numLabels)) == NULL) {
  1536. X            Tcl_AppendResult(interp, "Not enough memory ",
  1537. X                "for voices", (char *)NULL);
  1538. X            return (TCL_ERROR);
  1539. X        }
  1540. X        /* make hits(quanta) inside voices */
  1541. X        for (i = 0; i < dgPtr->numLabels; i++) {
  1542. X            if ((dgPtr->voices[i].volume =
  1543. X                (short *)ckalloc(dgPtr->numHits * sizeof(short)))
  1544. X                == NULL) {
  1545. X                Tcl_AppendResult(interp, "Not enough memory ",
  1546. X                    "for hits in voice", (char *)NULL);
  1547. X                return (TCL_ERROR);
  1548. X            }
  1549. X            for (j = 0; j < dgPtr->numHits; j++)
  1550. X                dgPtr->voices[i].volume[j] = 0;
  1551. X        }
  1552. X    } else {
  1553. X        if ((dgPtr->voices = (Voice *)ckrealloc(dgPtr->voices,
  1554. X            sizeof(Voice) * (dgPtr->numLabels + 1))) == NULL) {
  1555. X            Tcl_AppendResult(interp, "Not enough memory ",
  1556. X                "for voices", (char *)NULL);
  1557. X            return (TCL_ERROR);
  1558. X        }
  1559. X        /* make hits(quanta) inside new voice */
  1560. X        if ((dgPtr->voices[dgPtr->numLabels].volume =
  1561. X            (short *)ckalloc(dgPtr->numHits * sizeof(short))) == NULL) {
  1562. X            Tcl_AppendResult(interp, "Not enough memory ",
  1563. X                "for hits in voice", (char *)NULL);
  1564. X            return (TCL_ERROR);
  1565. X        }
  1566. X        for (j = 0; j < dgPtr->numHits; j++)
  1567. X            dgPtr->voices[dgPtr->numLabels].volume[j] = 0;
  1568. X    }
  1569. X
  1570. X    /* new pitch */
  1571. X    if (dgPtr->pitches == NULL) {
  1572. X        if ((dgPtr->pitches = (int *)ckalloc(dgPtr->numLabels + 1 *
  1573. X            sizeof(int))) == NULL) {
  1574. X            Tcl_AppendResult(interp, "Not enough memory for ",
  1575. X                "new pitch", (char *)NULL);
  1576. X            return (TCL_ERROR);
  1577. X        }
  1578. X        for (j = 0; j < dgPtr->numLabels + 1; j++)
  1579. X            dgPtr->pitches[j] = 0;
  1580. X    } else {
  1581. X        if ((dgPtr->pitches = (int *)ckrealloc(dgPtr->pitches,
  1582. X            sizeof(int) * (dgPtr->numLabels + 1))) == NULL) {
  1583. X            Tcl_AppendResult(interp, "Note enought memory for ",
  1584. X                "new pitch", (char *)NULL);
  1585. X            return (TCL_ERROR);
  1586. X        }
  1587. X        dgPtr->pitches[dgPtr->numLabels] = 0;
  1588. X    }
  1589. X
  1590. X    /* we also need extra bearings */
  1591. X    if (dgPtr->leftBearings == NULL) {
  1592. X        if ((dgPtr->leftBearings = (int *)ckalloc(dgPtr->numLabels + 1
  1593. X            * sizeof(int))) == NULL) {
  1594. X            Tcl_AppendResult(interp, "Not enough memory for ",
  1595. X                "leftBearings", (char *)NULL);
  1596. X            return (TCL_ERROR);
  1597. X        }
  1598. X    } else {
  1599. X        if ((dgPtr->leftBearings = (int *)ckrealloc(dgPtr->leftBearings,
  1600. X            sizeof(int) * (dgPtr->numLabels + 1))) == NULL) {
  1601. X            Tcl_AppendResult(interp, "Note enought memory for ",
  1602. X                "leftBearings", (char *)NULL);
  1603. X            return (TCL_ERROR);
  1604. X        }
  1605. X    }
  1606. X    if (dgPtr->rightBearings == NULL) {
  1607. X        if ((dgPtr->rightBearings = (int *)ckalloc(dgPtr->numLabels + 1
  1608. X            * sizeof(int))) == NULL) {
  1609. X            Tcl_AppendResult(interp, "Not enough memory for ",
  1610. X                "rightBearings", (char *)NULL);
  1611. X            return (TCL_ERROR);
  1612. X        }
  1613. X    } else {
  1614. X        if ((dgPtr->rightBearings =
  1615. X            (int *)ckrealloc(dgPtr->rightBearings, sizeof(int) *
  1616. X            (dgPtr->numLabels + 1))) == NULL) {
  1617. X            Tcl_AppendResult(interp, "Note enought memory for ",
  1618. X                "rightBearings", (char *)NULL);
  1619. X            return (TCL_ERROR);
  1620. X        }
  1621. X    }
  1622. X
  1623. X    dgPtr->numLabels++;
  1624. X
  1625. X    MakeLabelStr(dgPtr);
  1626. X    MakePitchStr(dgPtr);
  1627. X    if (AllocateGridLines(dgPtr) != TCL_OK)
  1628. X        return (TCL_ERROR);
  1629. X
  1630. X    /* we want to include new label in scrolling region */
  1631. X    height = dgPtr->bottomLabel - dgPtr->topLabel;
  1632. X    dgPtr->bottomLabel = dgPtr->numLabels - 1;
  1633. X    dgPtr->topLabel = dgPtr->bottomLabel - height;
  1634. X    dgPtr->flags |= UPDATE_YSCROLL;
  1635. X
  1636. X    ComputeDrumGridGeometry(dgPtr);
  1637. X
  1638. X    return (TCL_OK);
  1639. X}
  1640. X
  1641. static int
  1642. RemoveLabel(interp, dgPtr, argc, argv)
  1643. X    Tcl_Interp *interp;
  1644. X    DrumGrid *dgPtr;
  1645. X    int argc;
  1646. X    char **argv;
  1647. X{
  1648. X    int height;
  1649. X    int i;
  1650. X    int length;
  1651. X    char *chkPtr;
  1652. X
  1653. X    if (argc != 2) {
  1654. X        Tcl_AppendResult(interp, "Must specify \"label\" or \"index\"",
  1655. X            " followed by the label name or the index number",
  1656. X            (char *)NULL);
  1657. X        return (TCL_ERROR);
  1658. X    }
  1659. X
  1660. X    length = strlen(argv[0]);
  1661. X    if (strncmp(argv[0], "label", length) == 0) {
  1662. X        for (i = 0; i < dgPtr->numLabels; i++)
  1663. X            if (strcmp(dgPtr->labels[i], argv[1]) == 0)
  1664. X                break;
  1665. X        if (i == dgPtr->numLabels) {
  1666. X            Tcl_AppendResult(interp, "No label \"", argv[1],
  1667. X                "\" found in drum grid", (char *)NULL);
  1668. X            return (TCL_ERROR);
  1669. X        }
  1670. X    } else if (strncmp(argv[0], "index", length) == 0) {
  1671. X        i = (int)strtol(argv[1], &chkPtr, 0);
  1672. X        if (chkPtr == argv[1] || i < 0 || i >= dgPtr->numLabels) {
  1673. X            Tcl_AppendResult(interp, "Bad index number ",
  1674. X                argv[1], (char *)NULL);
  1675. X            return (TCL_ERROR);
  1676. X        }
  1677. X    } else {
  1678. X        Tcl_AppendResult(interp, "Must specify \"label\" or \"index\".",
  1679. X            (char *)NULL);
  1680. X        return (TCL_ERROR);
  1681. X    }
  1682. X
  1683. X    ckfree(dgPtr->labels[i]);
  1684. X    ckfree((char *)dgPtr->voices[i].volume);
  1685. X
  1686. X    /* move everything up one */
  1687. X    for (; i < dgPtr->numLabels - 1; i++) {
  1688. X        dgPtr->labels[i] = dgPtr->labels[i + 1];
  1689. X        dgPtr->voices[i] = dgPtr->voices[i + 1];
  1690. X        dgPtr->pitches[i] = dgPtr->pitches[i + 1];
  1691. X    }
  1692. X
  1693. X    if (dgPtr->numLabels - 1 == 0) {
  1694. X        ckfree((char *)dgPtr->labels);
  1695. X        dgPtr->labels = NULL;
  1696. X    } else {
  1697. X        if ((dgPtr->labels = (char **)ckrealloc(dgPtr->labels,
  1698. X            sizeof(char *) * (dgPtr->numLabels - 1))) == NULL) {
  1699. X            Tcl_AppendResult(interp, "couldn't realloc label ",
  1700. X                "space", (char *)NULL);
  1701. X            return (TCL_ERROR);
  1702. X        }
  1703. X    }
  1704. X
  1705. X    /* one less voice */
  1706. X    if (dgPtr->numLabels - 1 == 0) {
  1707. X        ckfree((char *)dgPtr->voices);
  1708. X        dgPtr->voices = NULL;
  1709. X    } else {
  1710. X        if ((dgPtr->voices = (Voice *)ckrealloc(dgPtr->voices,
  1711. X            sizeof(Voice) * (dgPtr->numLabels - 1))) == NULL) {
  1712. X            Tcl_AppendResult(interp, "Couldn't realloc ",
  1713. X                "voices", (char *)NULL);
  1714. X            return (TCL_ERROR);
  1715. X        }
  1716. X    }
  1717. X
  1718. X    /* one less pitch */
  1719. X    if (dgPtr->numLabels - 1 == 0) {
  1720. X        ckfree((char *)dgPtr->pitches);
  1721. X        dgPtr->pitches = NULL;
  1722. X    } else {
  1723. X        if ((dgPtr->pitches = (int *)ckrealloc(dgPtr->pitches,
  1724. X            sizeof(int) * (dgPtr->numLabels - 1))) == NULL) {
  1725. X            Tcl_AppendResult(interp, "Couldn't realloc ",
  1726. X                "pitches", (char *)NULL);
  1727. X            return (TCL_ERROR);
  1728. X        }
  1729. X    }
  1730. X    
  1731. X    /* one less on the bearings */
  1732. X    if (dgPtr->numLabels - 1 == 0) {
  1733. X        ckfree((char *)dgPtr->leftBearings);
  1734. X        dgPtr->leftBearings = NULL;
  1735. X    } else {
  1736. X        if ((dgPtr->leftBearings = (int *)ckrealloc(dgPtr->leftBearings,
  1737. X            sizeof(int) * (dgPtr->numLabels - 1))) == NULL) {
  1738. X            Tcl_AppendResult(interp, "Couldn't realloc ",
  1739. X                "leftBearings", (char *)NULL);
  1740. X            return (TCL_ERROR);
  1741. X        }
  1742. X    }
  1743. X    if (dgPtr->numLabels - 1 == 0) {
  1744. X        ckfree((char *)dgPtr->rightBearings);
  1745. X        dgPtr->rightBearings = NULL;
  1746. X    } else {
  1747. X        if ((dgPtr->rightBearings = (int *)
  1748. X            ckrealloc(dgPtr->rightBearings, sizeof(int) *
  1749. X            (dgPtr->numLabels - 1))) == NULL) {
  1750. X            Tcl_AppendResult(interp, "Couldn't realloc ",
  1751. X                "rightBearings", (char *)NULL);
  1752. X            return (TCL_ERROR);
  1753. X        }
  1754. X    }
  1755. X    
  1756. X    dgPtr->numLabels--;
  1757. X
  1758. X    if (AllocateGridLines(dgPtr) != TCL_OK)
  1759. X        return (TCL_ERROR);
  1760. X    MakeLabelStr(dgPtr);
  1761. X    MakePitchStr(dgPtr);
  1762. X
  1763. X    /* make sure we stay in bounds */
  1764. X    if (dgPtr->bottomLabel > dgPtr->numLabels - 1) {
  1765. X        height = dgPtr->bottomLabel - dgPtr->topLabel;
  1766. X        dgPtr->bottomLabel = dgPtr->numLabels - 1;
  1767. X        dgPtr->topLabel = dgPtr->bottomLabel - height;
  1768. X        dgPtr->flags |= UPDATE_YSCROLL;
  1769. X    }
  1770. X
  1771. X    ComputeDrumGridGeometry(dgPtr);
  1772. X
  1773. X    return (TCL_OK);
  1774. X}
  1775. X
  1776. static int
  1777. AllocateGridLines(dgPtr)
  1778. X    DrumGrid *dgPtr;
  1779. X{
  1780. X    Tcl_Interp *interp = dgPtr->interp;
  1781. X
  1782. X    if (dgPtr->vertLineColors != NULL)
  1783. X        ckfree((char *)dgPtr->vertLineColors);
  1784. X    if (dgPtr->vertLinePos != NULL)
  1785. X        ckfree((char *)dgPtr->vertLinePos);
  1786. X    if (dgPtr->horizLineColors != NULL)
  1787. X        ckfree((char *)dgPtr->horizLineColors);
  1788. X    if (dgPtr->horizLinePos != NULL)
  1789. X        ckfree((char *)dgPtr->horizLinePos);
  1790. X
  1791. X    if ((dgPtr->vertLineColors = (GC *)ckalloc(sizeof(GC) *
  1792. X        (dgPtr->numHits + 2))) == NULL) {
  1793. X        Tcl_AppendResult(interp,
  1794. X            "Couldn't allocate new vertLineColors", (char *)NULL);
  1795. X        return (TCL_ERROR);
  1796. X    }
  1797. X    if ((dgPtr->vertLinePos = (XSegment *)ckalloc(sizeof(XSegment) *
  1798. X        (dgPtr->rightHit - dgPtr->leftHit + 3))) == NULL) {
  1799. X        Tcl_AppendResult(interp, "Couldn't allocate new vertLinePos",
  1800. X            (char *)NULL);
  1801. X        return (TCL_ERROR);
  1802. X    }
  1803. X    if ((dgPtr->horizLineColors = (GC *)ckalloc(sizeof(GC) *
  1804. X        (dgPtr->numLabels + 1))) == NULL) {
  1805. X        Tcl_AppendResult(interp,
  1806. X            "Couldn't allocate new horizLineColors", (char *)NULL);
  1807. X        return (TCL_ERROR);
  1808. X    }
  1809. X    if ((dgPtr->horizLinePos = (XSegment *)ckalloc(sizeof(XSegment) *
  1810. X        (dgPtr->bottomLabel - dgPtr->topLabel + 2))) == NULL) {
  1811. X        Tcl_AppendResult(interp, "Couldn't allocate new horizLinePos",
  1812. X            (char *)NULL);
  1813. X        return (TCL_ERROR);
  1814. X    }
  1815. X    return (TCL_OK);
  1816. X}
  1817. X
  1818. static void
  1819. XFitSize(dgPtr)
  1820. X    DrumGrid *dgPtr;
  1821. X{
  1822. X    if (dgPtr->leftHit + dgPtr->resizedWidth <= dgPtr->numHits)
  1823. X        dgPtr->rightHit = dgPtr->leftHit + dgPtr->resizedWidth - 1;
  1824. X    else {
  1825. X        dgPtr->rightHit = dgPtr->numHits - 1;
  1826. X        if ((dgPtr->leftHit = dgPtr->numHits - dgPtr->resizedWidth) < 0)
  1827. X            dgPtr->leftHit = 0;
  1828. X    }
  1829. X    if (dgPtr->topLabel + dgPtr->resizedHeight <= dgPtr->numLabels)
  1830. X        dgPtr->bottomLabel = dgPtr->topLabel + dgPtr->resizedHeight - 1;
  1831. X    else {
  1832. X        dgPtr->bottomLabel = dgPtr->numLabels - 1;
  1833. X        if ((dgPtr->topLabel = dgPtr->numLabels - dgPtr->resizedHeight)
  1834. X            < 0)
  1835. X            dgPtr->topLabel = 0;
  1836. X    }
  1837. X}
  1838. X
  1839. static void
  1840. ChangeDrumGridLeft(dgPtr, index)
  1841. X    DrumGrid *dgPtr;
  1842. X    int index;
  1843. X{
  1844. X    int width;
  1845. X
  1846. X    width = dgPtr->rightHit - dgPtr->leftHit + 1;
  1847. X
  1848. X    if (index > dgPtr->numHits - width)
  1849. X        index = dgPtr->numHits - width;
  1850. X    if (index < 0)
  1851. X        index = 0;
  1852. X
  1853. X    if (dgPtr->leftHit != index) {
  1854. X        dgPtr->leftHit = index;
  1855. X        dgPtr->rightHit = index + width - 1;
  1856. X        if (!(dgPtr->flags & REDRAW_PENDING)) {
  1857. X            Tk_DoWhenIdle(DisplayDrumGrid, (ClientData)dgPtr);
  1858. X            dgPtr->flags |= REDRAW_PENDING;
  1859. X        }
  1860. X        dgPtr->flags |= UPDATE_XSCROLL;
  1861. X    }
  1862. X}
  1863. X
  1864. static void
  1865. ChangeDrumGridTop(dgPtr, index)
  1866. X    DrumGrid *dgPtr;
  1867. X    int index;
  1868. X{
  1869. X    int height;
  1870. X
  1871. X    height = dgPtr->bottomLabel - dgPtr->topLabel + 1;
  1872. X
  1873. X    if (index > dgPtr->numLabels - height)
  1874. X        index = dgPtr->numLabels - height;
  1875. X    if (index < 0)
  1876. X        index = 0;
  1877. X
  1878. X    if (dgPtr->topLabel != index) {
  1879. X        dgPtr->topLabel = index;
  1880. X        dgPtr->bottomLabel = index + height - 1;
  1881. X        if (!(dgPtr->flags & REDRAW_PENDING)) {
  1882. X            Tk_DoWhenIdle(DisplayDrumGrid, (ClientData)dgPtr);
  1883. X            dgPtr->flags |= REDRAW_PENDING;
  1884. X        }
  1885. X        dgPtr->flags |= UPDATE_YSCROLL;
  1886. X    }
  1887. X}
  1888. X
  1889. static void
  1890. DrumGridUpdateXScroll(dgPtr)
  1891. X    DrumGrid *dgPtr;
  1892. X{
  1893. X    char string[60];
  1894. X    int num_showing;
  1895. X
  1896. X    if (dgPtr->xScrollCmd == NULL)
  1897. X        return;
  1898. X
  1899. X    num_showing = dgPtr->rightHit - dgPtr->leftHit + 1;
  1900. X    sprintf(string, " %d %d %d %d", dgPtr->numHits, num_showing,
  1901. X        dgPtr->leftHit, dgPtr->rightHit);
  1902. X
  1903. X    if (Tcl_VarEval(dgPtr->interp, dgPtr->xScrollCmd, string,
  1904. X        (char *)NULL) != TCL_OK)
  1905. X        Tk_BackgroundError(dgPtr->interp);
  1906. X}
  1907. X
  1908. static void
  1909. DrumGridUpdateYScroll(dgPtr)
  1910. X    DrumGrid *dgPtr;
  1911. X{
  1912. X    char string[60];
  1913. X    int num_showing;
  1914. X
  1915. X    if (dgPtr->yScrollCmd == NULL)
  1916. X        return;
  1917. X
  1918. X    num_showing = dgPtr->bottomLabel - dgPtr->topLabel + 1;
  1919. X    sprintf(string, " %d %d %d %d", dgPtr->numLabels, num_showing,
  1920. X        dgPtr->topLabel, dgPtr->bottomLabel);
  1921. X
  1922. X    if (Tcl_VarEval(dgPtr->interp, dgPtr->yScrollCmd, string,
  1923. X        (char *)NULL) != TCL_OK)
  1924. X        Tk_BackgroundError(dgPtr->interp);
  1925. X}
  1926. X
  1927. static int
  1928. GetLabels(interp, dgPtr, argc, argv)
  1929. X    Tcl_Interp *interp;
  1930. X    DrumGrid *dgPtr;
  1931. X    int argc;
  1932. X    char **argv;
  1933. X{
  1934. X    int i;
  1935. X
  1936. X    for (i = 0; i < dgPtr->numLabels; i++)
  1937. X        Tcl_AppendElement(interp, dgPtr->labels[i], 0);
  1938. X
  1939. X    return (TCL_OK);
  1940. X}
  1941. X
  1942. static int
  1943. ListPitches(interp, dgPtr, argc, argv)
  1944. X    Tcl_Interp *interp;
  1945. X    DrumGrid *dgPtr;
  1946. X    int argc;
  1947. X    char **argv;
  1948. X{
  1949. X    int i;
  1950. X    char dummy[10];
  1951. X
  1952. X    for (i = 0; i < dgPtr->numLabels; i++) {
  1953. X        sprintf(dummy, "%d", dgPtr->pitches[i]);
  1954. X        Tcl_AppendElement(interp, dummy, 0);
  1955. X    }
  1956. X
  1957. X    return (TCL_OK);
  1958. X}
  1959. X
  1960. static void
  1961. MakeLabelStr(dgPtr)
  1962. X    DrumGrid *dgPtr;
  1963. X{
  1964. X    Tcl_Interp *temp_interp;
  1965. X    int i;
  1966. X
  1967. X    temp_interp = Tcl_CreateInterp();
  1968. X    for (i = 0; i < dgPtr->numLabels; i++)
  1969. X        Tcl_AppendElement(temp_interp, dgPtr->labels[i], 0);
  1970. X
  1971. X    if (dgPtr->labelStr != NULL)
  1972. X        ckfree(dgPtr->labelStr);
  1973. X    dgPtr->labelStr = ckstrdup(temp_interp->result);
  1974. X
  1975. X    Tcl_DeleteInterp(temp_interp);
  1976. X}
  1977. X
  1978. static void
  1979. MakePitchStr(dgPtr)
  1980. X    DrumGrid *dgPtr;
  1981. X{
  1982. X    Tcl_Interp *temp_interp;
  1983. X    int i;
  1984. X    char dummy[10];
  1985. X
  1986. X    temp_interp = Tcl_CreateInterp();
  1987. X    for (i = 0; i < dgPtr->numLabels; i++) {
  1988. X        sprintf(dummy, "%d", dgPtr->pitches[i]);
  1989. X        Tcl_AppendElement(temp_interp, dummy, 0);
  1990. X    }
  1991. X
  1992. X    if (dgPtr->labelStr != NULL)
  1993. X        ckfree(dgPtr->pitchStr);
  1994. X    dgPtr->pitchStr = ckstrdup(temp_interp->result);
  1995. X
  1996. X    Tcl_DeleteInterp(temp_interp);
  1997. X}
  1998. X
  1999. char *
  2000. Tclm_DbCkstrdup(str)
  2001. X    char *str;
  2002. X{
  2003. X    char *new_str;
  2004. X
  2005. X    if (str == NULL)
  2006. X        return (NULL);
  2007. X    if ((new_str = ckalloc(strlen(str) + 1)) == NULL)
  2008. X        return (NULL);
  2009. X    strcpy(new_str, str);
  2010. X    return (new_str);
  2011. X}
  2012. END_OF_FILE
  2013. if test 54953 -ne `wc -c <'xdrum-1.0/tkmGrid.c'`; then
  2014.     echo shar: \"'xdrum-1.0/tkmGrid.c'\" unpacked with wrong size!
  2015. fi
  2016. # end of 'xdrum-1.0/tkmGrid.c'
  2017. fi
  2018. echo shar: End of archive 2 \(of 2\).
  2019. cp /dev/null ark2isdone
  2020. MISSING=""
  2021. for I in 1 2 ; do
  2022.     if test ! -f ark${I}isdone ; then
  2023.     MISSING="${MISSING} ${I}"
  2024.     fi
  2025. done
  2026. if test "${MISSING}" = "" ; then
  2027.     echo You have unpacked both archives.
  2028.     rm -f ark[1-9]isdone
  2029. else
  2030.     echo You still need to unpack the following archives:
  2031.     echo "        " ${MISSING}
  2032. fi
  2033. ##  End of shell archive.
  2034. exit 0
  2035.  
  2036. exit 0 # Just in case...
  2037.