home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / lang / tcl / 2353 < prev    next >
Encoding:
Internet Message Format  |  1993-01-12  |  27.2 KB

  1. Path: sparky!uunet!olivea!spool.mu.edu!agate!boulder!csn!cherokee!durian
  2. From: durian@advtech.uswest.com (Mike Durian)
  3. Newsgroups: comp.lang.tcl
  4. Subject: tclm0.1 - tcl with MIDI extensions (1/7)
  5. Message-ID: <1993Jan12.202709.19721@advtech.uswest.com>
  6. Date: 12 Jan 93 20:27:09 GMT
  7. Sender: news@advtech.uswest.com (Radio Free Boulder)
  8. Organization: U S WEST Advanced Technologies
  9. Lines: 990
  10. Nntp-Posting-Host: mongo.advtech.uswest.com
  11.  
  12. # This is a shell archive.  Save it in a file, remove anything before
  13. # this line, and then unpack it by entering "sh file".  Note, it may
  14. # create directories; files and directories will be owned by you and
  15. # have default permissions.
  16. #
  17. # This archive contains:
  18. #
  19. #    tclm0.1
  20. #    tclm0.1/README
  21. #    tclm0.1/tclm.h
  22. #    tclm0.1/tclmCmd.c
  23. #
  24. echo c - tclm0.1
  25. mkdir tclm0.1 > /dev/null 2>&1
  26. echo x - tclm0.1/README
  27. sed 's/^X//' >tclm0.1/README << 'END-of-tclm0.1/README'
  28. X1/11/93
  29. X  This is the first release, 0.1, of tclm.  Tclm is simply a
  30. Xtcl interpreter with extensions for the manipulation of
  31. XStandard MIDI Files.  In the most basic form tclm allows
  32. Xyou to read, write and create SMFs as well as get and put events.
  33. XThere are also additional commands that help manipulate
  34. Xindividual events.
  35. X  As a special bonus tclm contains a command to play
  36. XSMFs.  Unfortunately, this is only available on BSD/386
  37. Xsystems equiped with a MPU-401 compatible MIDI card
  38. Xas it uses the MPU-401 MIDI device driver.
  39. X  Compilation should be fairly straight forward.  Just
  40. Xedit the Makefile and adjust TCLSRCDIR, DEFS, RANLIB
  41. Xand BINDIR as appropriate for your system.  A 'make'
  42. Xand a 'make install' should do it then.  Be sure
  43. Xto change the first line on mplay and minfo to point
  44. Xto the correct location of your tclm.
  45. X  I have included a small patch for BSD/386 systems.  There
  46. Xare conflicts between the tcl setenv command and the
  47. Xsystem setenv command.  The patch merely changes the tcl
  48. Xsetenv and unsetenv to be called Setenv and Unsetenv
  49. Xrespectively.  The patch was made from the tk3.0 directory,
  50. Xbut you should be able to wing it if you need to.
  51. X'patch -p < bsdi.patch' worked for me.
  52. X  If you do build on a BSD/386 system with MPU defined,
  53. Xbe sure you have set up a symbolic link between
  54. X/usr/src/sys/i386 and /usr/include/i386.
  55. X  Besides the tclm interpreter there are also two sample
  56. Xscripts.  One, minfo, dumps SMFs to a human readable form
  57. Xand should works on all systems.  The other, mplay, plays
  58. XSMFs and will only work on systems with the MPU-401 routines,
  59. Xname BSD/386 machines.
  60. X  I imagine people won't like me for it, but I've written
  61. Xthe man pages with the mdoc routines.  Because of this I'm
  62. Xincluding preformatted man pages and do not install them
  63. Xin the Makefile.
  64. X  Keep in mind that this is the first release; I'm sure
  65. Xthere are numerous bugs.  Please send me all ideas, fixes,
  66. Xbugs and interesting scripts.
  67. X
  68. XMike Durian - durian@advtech.uswest.com
  69. END-of-tclm0.1/README
  70. echo x - tclm0.1/tclm.h
  71. sed 's/^X//' >tclm0.1/tclm.h << 'END-of-tclm0.1/tclm.h'
  72. X/* tclm.h,v 1.3 1993/01/12 19:23:04 durian Exp */
  73. X/*
  74. X * Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  75. X *
  76. X * Redistribution and use in source and binary forms, with or without
  77. X * modification, are permitted provided that the following conditions
  78. X * are met:
  79. X * 1. Redistributions of source code must retain the above copyright
  80. X *    notice, this list of conditions and the following disclaimer.
  81. X * 2. Redistributions in binary form must reproduce the above copyright
  82. X *    notice, this list of conditions and the following disclaimer in the
  83. X *    documentation and/or other materials provided with the distribution.
  84. X * 3. All advertising materials mentioning features or use of this software
  85. X *    must display the following acknowledgement:
  86. X *    This product includes software developed by Michael B. Durian.
  87. X * 4. The name of the the Author may be used to endorse or promote 
  88. X *    products derived from this software without specific prior written 
  89. X *    permission.
  90. X *
  91. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  92. X * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  93. X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  94. X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  95. X * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  96. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  97. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  98. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  99. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  100. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  101. X * SUCH DAMAGE.
  102. X */
  103. X#ifndef TCLM_H
  104. X#define TCLM_H
  105. Xtypedef struct {
  106. X    HCHUNK    hchunk;
  107. X    TCHUNK    *tchunks;
  108. X} MIDI_FILE;
  109. X
  110. X#define MAX_EVENT_SIZE 256
  111. X
  112. Xextern int Tclm_MidiConfig _ANSI_ARGS_((ClientData, Tcl_Interp *, int,
  113. X    char **));
  114. Xextern int Tclm_ConvertBytes _ANSI_ARGS_((Tcl_Interp *, char *,
  115. X    unsigned char *, int *));
  116. Xextern int Tclm_Division _ANSI_ARGS_((Tcl_Interp *, int, char **));
  117. Xextern int Tclm_MidiFixToVar _ANSI_ARGS_((ClientData, Tcl_Interp *, int,
  118. X    char **));
  119. Xextern int Tclm_Format _ANSI_ARGS_((Tcl_Interp *, int, char **));
  120. Xextern int Tclm_MidiFree _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **));
  121. Xextern int Tclm_MidiGet _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **));
  122. Xextern int Tclm_MidiPut _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **));
  123. Xextern int Tclm_GetMFile _ANSI_ARGS_((Tcl_Interp *, char *, MIDI_FILE **));
  124. Xextern void Tclm_InitMidi _ANSI_ARGS_((Tcl_Interp *));
  125. Xextern int Tclm_MidiMake _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **));
  126. Xextern int Tclm_NumTracks _ANSI_ARGS_((Tcl_Interp *, int, char **));
  127. Xextern int Tclm_MidiRead _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **));
  128. Xextern int Tclm_MidiRewind _ANSI_ARGS_((ClientData, Tcl_Interp *, int,
  129. X    char **));
  130. Xextern int Tclm_SetMFile _ANSI_ARGS_((Tcl_Interp *, char *, MIDI_FILE *));
  131. Xextern int Tclm_MidiTiming _ANSI_ARGS_((ClientData, Tcl_Interp *, int,
  132. X    char **));
  133. Xextern int Tclm_MidiVarToFix _ANSI_ARGS_((ClientData, Tcl_Interp *, int,
  134. X    char **));
  135. Xextern int Tclm_MidiWrite _ANSI_ARGS_((ClientData, Tcl_Interp *, int,
  136. X    char **));
  137. Xextern int Tclm_MidiMPU _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **));
  138. X#endif
  139. END-of-tclm0.1/tclm.h
  140. echo x - tclm0.1/tclmCmd.c
  141. sed 's/^X//' >tclm0.1/tclmCmd.c << 'END-of-tclm0.1/tclmCmd.c'
  142. X/* tclmCmd.c,v 1.3 1993/01/12 19:23:08 durian Exp */
  143. X/*
  144. X * Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  145. X *
  146. X * Redistribution and use in source and binary forms, with or without
  147. X * modification, are permitted provided that the following conditions
  148. X * are met:
  149. X * 1. Redistributions of source code must retain the above copyright
  150. X *    notice, this list of conditions and the following disclaimer.
  151. X * 2. Redistributions in binary form must reproduce the above copyright
  152. X *    notice, this list of conditions and the following disclaimer in the
  153. X *    documentation and/or other materials provided with the distribution.
  154. X * 3. All advertising materials mentioning features or use of this software
  155. X *    must display the following acknowledgement:
  156. X *    This product includes software developed by Michael B. Durian.
  157. X * 4. The name of the the Author may be used to endorse or promote 
  158. X *    products derived from this software without specific prior written 
  159. X *    permission.
  160. X *
  161. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  162. X * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  163. X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  164. X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  165. X * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  166. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  167. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  168. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  169. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  170. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  171. X * SUCH DAMAGE.
  172. X */
  173. X#include "tclInt.h"
  174. X#include "tclUnix.h"
  175. X#include "mutil.h"
  176. X#include "tclm.h"
  177. X
  178. X
  179. XTcl_HashTable MidiFileHash;
  180. Xstatic int mfileId = 0;
  181. X
  182. Xvoid
  183. XTclm_InitMidi(interp)
  184. X    Tcl_Interp *interp;
  185. X{
  186. X
  187. X    Tcl_CreateCommand(interp, "midiconfig", Tclm_MidiConfig, NULL, NULL);
  188. X    Tcl_CreateCommand(interp, "midiread", Tclm_MidiRead, NULL, NULL);
  189. X    Tcl_CreateCommand(interp, "midiwrite", Tclm_MidiWrite, NULL, NULL);
  190. X    Tcl_CreateCommand(interp, "midimake", Tclm_MidiMake, NULL, NULL);
  191. X    Tcl_CreateCommand(interp, "midifree", Tclm_MidiFree, NULL, NULL);
  192. X    Tcl_CreateCommand(interp, "midirewind", Tclm_MidiRewind, NULL, NULL);
  193. X
  194. X    Tcl_CreateCommand(interp, "midifixtovar", Tclm_MidiFixToVar, NULL,
  195. X        NULL);
  196. X    Tcl_CreateCommand(interp, "midivartofix", Tclm_MidiVarToFix, NULL,
  197. X        NULL);
  198. X    Tcl_CreateCommand(interp, "midiget", Tclm_MidiGet, NULL, NULL);
  199. X    Tcl_CreateCommand(interp, "midiput", Tclm_MidiPut, NULL, NULL);
  200. X    Tcl_CreateCommand(interp, "miditiming", Tclm_MidiTiming, NULL, NULL);
  201. X    Tcl_CreateCommand(interp, "midimpu", Tclm_MidiMPU, NULL, NULL);
  202. X    Tcl_InitHashTable(&MidiFileHash, TCL_ONE_WORD_KEYS);
  203. X}
  204. X
  205. X
  206. Xint
  207. XTclm_MidiConfig(dummy, interp, argc, argv)
  208. X    ClientData dummy;
  209. X    Tcl_Interp *interp;
  210. X    int argc;
  211. X    char **argv;
  212. X{
  213. X    int length;
  214. X    int result;
  215. X
  216. X    /*
  217. X     * argv[0] - midiconfig
  218. X     * argv[1] - mfileID
  219. X     * argv[2] - format | division | tracks
  220. X     * argv[3] - optional arg
  221. X     */
  222. X    result = TCL_OK;
  223. X    if (argc < 3 || argc > 4) {
  224. X        Tcl_AppendResult(interp, "wrong # args: should be \"",
  225. X            argv[0], "mfileId {format | division | tracks} ?arg?\"",
  226. X            (char *)NULL);
  227. X        return (TCL_ERROR);
  228. X    }
  229. X
  230. X    length = strlen(argv[2]);
  231. X    switch(argv[2][0]) {
  232. X    case 'd':
  233. X        if (strncmp(argv[2], "division", length) == 0)
  234. X            result = Tclm_Division(interp, argc, argv);
  235. X        else {
  236. X            Tcl_AppendResult(interp, "bad option, ", argv[2],
  237. X                ", must be one of format, division or tracks",
  238. X                (char *)NULL);
  239. X            return (TCL_ERROR);
  240. X        }
  241. X        break;
  242. X    case 'f':
  243. X        if (strncmp(argv[2], "format", length) == 0)
  244. X            result = Tclm_Format(interp, argc, argv);
  245. X        else {
  246. X            Tcl_AppendResult(interp, "bad option, ", argv[2],
  247. X                ", must be one of format, division or tracks",
  248. X                (char *)NULL);
  249. X            return (TCL_ERROR);
  250. X        }
  251. X        break;
  252. X    case 't':
  253. X        if (strncmp(argv[2], "tracks", length) == 0)
  254. X            result = Tclm_NumTracks(interp, argc, argv);
  255. X        else {
  256. X            Tcl_AppendResult(interp, "bad option, ", argv[2],
  257. X                ", must be one of format, division or tracks",
  258. X                (char *)NULL);
  259. X            return (TCL_ERROR);
  260. X        }
  261. X        break;
  262. X    default:
  263. X        Tcl_AppendResult(interp, "bad option, ", argv[2],
  264. X            ", must be one of format, division or tracks",
  265. X            (char *)NULL);
  266. X        return (TCL_ERROR);
  267. X    }
  268. X
  269. X    return (result);
  270. X}
  271. X
  272. Xint
  273. XTclm_MidiMake(dummy, interp, argc, argv)
  274. X    ClientData dummy;
  275. X    Tcl_Interp *interp;
  276. X    int argc;
  277. X    char **argv;
  278. X{
  279. X    MIDI_FILE *mfile;
  280. X    Tcl_HashEntry *hash_entry;
  281. X    int fd;
  282. X    int i;
  283. X    int created_hash;
  284. X    char num_str[20];
  285. X
  286. X    /*
  287. X     * argv[0] - midimake
  288. X     */
  289. X    if (argc != 1) {
  290. X        Tcl_AppendResult(interp, "bad # args: should be \"",
  291. X            argv[0], "\"", (char *)NULL);
  292. X        return (TCL_ERROR);
  293. X    }
  294. X    if ((mfile = (MIDI_FILE *)malloc(sizeof(MIDI_FILE))) == NULL) {
  295. X        Tcl_AppendResult(interp, "Not enough memory for MIDI file",
  296. X            (char *)NULL);
  297. X        return (TCL_ERROR);
  298. X    }
  299. X    strncpy(mfile->hchunk.str, "MThd", 4);
  300. X    mfile->hchunk.length = 6;
  301. X    mfile->hchunk.format = 1;
  302. X    mfile->hchunk.division = 120;
  303. X    mfile->hchunk.num_trks = 0;
  304. X    mfile->tchunks = NULL;
  305. X
  306. X    hash_entry = Tcl_CreateHashEntry(&MidiFileHash, (char *)mfileId,
  307. X        &created_hash);
  308. X    if (!created_hash) {
  309. X        Tcl_AppendResult(interp, "Hash bucket for file alread ",
  310. X            "exists", (char *)NULL);
  311. X        return (TCL_ERROR);
  312. X    }
  313. X    Tcl_SetHashValue(hash_entry, mfile);
  314. X
  315. X    sprintf(interp->result, "mfile%d", mfileId++);
  316. X    return (TCL_OK);
  317. X}
  318. X
  319. Xint
  320. XTclm_MidiRead(dummy, interp, argc, argv)
  321. X    ClientData dummy;
  322. X    Tcl_Interp *interp;
  323. X    int argc;
  324. X    char **argv;
  325. X{
  326. X    MIDI_FILE *mfile;
  327. X    OpenFile *filePtr;
  328. X    Tcl_HashEntry *hash_entry;
  329. X    int created_hash;
  330. X    int fd;
  331. X    int i;
  332. X    int result;
  333. X    char num_str[20];
  334. X
  335. X    /*
  336. X     * argv[0] - midiread
  337. X     * argv[1] - open file descriptor
  338. X     */
  339. X    if (argc != 2) {
  340. X        Tcl_AppendResult(interp, "bad # args: should be \"",
  341. X            argv[0], " fileId\"", (char *)NULL);
  342. X        return (TCL_ERROR);
  343. X    }
  344. X    if ((result = TclGetOpenFile(interp, argv[1], &filePtr)) != TCL_OK)
  345. X        return (result);
  346. X
  347. X    fd = fileno(filePtr->f);
  348. X    if ((mfile = (MIDI_FILE *)malloc(sizeof(MIDI_FILE))) == NULL) {
  349. X        Tcl_AppendResult(interp, "Not enough memory for MIDI file",
  350. X            (char *)NULL);
  351. X        return (TCL_ERROR);
  352. X    }
  353. X    if (!read_header_chunk(fd, &mfile->hchunk)) {
  354. X        if (MidiEof)
  355. X            Tcl_AppendResult(interp, "EOF");
  356. X        else
  357. X            Tcl_AppendResult(interp,
  358. X                "Couldn't read header chunk\n", MidiError,
  359. X                (char *)NULL);
  360. X        return (TCL_ERROR);
  361. X    }
  362. X    if ((mfile->tchunks = (TCHUNK *)malloc(mfile->hchunk.num_trks *
  363. X        sizeof(TCHUNK))) == NULL) {
  364. X        Tcl_AppendResult(interp, "Not enough memory for track ",
  365. X            "chunks", (char *)NULL);
  366. X        return (TCL_ERROR);
  367. X    }
  368. X
  369. X    for (i = 0;  i < mfile->hchunk.num_trks; i++) {
  370. X        if (!read_track_chunk(fd, &(mfile->tchunks[i]))) {
  371. X            sprintf(num_str, "%d", i);
  372. X            Tcl_AppendResult(interp, "Couldn't read track ",
  373. X                "number ",  num_str, "\n", MidiError,
  374. X                (char *)NULL);
  375. X            return (TCL_ERROR);
  376. X        }
  377. X    }
  378. X    hash_entry = Tcl_CreateHashEntry(&MidiFileHash, (char *)mfileId,
  379. X        &created_hash);
  380. X    if (!created_hash) {
  381. X        Tcl_AppendResult(interp, "Hash bucket for file alread ",
  382. X            "exists", (char *)NULL);
  383. X        return (TCL_ERROR);
  384. X    }
  385. X    Tcl_SetHashValue(hash_entry, mfile);
  386. X
  387. X    sprintf(interp->result, "mfile%d", mfileId++);
  388. X    return (TCL_OK);
  389. X}
  390. X
  391. Xint
  392. XTclm_MidiWrite(dummy, interp, argc, argv)
  393. X    ClientData dummy;
  394. X    Tcl_Interp *interp;
  395. X    int argc;
  396. X    char **argv;
  397. X{
  398. X    MIDI_FILE *mfile;
  399. X    OpenFile *filePtr;
  400. X    Tcl_HashEntry *hash_entry;
  401. X    int fd;
  402. X    int i;
  403. X    int result;
  404. X    char num_str[20];
  405. X
  406. X    /*
  407. X     * argv[0] - midiwrite
  408. X     * argv[1] - mfileId
  409. X     * argv[2] - fileId
  410. X     */
  411. X    if (argc != 3) {
  412. X        Tcl_AppendResult(interp, "bad # args: shoudl be \"",
  413. X            argv[0], " mfileId fileId\"", (char *)NULL);
  414. X        return (TCL_ERROR);
  415. X    }
  416. X    if ((result = TclGetOpenFile(interp, argv[2], &filePtr)) != TCL_OK)
  417. X        return (result);
  418. X
  419. X    if ((result = Tclm_GetMFile(interp, argv[1], &mfile)) != TCL_OK)
  420. X        return (result);
  421. X
  422. X    fd = fileno(filePtr->f);
  423. X
  424. X    if (!write_header_chunk(fd, &mfile->hchunk)) {
  425. X        Tcl_AppendResult(interp, "Couldn't write header chunk\n",
  426. X            MidiError, (char *)NULL);
  427. X        return (TCL_ERROR);
  428. X    }
  429. X    for (i = 0; i < mfile->hchunk.num_trks; i++) {
  430. X        if (!write_track_chunk(fd, &(mfile->tchunks[i]))) {
  431. X            sprintf(interp->result,
  432. X                "Coudln't write track chunk %d\n%s", i,
  433. X                MidiError);
  434. X            return (TCL_ERROR);
  435. X        }
  436. X    }
  437. X    return (TCL_OK);
  438. X}
  439. X
  440. Xint
  441. XTclm_MidiFree(dummy, interp, argc, argv)
  442. X    ClientData dummy;
  443. X    Tcl_Interp *interp;
  444. X    int argc;
  445. X    char **argv;
  446. X{
  447. X    MIDI_FILE *mfile;
  448. X    int mfileId;
  449. X    int result;
  450. X
  451. X    /*
  452. X     * argv[0] - midifree
  453. X     * argv[1] - mfileId
  454. X     */
  455. X    if (argc != 2) {
  456. X        Tcl_AppendResult(interp, "bad # args: should be \"",
  457. X            argv[0], " mfileId\"", (char *)NULL);
  458. X        return (TCL_ERROR);
  459. X    }
  460. X
  461. X    if ((result = Tclm_GetMFile(interp, argv[1], &mfile)) != TCL_OK)
  462. X        return (result);
  463. X
  464. X    mfileId = (int)strtol(argv[1] + 5, NULL, 0);
  465. X    Tcl_DeleteHashEntry(Tcl_FindHashEntry(&MidiFileHash, (char *)mfileId));
  466. X
  467. X    free(mfile->tchunks);
  468. X    free(mfile);
  469. X    return (TCL_OK);
  470. X}
  471. X
  472. Xint
  473. XTclm_GetMFile(interp, FileId, mfile)
  474. X    Tcl_Interp *interp;
  475. X    char *FileId;
  476. X    MIDI_FILE **mfile;
  477. X{
  478. X    Tcl_HashEntry *hash_entry;
  479. X    char *chk_ptr;
  480. X    int mfileId;
  481. X
  482. X    if (strncmp(FileId, "mfile", 5) != 0) {
  483. X        Tcl_AppendResult(interp, "Bad MIDI file identifier \"",
  484. X            FileId, "\"", (char *)NULL);
  485. X        return (TCL_ERROR);
  486. X    }
  487. X
  488. X    mfileId = (int)strtol(FileId + 5, &chk_ptr, 0);
  489. X    if (chk_ptr == FileId + 5) {
  490. X        Tcl_AppendResult(interp, "Bad MIDI file identifier \"",
  491. X            FileId, "\"", (char *)NULL);
  492. X        return (TCL_ERROR);
  493. X    }
  494. X    if ((hash_entry = Tcl_FindHashEntry(&MidiFileHash, (char *)mfileId))
  495. X        == NULL) {
  496. X        Tcl_AppendResult(interp, FileId, " doesn't exist",
  497. X            (char *)NULL);
  498. X        return (TCL_ERROR);
  499. X    }
  500. X    *mfile = (MIDI_FILE *)Tcl_GetHashValue(hash_entry);
  501. X    return (TCL_OK);
  502. X}
  503. X
  504. Xint
  505. XTclm_SetMFile(interp, FileId, mfile)
  506. X    Tcl_Interp *interp;
  507. X    char *FileId;
  508. X    MIDI_FILE *mfile;
  509. X{
  510. X    Tcl_HashEntry *hash_entry;
  511. X    char *chk_ptr;
  512. X    int mfileId;
  513. X
  514. X    if (strncmp(FileId, "mfile", 5) != 0) {
  515. X        Tcl_AppendResult(interp, "Bad MIDI file identifier \"",
  516. X            FileId, "\"", (char *)NULL);
  517. X        return (TCL_ERROR);
  518. X    }
  519. X
  520. X    mfileId = (int)strtol(FileId + 5, &chk_ptr, 0);
  521. X    if (chk_ptr == FileId + 5) {
  522. X        Tcl_AppendResult(interp, "Bad MIDI file identifier \"",
  523. X            FileId, "\"", (char *)NULL);
  524. X        return (TCL_ERROR);
  525. X    }
  526. X    if ((hash_entry = Tcl_FindHashEntry(&MidiFileHash, (char *)mfileId))
  527. X        == NULL) {
  528. X        Tcl_AppendResult(interp, FileId, " doesn't exist",
  529. X            (char *)NULL);
  530. X        return (TCL_ERROR);
  531. X    }
  532. X    Tcl_SetHashValue(hash_entry, (char *)mfile);
  533. X    return (TCL_OK);
  534. X}
  535. X
  536. Xint
  537. XTclm_NumTracks(interp, argc, argv)
  538. X    Tcl_Interp *interp;
  539. X    int argc;
  540. X    char **argv;
  541. X{
  542. X    MIDI_FILE *mfile;
  543. X    char *chk_ptr;
  544. X    int i;
  545. X    int result;
  546. X    int num_trks;
  547. X
  548. X    /*
  549. X     * argv[0] - midiconfig
  550. X     * argv[1] - mfileId
  551. X     * argv[2] - tracks
  552. X     * argv[3] - optional number of tracks
  553. X     */
  554. X    if ((result = Tclm_GetMFile(interp, argv[1], &mfile)) != TCL_OK)
  555. X        return (result);
  556. X
  557. X    if (argc == 3)
  558. X        sprintf(interp->result, "%d", mfile->hchunk.num_trks);
  559. X    else {
  560. X        num_trks = (int)strtol(argv[3], &chk_ptr, 0);
  561. X        if (chk_ptr == argv[3]) {
  562. X            Tcl_AppendResult(interp, "Bad number of tracks ",
  563. X                argv[3], (char *)NULL);
  564. X            return (TCL_ERROR);
  565. X        }
  566. X        if (mfile->hchunk.format == 0 && num_trks != 1) {
  567. X            Tcl_AppendResult(interp, "Format 0 files can only ",
  568. X                "have one track, not ", argv[3], (char *)NULL);
  569. X            return (TCL_ERROR);
  570. X        }
  571. X        if (mfile->tchunks == NULL) {
  572. X            if (num_trks != 0) {
  573. X                if ((mfile->tchunks = (TCHUNK *)malloc(
  574. X                    sizeof(TCHUNK) * num_trks)) == NULL) {
  575. X                    Tcl_AppendResult(interp,
  576. X                        "Not enough memory for ", argv[3],
  577. X                        " tracks", (char *)NULL);
  578. X                }
  579. X            }
  580. X        } else {
  581. X            if (num_trks == 0) {
  582. X                free((char *)mfile->tchunks);
  583. X                mfile->tchunks = NULL;
  584. X            } else {
  585. X                if ((mfile->tchunks = (TCHUNK *)realloc(
  586. X                    mfile->tchunks, sizeof(TCHUNK) * num_trks))
  587. X                    == NULL) {
  588. X                    Tcl_AppendResult(interp,
  589. X                        "Not enough memory for ", argv[3],
  590. X                        " tracks", (char *)NULL);
  591. X                }
  592. X            }
  593. X        }
  594. X
  595. X        for (i = mfile->hchunk.num_trks; i < num_trks; i++) {
  596. X            mfile->tchunks[i].event_start = NULL;
  597. X            mfile->tchunks[i].events = NULL;
  598. X            mfile->tchunks[i].msize = 0;
  599. X            mfile->tchunks[i].length = 0;
  600. X            mfile->tchunks[i].pos = 0;
  601. X            strncpy(mfile->tchunks[i].str, "MTrk", 4);
  602. X        }
  603. X
  604. X        mfile->hchunk.num_trks = num_trks;
  605. X        if ((result = Tclm_SetMFile(interp, argv[1], mfile)) !=
  606. X            TCL_OK)
  607. X            return (result);
  608. X    }
  609. X    return (TCL_OK);
  610. X}
  611. X
  612. Xint
  613. XTclm_Format(interp, argc, argv)
  614. X    Tcl_Interp *interp;
  615. X    int argc;
  616. X    char **argv;
  617. X{
  618. X    MIDI_FILE *mfile;
  619. X    char *chk_ptr;
  620. X    int result;
  621. X    int format;
  622. X
  623. X    /*
  624. X     * argv[0] - midiconfig
  625. X     * argv[1] - mfileId
  626. X     * argv[2] - format
  627. X     * argv[3] - optional arg
  628. X     */
  629. X
  630. X    if ((result = Tclm_GetMFile(interp, argv[1], &mfile)) != TCL_OK)
  631. X        return (result);
  632. X
  633. X    if (argc == 3)
  634. X        sprintf(interp->result, "%d", mfile->hchunk.format);
  635. X    else {
  636. X        format = (int)strtol(argv[3], &chk_ptr, 0);
  637. X        if (chk_ptr == argv[3] || format < 0 || format > 2) {
  638. X            Tcl_AppendResult(interp, "Bad format",
  639. X                argv[2], (char *)NULL);
  640. X            return (TCL_ERROR);
  641. X        }
  642. X        mfile->hchunk.format = format;
  643. X        if ((result = Tclm_SetMFile(interp, argv[1], mfile)) !=
  644. X            TCL_OK)
  645. X            return (result);
  646. X    }
  647. X    return (TCL_OK);
  648. X}
  649. X
  650. Xint
  651. XTclm_Division(interp, argc, argv)
  652. X    Tcl_Interp *interp;
  653. X    int argc;
  654. X    char **argv;
  655. X{
  656. X    MIDI_FILE *mfile;
  657. X    char *chk_ptr;
  658. X    int division;
  659. X    int result;
  660. X
  661. X    /*
  662. X     * argv[0] - midiconfig
  663. X     * argv[1] - mfileId
  664. X     * argv[2] - division
  665. X     * argv[3] - optional arg
  666. X     */
  667. X
  668. X    if ((result = Tclm_GetMFile(interp, argv[1], &mfile)) != TCL_OK)
  669. X        return (result);
  670. X
  671. X    if (argc == 3)
  672. X        sprintf(interp->result, "%d", mfile->hchunk.division);
  673. X    else {
  674. X        division = (int)strtol(argv[3], &chk_ptr, 0);
  675. X        if (chk_ptr == argv[3]) {
  676. X            Tcl_AppendResult(interp, "bad division value ",
  677. X                argv[3], (char *)NULL);
  678. X            return (TCL_ERROR);
  679. X        }
  680. X        mfile->hchunk.division = division;
  681. X        if ((result = Tclm_SetMFile(interp, argv[1], mfile)) !=
  682. X            TCL_OK)
  683. X            return (result);
  684. X    }
  685. X    return (TCL_OK);
  686. X}
  687. X
  688. Xint
  689. XTclm_MidiGet(dummy, interp, argc, argv)
  690. X    ClientData dummy;
  691. X    Tcl_Interp *interp;
  692. X    int argc;
  693. X    char **argv;
  694. X{
  695. X    MIDI_FILE *mfile;
  696. X    char *chk_ptr;
  697. X    int event_size;
  698. X    int i;
  699. X    int result;
  700. X    int track_num;
  701. X    EVENT_TYPE event_type;
  702. X    char number[10];
  703. X    unsigned char event[MAX_EVENT_SIZE];
  704. X
  705. X    /*
  706. X     * argv[0] - midiget
  707. X     * argv[1] - mfileId
  708. X     * argv[2] - track number
  709. X     */
  710. X
  711. X    if (argc != 3) {
  712. X        Tcl_AppendResult(interp, "bad # args: should be \"",
  713. X            argv[0], " mfileId track_num\"", (char *)NULL);
  714. X        return (TCL_ERROR);
  715. X    }
  716. X
  717. X    if ((result = Tclm_GetMFile(interp, argv[1], &mfile)) != TCL_OK)
  718. X        return (result);
  719. X
  720. X    track_num = (int)strtol(argv[2], &chk_ptr, 0);
  721. X    if (chk_ptr == argv[2] || track_num < 0 ||
  722. X        track_num > mfile->hchunk.num_trks - 1) {
  723. X        Tcl_AppendResult(interp, "Bad track number ", argv[2],
  724. X            (char *)NULL);
  725. X        return (TCL_ERROR);
  726. X    }
  727. X    if ((event_size = get_smf_event(&(mfile->tchunks[track_num]), event,
  728. X        &event_type)) == -1) {
  729. X        Tcl_AppendResult(interp, "Couldn't get event from ", argv[1],
  730. X            " track ", argv[2], "\n", MidiError, (char *)NULL);
  731. X        return (TCL_ERROR);
  732. X    }
  733. X
  734. X    /* convert event to numbers in hex */
  735. X    for (i = 0; i < event_size; i++) {
  736. X        sprintf(number, "0x%02x", event[i]);
  737. X        Tcl_AppendElement(interp, number, 0);
  738. X    }
  739. X
  740. X    return (TCL_OK);
  741. X}
  742. X
  743. Xint
  744. XTclm_ConvertBytes(interp, str, bytes, num_bytes)
  745. X    Tcl_Interp *interp;
  746. X    char *str;
  747. X    unsigned char *bytes;
  748. X    int *num_bytes;
  749. X{
  750. X    int i;
  751. X    int result;
  752. X    char *chk_ptr;
  753. X    char **bytes_str;
  754. X
  755. X    if ((result = Tcl_SplitList(interp, str, num_bytes, &bytes_str)) !=
  756. X        TCL_OK)
  757. X        return (result);
  758. X
  759. X    for (i = 0; i < *num_bytes; i++) {
  760. X        *bytes++ = (unsigned char)strtol(bytes_str[i], &chk_ptr, 0);
  761. X        if (chk_ptr == bytes_str[i]) {
  762. X            Tcl_AppendResult(interp, "Bad event data ",
  763. X                bytes_str[i], (char *)NULL);
  764. X            free((char *)bytes_str);
  765. X            return (TCL_ERROR);
  766. X        }
  767. X    }
  768. X    free((char *)bytes_str);
  769. X    return (TCL_OK);
  770. X}
  771. X
  772. Xint
  773. XTclm_MidiPut(dummy, interp, argc, argv)
  774. X    ClientData dummy;
  775. X    Tcl_Interp *interp;
  776. X    int argc;
  777. X    char **argv;
  778. X{
  779. X    MIDI_FILE *mfile;
  780. X    char *chk_ptr;
  781. X    int num_bytes;
  782. X    int result;
  783. X    int track_num;
  784. X    unsigned char event[MAX_EVENT_SIZE];
  785. X
  786. X    /*
  787. X     * argv[0] - midiput
  788. X     * argv[1] - mfileId
  789. X     * argv[2] - track number
  790. X     * argv[3] - event
  791. X     */
  792. X    if (argc != 4) {
  793. X        Tcl_AppendResult(interp, "bad # args: should be \"",
  794. X            argv[0], " mfileId track_num event\"", (char *)NULL);
  795. X        return (TCL_ERROR);
  796. X    }
  797. X    if ((result = Tclm_GetMFile(interp, argv[1], &mfile)) != TCL_OK)
  798. X        return (result);
  799. X
  800. X    track_num = (int)strtol(argv[2], &chk_ptr, 0);
  801. X    if (chk_ptr == argv[2] || track_num < 0 ||
  802. X        track_num > mfile->hchunk.num_trks - 1) {
  803. X        Tcl_AppendResult(interp, "Bad track number ", argv[2],
  804. X            (char *)NULL);
  805. X        return (TCL_ERROR);
  806. X    }
  807. X
  808. X    if ((result = Tclm_ConvertBytes(interp, argv[3], event, &num_bytes))
  809. X        != TCL_OK)
  810. X        return (result);
  811. X
  812. X    if (!put_smf_event(&(mfile->tchunks[track_num]), event, num_bytes)) {
  813. X        Tcl_AppendResult(interp, "Couldn't put event\n",
  814. X            MidiError, (char *)NULL);
  815. X        return (TCL_ERROR);
  816. X    }
  817. X
  818. X    return (TCL_OK);
  819. X}
  820. X
  821. Xint
  822. XTclm_MidiRewind(dummy, interp, argc, argv)
  823. X    ClientData dummy;
  824. X    Tcl_Interp *interp;
  825. X    int argc;
  826. X    char **argv;
  827. X{
  828. X    MIDI_FILE *mfile;
  829. X    char *chk_ptr;
  830. X    char **track_list;
  831. X    int i;
  832. X    int num_tracks;
  833. X    int result;
  834. X    int track;
  835. X    char number[10];
  836. X
  837. X    /*
  838. X     * argv[0] - midirewind
  839. X     * argv[1] = mfileId
  840. X     * argv[2] = optional track list
  841. X     */
  842. X    if (argc < 2 || argc > 3) {
  843. X        Tcl_AppendResult(interp, "bad # args: should be \"",
  844. X            argv[0], " mfileId ?track list?\"", (char *)NULL);
  845. X        return (TCL_ERROR);
  846. X    }
  847. X
  848. X    if ((result = Tclm_GetMFile(interp, argv[1], &mfile)) != TCL_OK)
  849. X        return (result);
  850. X
  851. X    if (argc == 2)
  852. X        for (i = 0; i < mfile->hchunk.num_trks; i++)
  853. X            rewind_track(&(mfile->tchunks[i]));
  854. X    else {
  855. X        if ((result = Tcl_SplitList(interp, argv[2], &num_tracks,
  856. X            &track_list)) != TCL_OK)
  857. X            return (result);
  858. X        for (i = 0; i < num_tracks; i++) {
  859. X            track = (int)strtol(track_list[i], &chk_ptr, 0);
  860. X            if (chk_ptr == track_list[i] || track < 0 ||
  861. X                track >= mfile->hchunk.num_trks) {
  862. X                Tcl_AppendResult(interp, "Bad track value ",
  863. X                    track_list[i], (char *)NULL);
  864. X                free ((char *)track_list);
  865. X                return (TCL_ERROR);
  866. X            }
  867. X            rewind_track(&(mfile->tchunks[track]));
  868. X        }
  869. X        free((char *)track_list);
  870. X    }
  871. X
  872. X    return (TCL_OK);
  873. X}
  874. X
  875. Xint
  876. XTclm_MidiVarToFix(dummy, interp, argc, argv)
  877. X    ClientData dummy;
  878. X    Tcl_Interp *interp;
  879. X    int argc;
  880. X    char **argv;
  881. X{
  882. X    long fix;
  883. X    int delta;
  884. X    int num_bytes;
  885. X    int result;
  886. X    unsigned char bytes[MAX_EVENT_SIZE];
  887. X
  888. X    /*
  889. X     * argv[0] - midivartofix
  890. X     * argv[1] - midi event
  891. X     */
  892. X    if (argc != 2) {
  893. X        Tcl_AppendResult(interp, "bad # args: should be\"",
  894. X            argv[0], " midi_event\"", (char *)NULL);
  895. X        return (TCL_ERROR);
  896. X    }
  897. X    if ((result = Tclm_ConvertBytes(interp, argv[1], bytes, &num_bytes))
  898. X        != TCL_OK)
  899. X        return (result);
  900. X
  901. X    fix = var2fix(bytes, &delta);
  902. X    sprintf(interp->result, "%ld", fix);
  903. X    return (TCL_OK);
  904. X}
  905. X
  906. Xint
  907. XTclm_MidiFixToVar(dummy, interp, argc, argv)
  908. X    ClientData dummy;
  909. X    Tcl_Interp *interp;
  910. X    int argc;
  911. X    char **argv;
  912. X{
  913. X    long fix;
  914. X    char *chk_ptr;
  915. X    int i;
  916. X    int num_bytes;
  917. X    unsigned char bytes[4];
  918. X    char byte_str[10];
  919. X
  920. X    /*
  921. X     * argv[0] - midifixtovar
  922. X     * argv[1] - fixed length value
  923. X     */
  924. X    if (argc != 2) {
  925. X        Tcl_AppendResult(interp, "bad # args: should be \"",
  926. X            argv[0], " fixval\"", (char *)NULL);
  927. X        return (TCL_ERROR);
  928. X    }
  929. X
  930. X    fix = strtol(argv[1], &chk_ptr, 0);
  931. X    if (chk_ptr == argv[1]) {
  932. X        Tcl_AppendResult(interp, "Bad fixed length value ", argv[1],
  933. X            (char *)NULL);
  934. X        return (TCL_ERROR);
  935. X    }
  936. X    num_bytes = fix2var(fix, bytes);
  937. X    for (i = 0; i < num_bytes; i++) {
  938. X        sprintf(byte_str, "0x%02x", bytes[i]);
  939. X        Tcl_AppendElement(interp, byte_str, 0);
  940. X    }
  941. X    return (TCL_OK);
  942. X}
  943. X
  944. Xint
  945. XTclm_MidiTiming(dummy, interp, argc, argv)
  946. X    ClientData dummy;
  947. X    Tcl_Interp *interp;
  948. X    int argc;
  949. X    char **argv;
  950. X{
  951. X    int delta;
  952. X    int i;
  953. X    int num_bytes;
  954. X    int result;
  955. X    unsigned char bytes[MAX_EVENT_SIZE];
  956. X    char str[10];
  957. X
  958. X    /*
  959. X     * argv[0] - miditiming
  960. X     * argv[1] - event
  961. X     */
  962. X
  963. X    if ((result = Tclm_ConvertBytes(interp, argv[1], bytes, &num_bytes))
  964. X        != TCL_OK)
  965. X        return (result);
  966. X
  967. X    (void)var2fix(bytes, &delta);
  968. X
  969. X    for (i = 0; i < delta; i++) {
  970. X        sprintf(str, "0x%02x", bytes[i]);
  971. X        Tcl_AppendElement(interp, str, 0);
  972. X    }
  973. X    return (TCL_OK);
  974. X}
  975. X
  976. Xint
  977. XTclm_MidiMPU(dummy, interp, argc, argv)
  978. X    ClientData dummy;
  979. X    Tcl_Interp *interp;
  980. X    int argc;
  981. X    char **argv;
  982. X{
  983. X
  984. X    /*
  985. X     * argv[0] - midimpu
  986. X     */
  987. X    if (argc != 1) {
  988. X        Tcl_AppendResult(interp, "wrong # args: should be\"",
  989. X            argv[0], "\"", (char *)NULL);
  990. X        return (TCL_ERROR);
  991. X    }
  992. X
  993. X#ifdef MPU
  994. X    Tcl_AppendResult(interp, "1", (char *)NULL);
  995. X#else
  996. X    Tcl_AppendResult(interp, "0", (char *)NULL);
  997. X#endif
  998. X    return (TCL_OK);
  999. X}
  1000. END-of-tclm0.1/tclmCmd.c
  1001. exit
  1002.