home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / lang / tcl / 2358 < prev    next >
Encoding:
Text File  |  1993-01-12  |  22.9 KB  |  958 lines

  1. Newsgroups: comp.lang.tcl
  2. Path: sparky!uunet!paladin.american.edu!howland.reston.ans.net!zaphod.mps.ohio-state.edu!magnus.acs.ohio-state.edu!usenet.ins.cwru.edu!agate!boulder!csn!cherokee!durian
  3. From: durian@advtech.uswest.com (Mike Durian)
  4. Subject: tclm0.1 - tcl with MIDI extensions (6/7)
  5. Message-ID: <1993Jan12.203053.20069@advtech.uswest.com>
  6. Sender: news@advtech.uswest.com (Radio Free Boulder)
  7. Nntp-Posting-Host: mongo.advtech.uswest.com
  8. Organization: U S WEST Advanced Technologies
  9. Date: Tue, 12 Jan 1993 20:30:53 GMT
  10. Lines: 946
  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/mlib/Makefile
  20. #    tclm0.1/mlib/mfileutil.c
  21. #    tclm0.1/mplay
  22. #
  23. echo x - tclm0.1/mlib/Makefile
  24. sed 's/^X//' >tclm0.1/mlib/Makefile << 'END-of-tclm0.1/mlib/Makefile'
  25. X# add -DMPU to defines if you wish to compile in the ability to
  26. X# play standard MIDI files.  This will only work on BSD/386
  27. X# (BSDI) machines equipped with a MPU401 compatible MIDI card.
  28. X# DEFS =
  29. XDEFS = -DMPU
  30. X
  31. X# set RANLIB to ranlib if your system has it - otherwise set it to
  32. X# true
  33. X# RANLIB = true
  34. XRANLIB = ranlib
  35. X
  36. XSRCS=mfileutil.c mplayutil.c mpu401.c
  37. XOBJS=mfileutil.o mplayutil.o mpu401.o
  38. XAR=libmutil.a
  39. X
  40. XCFLAGS= $(DEFS) -O -I.
  41. XCC=cc
  42. X
  43. Xall:    $(AR)
  44. X
  45. X$(AR):    $(OBJS)
  46. X    rm -f $(AR)
  47. X    ar cr $(AR) $(OBJS)
  48. X    $(RANLIB) $(AR)
  49. X
  50. Xclean:
  51. X    rm -f $(AR) $(OBJS)
  52. Xlint:
  53. X    lint $(SRCS) > lint.out >&1
  54. END-of-tclm0.1/mlib/Makefile
  55. echo x - tclm0.1/mlib/mfileutil.c
  56. sed 's/^X//' >tclm0.1/mlib/mfileutil.c << 'END-of-tclm0.1/mlib/mfileutil.c'
  57. X/* mfileutil.c,v 1.3 1993/01/12 19:23:38 durian Exp */
  58. X/*
  59. X * Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  60. X *
  61. X * Redistribution and use in source and binary forms, with or without
  62. X * modification, are permitted provided that the following conditions
  63. X * are met:
  64. X * 1. Redistributions of source code must retain the above copyright
  65. X *    notice, this list of conditions and the following disclaimer.
  66. X * 2. Redistributions in binary form must reproduce the above copyright
  67. X *    notice, this list of conditions and the following disclaimer in the
  68. X *    documentation and/or other materials provided with the distribution.
  69. X * 3. All advertising materials mentioning features or use of this software
  70. X *    must display the following acknowledgement:
  71. X *    This product includes software developed by Michael B. Durian.
  72. X * 4. The name of the the Author may be used to endorse or promote 
  73. X *    products derived from this software without specific prior written 
  74. X *    permission.
  75. X *
  76. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  77. X * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  78. X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  79. X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  80. X * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  81. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  82. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  83. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  84. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  85. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  86. X * SUCH DAMAGE.
  87. X */
  88. X#include <stdio.h>
  89. X#include <stdlib.h>
  90. X#include <unistd.h>
  91. X#include <string.h>
  92. X#include <sys/fcntl.h>
  93. X#include "mutil.h"
  94. X
  95. X/* hack so we know if a read failed because of an eof instead of bad data */
  96. Xint MidiEof = 0;
  97. Xchar MidiError[256];
  98. X
  99. Xint
  100. Xread_header_chunk(mfile, hchunk)
  101. X    int mfile;
  102. X    HCHUNK *hchunk;
  103. X{
  104. X
  105. X    if (mread(mfile, hchunk->str, sizeof(hchunk->str)) !=
  106. X        sizeof(hchunk->str)) {
  107. X        if (!MidiEof)
  108. X            sprintf(MidiError,
  109. X                "Couldn't read header chunk identifier");
  110. X        return (0);
  111. X    }
  112. X
  113. X    if (mread(mfile, (char *)&hchunk->length, sizeof(hchunk->length)) !=
  114. X        sizeof(hchunk->length)) {
  115. X        sprintf(MidiError, "Couldn't read header chunk length");
  116. X        return (0);
  117. X    }
  118. X
  119. X    if (mread(mfile, (char *)&hchunk->format, sizeof(hchunk->format)) !=
  120. X        sizeof(hchunk->format)) {
  121. X        sprintf(MidiError, "Couldn't read header chunk format");
  122. X        return (0);
  123. X    }
  124. X
  125. X    if (mread(mfile, (char *)&hchunk->num_trks, sizeof(hchunk->num_trks))
  126. X        != sizeof(hchunk->num_trks)) {
  127. X        sprintf(MidiError, "Couldn't read header chunk num_trks");
  128. X        return (0);
  129. X    }
  130. X
  131. X    if (mread(mfile, (char *)&hchunk->division, sizeof(hchunk->division))
  132. X        != sizeof(hchunk->division)) {
  133. X        sprintf(MidiError, "Couldn't read header chunk division");
  134. X        return (0);
  135. X    }
  136. X
  137. X    /* fix byte ordering */
  138. X    hchunk->length = mtohl(hchunk->length);
  139. X    hchunk->format = mtohs(hchunk->format);
  140. X    hchunk->num_trks = mtohs(hchunk->num_trks);
  141. X    hchunk->division = mtohs(hchunk->division);
  142. X
  143. X    if (strncmp(hchunk->str, "MThd", 4) != 0) {
  144. X        sprintf(MidiError, "Not a standard MIDI file");
  145. X        return (0);
  146. X    }
  147. X
  148. X    if (hchunk->length != 6) {
  149. X        sprintf(MidiError, "Bad header chunk size");
  150. X        return (0);
  151. X    }
  152. X
  153. X    if (hchunk->format == 0 && hchunk->num_trks != 1) {
  154. X        sprintf(MidiError,
  155. X            "Midi format 0, but number of tracks (%d) is > 1",
  156. X            hchunk->num_trks);
  157. X        return (0);
  158. X    }
  159. X
  160. X    return (1);
  161. X}
  162. X
  163. Xint
  164. Xread_track_chunk(mfile, tracks)
  165. X    int mfile;
  166. X    TCHUNK *tracks;
  167. X{
  168. X
  169. X    if (mread(mfile, tracks->str, 4) != 4) {
  170. X        sprintf(MidiError, "Couldn't read track chunk identifier");
  171. X        return (0);
  172. X    }
  173. X
  174. X    if (strncmp(tracks->str, "MTrk", 4) != 0) {
  175. X        sprintf(MidiError, "Bad track chunk identifier");
  176. X        return (0);
  177. X    }
  178. X
  179. X    if (mread(mfile, (char *)&tracks->length, sizeof(tracks->length)) !=
  180. X        sizeof(tracks->length)) {
  181. X        sprintf(MidiError, "Couldn't read track length");
  182. X        return (0);
  183. X    }
  184. X
  185. X    tracks->msize = tracks->length = mtohl(tracks->length);
  186. X    tracks->pos = 0;
  187. X
  188. X    /* allocate space for tracks events */
  189. X    if ((tracks->events = (unsigned char *) malloc(tracks->length)) ==
  190. X        NULL) {
  191. X        sprintf(MidiError, "Not enough memory for track data");
  192. X        return (0);
  193. X    }
  194. X    tracks->event_start = tracks->events;
  195. X
  196. X    if (mread(mfile, (char *)tracks->events, tracks->length) !=
  197. X        tracks->length) {
  198. X            sprintf(MidiError, "Couldn't read track data");
  199. X            return (0);
  200. X    }
  201. X    tracks->events = tracks->event_start;
  202. X
  203. X    return (1);
  204. X}
  205. X
  206. Xint
  207. Xskip_track_chunk(mfile)
  208. X    int mfile;
  209. X{
  210. X    long length;
  211. X    char str[4];
  212. X
  213. X    if (mread(mfile, str, sizeof(str)) != sizeof(str)) {
  214. X        sprintf(MidiError, "Couldn't read track chunk identifier");
  215. X        return (0);
  216. X    }
  217. X
  218. X    if (strncmp(str, "MTrk", 4) != 0) {
  219. X        sprintf(MidiError, "Bad track chunk identifier");
  220. X        return (0);
  221. X    }
  222. X
  223. X    if (mread(mfile, (char *)&length, sizeof(length)) != sizeof(length)) {
  224. X        sprintf(MidiError, "Couldn't read track length");
  225. X        return (0);
  226. X    }
  227. X
  228. X    length = mtohl(length);
  229. X
  230. X    if (lseek(mfile, length, SEEK_CUR) == -1) {
  231. X        sprintf(MidiError, "Couldn't seek past track");
  232. X        return (0);
  233. X    }
  234. X
  235. X    return (1);
  236. X}
  237. X
  238. Xint
  239. Xsplit_type_zero(tracks)
  240. X    TCHUNK *tracks;
  241. X{
  242. X    long tempo_delta;
  243. X    long data_delta;
  244. X    long timing;
  245. X    EVENT_TYPE event_type;
  246. X    int data_size;
  247. X    int event_size;
  248. X    int i;
  249. X    int offset;
  250. X    int malloced_data;
  251. X    int malloced_tempo;
  252. X    int malloc_inc;
  253. X    int tempo_size;
  254. X    int time_len;
  255. X    unsigned char event[256];
  256. X    unsigned char *data_events;
  257. X    unsigned char *data_ptr;
  258. X    unsigned char *last_events;
  259. X    unsigned char *tempo_events;
  260. X    unsigned char *tempo_ptr;
  261. X    unsigned char var_time[4];
  262. X
  263. X    data_size = 0;
  264. X    tempo_size = 0;
  265. X    tempo_delta = 0;
  266. X    data_delta = 0;
  267. X    malloc_inc = 512;
  268. X
  269. X    if ((data_events = (unsigned char *) malloc(malloc_inc))
  270. X            == NULL) {
  271. X        sprintf(MidiError, "Not enought memory to split track");
  272. X        return (0);
  273. X    }
  274. X    malloced_data = malloc_inc;
  275. X    if ((tempo_events = (unsigned char *) malloc(malloc_inc))
  276. X            == NULL) {
  277. X        sprintf(MidiError, "Not enought memory to split track");
  278. X        return (0);
  279. X    }
  280. X    malloced_tempo = malloc_inc;
  281. X
  282. X    data_ptr = data_events;
  283. X    tempo_ptr = tempo_events;
  284. X    while (event_size = get_smf_event(&tracks[0], event, &event_type)) {
  285. X        if (event_size == -1) {
  286. X            sprintf(MidiError,
  287. X                "Problem getting event while splitting");
  288. X            return (0);
  289. X        }
  290. X
  291. X        if (event_type ==  NORMAL || event_type == SYSEX) {
  292. X            timing = var2fix(event, &offset);
  293. X            data_delta += timing;
  294. X            time_len = fix2var(data_delta, var_time);
  295. X            data_size += event_size - offset + time_len;
  296. X            if (data_size > malloced_data) {
  297. X                last_events = data_events;
  298. X                if (!more_memory((char **)&data_events,
  299. X                    malloced_data + malloc_inc)) {
  300. X                    sprintf(MidiError,
  301. X                        "Not enough memory");
  302. X                    return (0);
  303. X                }
  304. X                if (data_events != last_events)
  305. X                    data_ptr = data_events + (data_ptr -
  306. X                        last_events);
  307. X            }
  308. X            /* copy in timing */
  309. X            for (i = 0; i < time_len; i++)
  310. X                *data_ptr++ = var_time[i];
  311. X
  312. X            /* copy in data */
  313. X            for (i = offset; i < event_size; i++)
  314. X                *data_ptr++ = event[i];
  315. X
  316. X            /* add timing to tempo delta */
  317. X            tempo_delta += timing;
  318. X            data_delta = 0;
  319. X        } else {
  320. X            timing = var2fix(event, &offset);
  321. X            tempo_delta += timing;
  322. X            time_len = fix2var(tempo_delta, var_time);
  323. X            tempo_size += event_size - offset + time_len;
  324. X            if (tempo_size > malloced_tempo) {
  325. X                last_events = tempo_events;
  326. X                if (!more_memory((char **)&tempo_events,
  327. X                    malloced_tempo + malloc_inc)) {
  328. X                    sprintf(MidiError,
  329. X                        "Not enough memory");
  330. X                    return (0);
  331. X                }
  332. X                if (tempo_events != last_events)
  333. X                    tempo_ptr = data_events + (tempo_ptr -
  334. X                        last_events);
  335. X            }
  336. X            /* copy in timing */
  337. X            for (i = 0; i < time_len; i++)
  338. X                *tempo_ptr++ = var_time[i];
  339. X
  340. X            /* copy in data */
  341. X            for (i = offset; i < event_size; i++)
  342. X                *tempo_ptr++ = event[i];
  343. X
  344. X            /* add timing to tempo delta */
  345. X            data_delta += timing;
  346. X            tempo_delta = 0;
  347. X        }
  348. X    }
  349. X
  350. X    /* add eot to tempo track */
  351. X    event[0] = 0xff;
  352. X    event[1] = METAEOT;
  353. X    event[2] = 0;
  354. X    event_size = 3;
  355. X
  356. X    time_len = fix2var(tempo_delta, var_time);
  357. X    tempo_size += event_size + time_len;
  358. X    if (tempo_size > malloced_tempo) {
  359. X        last_events = tempo_events;
  360. X        if (!more_memory((char **)&tempo_events, malloced_tempo +
  361. X            malloc_inc)) {
  362. X            sprintf(MidiError, "Not enough memory");
  363. X            return (0);
  364. X        }
  365. X        if (tempo_events != last_events)
  366. X            tempo_ptr = data_events + (tempo_ptr - last_events);
  367. X    }
  368. X    /* copy in timing */
  369. X    for (i = 0; i < time_len; i++)
  370. X        *tempo_ptr++ = var_time[i];
  371. X
  372. X    /* copy in data */
  373. X    for (i = 0; i < event_size; i++)
  374. X        *tempo_ptr++ = event[i];
  375. X            
  376. X    free(tracks[0].events);
  377. X    tracks[0].events = tracks[0].event_start = tempo_events;
  378. X    tracks[1].events = tracks[1].event_start = data_events;
  379. X    tracks[0].msize = malloced_tempo;
  380. X    tracks[1].msize = malloced_data;
  381. X    tracks[0].length = tempo_size;
  382. X    tracks[1].length = data_size;
  383. X    tracks[0].pos = 0;
  384. X    tracks[1].pos = 0;
  385. X    (void) strncpy(tracks[0].str, "MTrk", 4);
  386. X    (void) strncpy(tracks[1].str, "MTrk", 4);
  387. X    return (1);
  388. X}
  389. X
  390. Xint
  391. Xmore_memory(ptr, size)
  392. X    char **ptr;
  393. X    int size;
  394. X{
  395. X
  396. X    if ((*ptr = realloc(*ptr, size)) == NULL)
  397. X        return (0);
  398. X    else
  399. X        return (1);
  400. X}
  401. X
  402. Xint
  403. Xget_smf_event(track, event, event_type)
  404. X    TCHUNK *track;
  405. X    unsigned char *event;
  406. X    EVENT_TYPE *event_type;
  407. X{
  408. X    long length = 0;
  409. X    int i;
  410. X    int size;
  411. X    static int extra_bytes[] = {2, 2, 2, 2, 1, 1, 2, 0};
  412. X    unsigned char etype;
  413. X    static unsigned char r_state;
  414. X            
  415. X    if (track->pos >= track->length)
  416. X        return (0);
  417. X
  418. X    /*
  419. X     * get timing bytes
  420. X     */
  421. X    if (track->pos++ == track->length)
  422. X        return (-1);
  423. X    *event++ = *track->events++;
  424. X    size = 1;
  425. X    while (*(event - 1) & 0x80) {
  426. X        if (track->pos++ == track->length)
  427. X            return (-1);
  428. X        *event++ = *track->events++;
  429. X        size++;
  430. X    }
  431. X
  432. X    if (track->pos++ == track->length)
  433. X        return (-1);
  434. X    *event = *track->events++;
  435. X
  436. X    /* get event type */
  437. X    switch (*event) {
  438. X    case 0xff:
  439. X        /* meta event */
  440. X        if (track->pos++ == track->length)
  441. X            return (-1);
  442. X        size++;
  443. X        event++;
  444. X        *event_type = *event++ = *track->events++;
  445. X        size++;
  446. X        /* get length as a variable length */
  447. X        do {
  448. X            if (track->pos++ == track->length)
  449. X                return (-1);
  450. X            length = (length << 7) + (*track->events & 0x7f);
  451. X            *event = *track->events++;
  452. X            size++;
  453. X        } while (*event++ & 0x80);
  454. X        for (; length > 0; length--) {
  455. X            /* get event */
  456. X            if (track->pos++ == track->length)
  457. X                return (-1);
  458. X            *event++ = *track->events++;
  459. X            size++;
  460. X        }
  461. X        break;
  462. X    case 0xf0:
  463. X    case 0xf7:
  464. X        event++;
  465. X        size++;
  466. X        *event_type = SYSEX;
  467. X        do {
  468. X            if (track->pos++ == track->length)
  469. X                return (-1);
  470. X            *event = *track->events++;
  471. X            size++;
  472. X        } while (*event++ != 0xf7);
  473. X        break;
  474. X    default:
  475. X        *event_type = NORMAL;
  476. X        size++;
  477. X        if (*event & 0x80) {
  478. X            etype = *event;
  479. X            r_state = (*event >> 4) & 0x0f;
  480. X            for (i = 0; i < extra_bytes[(etype >> 4) & 0x07];
  481. X                i++) {
  482. X                event++;
  483. X                if (track->pos++ == track->length)
  484. X                    return(-1);
  485. X                *event = *track->events++;
  486. X                size++;
  487. X            }
  488. X        } else {
  489. X            /* assume it is a continuation of note on */
  490. X            /* get other data byte */
  491. X            switch (r_state) {
  492. X            case 0x08:
  493. X            case 0x09:
  494. X            case 0x0a:
  495. X            case 0x0b:
  496. X            case 0x0e:
  497. X                event++;
  498. X                if (track->pos++ == track->length)
  499. X                    return (-1);
  500. X                *event = *track->events++;
  501. X                size++;
  502. X                break;
  503. X            default:
  504. X                break;
  505. X            }
  506. X        }
  507. X    }
  508. X    return (size);
  509. X}
  510. X
  511. Xint
  512. Xput_smf_event(track, event, event_size)
  513. X    TCHUNK *track;
  514. X    unsigned char *event;
  515. X    int event_size;
  516. X{
  517. X
  518. X    if (track->msize == 0) {
  519. X        if ((track->event_start = (unsigned char *)malloc(
  520. X            BUFSIZ)) == NULL) {
  521. X            sprintf(MidiError, "Not enough memory for new event");
  522. X            return (0);
  523. X        }
  524. X        track->msize = BUFSIZ;
  525. X        track->events = track->event_start;
  526. X    }
  527. X    track->length += event_size;
  528. X    if (track->pos + event_size > track->msize) {
  529. X        track->msize += BUFSIZ;
  530. X        if ((track->event_start =
  531. X            (unsigned char *)realloc(track->event_start, track->msize))
  532. X            == NULL) {
  533. X            perror("");
  534. X            sprintf(MidiError, "Not enough memory for new event");
  535. X            track->length -= event_size;
  536. X            track->msize -= BUFSIZ;
  537. X            return (0);
  538. X        }
  539. X        /* starting position might move */
  540. X        track->events = track->event_start + track->pos;
  541. X    }
  542. X
  543. X    memcpy(track->events, event, event_size);
  544. X    track->events += event_size;
  545. X    track->pos += event_size;
  546. X    return (1);
  547. X}
  548. X
  549. Xvoid
  550. Xrewind_track(track)
  551. X    TCHUNK *track;
  552. X{
  553. X    track->pos = 0;
  554. X    track->events = track->event_start;
  555. X}
  556. X
  557. Xvoid
  558. Xreset_track(track)
  559. X    TCHUNK *track;
  560. X{
  561. X    track->pos = 0;
  562. X    track->length = 0;
  563. X    track->events = track->event_start;
  564. X}
  565. X
  566. X
  567. Xint
  568. Xwrite_header_chunk(mfile, hchunk)
  569. X    int mfile;
  570. X    HCHUNK *hchunk;
  571. X{
  572. X
  573. X    (void)strncpy(hchunk->str, "MThd", 4);
  574. X    if (mwrite(mfile, hchunk->str, 4) != 4) {
  575. X        sprintf(MidiError, "Couldn't write header chunk identifier");
  576. X        return (0);
  577. X    }
  578. X
  579. X    hchunk->length = 6;
  580. X    hchunk->length = htoml(hchunk->length);
  581. X    if (mwrite(mfile, (char *)&hchunk->length, sizeof(hchunk->length)) !=
  582. X        sizeof(hchunk->length)) {
  583. X        sprintf(MidiError, "Couldn't write header chunk length");
  584. X        return (0);
  585. X    }
  586. X    hchunk->length = mtohl(hchunk->length);
  587. X
  588. X    hchunk->format = htoms(hchunk->format);
  589. X    if (mwrite(mfile, (char *)&hchunk->format, sizeof(hchunk->format)) !=
  590. X        sizeof(hchunk->format)) {
  591. X        sprintf(MidiError, "Couldn't write header chunk format");
  592. X        return (0);
  593. X    }
  594. X    hchunk->format = mtohs(hchunk->format);
  595. X
  596. X    hchunk->num_trks = htoms(hchunk->num_trks);
  597. X    if (mwrite(mfile, (char *)&hchunk->num_trks, sizeof(hchunk->num_trks))
  598. X        != sizeof(hchunk->num_trks)) {
  599. X        sprintf(MidiError, "Couldn't write number of tracks");
  600. X        return (0);
  601. X    }
  602. X    hchunk->num_trks = mtohs(hchunk->num_trks);
  603. X
  604. X    hchunk->division = htoms(hchunk->division);
  605. X    if (mwrite(mfile, (char *)&hchunk->division, sizeof(hchunk->division))
  606. X        != sizeof(hchunk->division)) {
  607. X        sprintf(MidiError, "Couldn't write header chunk division");
  608. X        return (0);
  609. X    }
  610. X    hchunk->division = mtohs(hchunk->division);
  611. X
  612. X    return (1);
  613. X}
  614. X
  615. Xint
  616. Xwrite_track_chunk(mfile, tchunk)
  617. X    int mfile;
  618. X    TCHUNK *tchunk;
  619. X{
  620. X    long midi_length;
  621. X
  622. X    (void)strncpy(tchunk->str, "MTrk", 4);
  623. X    if (mwrite(mfile, tchunk->str, 4) != 4) {
  624. X        sprintf(MidiError, "Couldn't write track chunk identifier");
  625. X        return (0);
  626. X    }
  627. X
  628. X    midi_length = htoml(tchunk->length);
  629. X    if (mwrite(mfile, (char *)&midi_length, sizeof(midi_length)) !=
  630. X        sizeof(midi_length)) {
  631. X        sprintf(MidiError, "Couldn't write track length");
  632. X        return (0);
  633. X    }
  634. X
  635. X    if (mwrite(mfile, (char *)tchunk->event_start, tchunk->length)
  636. X        != tchunk->length) {
  637. X        sprintf(MidiError, "Couldn't write track events");
  638. X        return (0);
  639. X    }
  640. X
  641. X    return (1);
  642. X}
  643. X
  644. Xint
  645. Xload_tracks(mfile, hchunk, tracks_ptr, spec_tracks)
  646. X    int mfile;
  647. X    HCHUNK *hchunk;
  648. X    TCHUNK **tracks_ptr;
  649. X    TRKS *spec_tracks;
  650. X{
  651. X    TCHUNK *tracks;
  652. X    int i;
  653. X    int cur_track;
  654. X
  655. X    if (hchunk->format == 0) {
  656. X        if (spec_tracks->num_tracks) {
  657. X            sprintf(MidiError,
  658. X                "Specified tracks are ignored on file type 0");
  659. X        }
  660. X
  661. X        if ((tracks = (TCHUNK *) malloc(sizeof(TCHUNK) * 2)) == NULL) {
  662. X            sprintf(MidiError, "No memory available for tracks");
  663. X            return (0);
  664. X        }
  665. X
  666. X        if (!read_track_chunk(mfile, &tracks[0])) {
  667. X            sprintf(MidiError, "Couldn't read track 0");
  668. X            return (0);
  669. X        }
  670. X
  671. X        if (!split_type_zero(tracks)) {
  672. X            sprintf(MidiError, "Couldn't split MIDI file type 0");
  673. X            return (0);
  674. X        }
  675. X
  676. X        *tracks_ptr = tracks;
  677. X
  678. X        return (2);
  679. X    }
  680. X        
  681. X    if (spec_tracks->num_tracks == 0) {
  682. X        for (i = 0; i < hchunk->num_trks; i++)
  683. X            spec_tracks->tracks[i] = i;
  684. X        spec_tracks->num_tracks = hchunk->num_trks;
  685. X    }
  686. X
  687. X    if ((tracks = (TCHUNK *) malloc(sizeof(TCHUNK) *
  688. X            spec_tracks->num_tracks)) == NULL) {
  689. X        sprintf(MidiError, "No memory available for tracks");
  690. X        return (0);
  691. X    }
  692. X
  693. X    cur_track = 0;
  694. X    /* read in tracks */
  695. X    for (i = 0; i <= spec_tracks->tracks[spec_tracks->num_tracks - 1];
  696. X            i++) {
  697. X        if (i == spec_tracks->tracks[cur_track]) {
  698. X            /* read track chunk */
  699. X            if (!read_track_chunk(mfile, &tracks[cur_track++])) {
  700. X                sprintf(MidiError, "Couldn't read track %d",
  701. X                    i);
  702. X                return (0);
  703. X            }
  704. X        } else {
  705. X            if (!skip_track_chunk(mfile)) {
  706. X                sprintf(MidiError,
  707. X                    "Couldn't skip track chunk %d", i);
  708. X                return (0);
  709. X            }
  710. X        }
  711. X    }
  712. X
  713. X    *tracks_ptr = tracks;
  714. X    return (spec_tracks->num_tracks);
  715. X}
  716. X
  717. Xint
  718. Xfix2var(val, ptr)
  719. X    long val;
  720. X    unsigned char *ptr;
  721. X{
  722. X    int i;
  723. X    unsigned char buf[4];
  724. X    unsigned char *bptr;
  725. X
  726. X    buf[0] = buf[1] = buf[2] = buf[3] = 0;
  727. X    bptr = buf;
  728. X    *bptr++ = val & 0x7f;
  729. X    while ((val >>= 7) > 0) {
  730. X        *bptr |= 0x80;
  731. X        *bptr++ += (val & 0x7f);
  732. X    }
  733. X
  734. X    i = 0;
  735. X    do {
  736. X        *ptr++ = *--bptr;
  737. X        i++;
  738. X    } while (bptr != buf);
  739. X
  740. X    return (i);
  741. X}
  742. X
  743. Xlong
  744. Xvar2fix(var, delta)
  745. X    unsigned char *var;
  746. X    int *delta;
  747. X{
  748. X    long fix;
  749. X
  750. X    fix = 0;
  751. X    *delta = 0;
  752. X    if (*var & 0x80)
  753. X        do {
  754. X            fix = (fix << 7) + (*var & 0x7f);
  755. X            (*delta)++;
  756. X        } while (*var++ & 0x80);
  757. X    else {
  758. X        fix = *var++;
  759. X        (*delta)++;
  760. X    }
  761. X
  762. X    return (fix);
  763. X}
  764. X
  765. Xvoid
  766. Xfree_track(track)
  767. X    TCHUNK *track;
  768. X{
  769. X
  770. X    if (track->event_start != NULL)
  771. X        free(track->event_start);
  772. X    track->event_start = NULL;
  773. X    track->events = NULL;
  774. X    track->length = 0;
  775. X    track->pos = 0;
  776. X    track->msize = 0;
  777. X}
  778. X
  779. Xint
  780. Xmread(dev, buf, size)
  781. X    int dev;
  782. X    char *buf;
  783. X    int size;
  784. X{
  785. X    int num_read;
  786. X    int total_read;
  787. X
  788. X    total_read = 0;
  789. X    do {
  790. X        if ((num_read = read(dev, buf, size - total_read)) == -1) {
  791. X            perror("");
  792. X            return (-1);
  793. X        }
  794. X        if (num_read == 0)
  795. X            break;
  796. X        total_read += num_read;
  797. X        buf += num_read;
  798. X    } while (size > total_read);
  799. X    if (total_read == 0)
  800. X        MidiEof = 1;
  801. X    return (total_read);
  802. X}
  803. X
  804. Xint
  805. Xmwrite(dev, buf, size)
  806. X    int dev;
  807. X    char *buf;
  808. X    int size;
  809. X{
  810. X    int num_written;
  811. X    int total_written;
  812. X
  813. X    total_written = 0;
  814. X    do {
  815. X        if ((num_written = write(dev, buf, size - total_written))
  816. X            == -1) {
  817. X            perror("");
  818. X            return (-1);
  819. X        }
  820. X        if (num_written == 0)
  821. X            break;
  822. X        total_written += num_written;
  823. X        buf += num_written;
  824. X    } while (size > total_written);
  825. X    return (total_written);
  826. X}
  827. END-of-tclm0.1/mlib/mfileutil.c
  828. echo x - tclm0.1/mplay
  829. sed 's/^X//' >tclm0.1/mplay << 'END-of-tclm0.1/mplay'
  830. X#!/usr/local/bin/tclm -f
  831. X#
  832. X# Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  833. X#
  834. X# Redistribution and use in source and binary forms, with or without
  835. X# modification, are permitted provided that the following conditions
  836. X# are met:
  837. X# 1. Redistributions of source code must retain the above copyright
  838. X#    notice, this list of conditions and the following disclaimer.
  839. X# 2. Redistributions in binary form must reproduce the above copyright
  840. X#    notice, this list of conditions and the following disclaimer in the
  841. X#    documentation and/or other materials provided with the distribution.
  842. X# 3. All advertising materials mentioning features or use of this software
  843. X#    must display the following acknowledgement:
  844. X#    This product includes software developed by Michael B. Durian.
  845. X# 4. The name of the the Author may be used to endorse or promote 
  846. X#    products derived from this software without specific prior written 
  847. X#    permission.
  848. X#
  849. X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  850. X# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  851. X# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  852. X# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  853. X# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  854. X# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  855. X# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  856. X# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  857. X# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  858. X# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  859. X# SUCH DAMAGE.
  860. X#
  861. X
  862. Xif {! [midimpu]} {
  863. X    puts stderr [concat "Cannot play.  Tclm was not compiled with the " \
  864. X        "MPU functionality turned on."]
  865. X    exit 1
  866. X}
  867. X
  868. Xset repeat 0
  869. Xset tracks {}
  870. Xset speed 1.0
  871. Xset filenames {}
  872. X
  873. Xproc parse_arg {args} {
  874. X    global repeat
  875. X    global tracks
  876. X    global speed
  877. X    global filenames
  878. X
  879. X    # strip away extra {}'s
  880. X    set args [lindex $args 0]
  881. X    set num_args [llength $args]
  882. X    if {$num_args > 1 && [string compare [lindex $args 0] "-f"] == 0} {
  883. X        set i 2
  884. X    } else {
  885. X        set i 0
  886. X    }
  887. X    for {} {$i < $num_args} {incr i} {
  888. X
  889. X        set arg [lindex $args $i]
  890. X        case $arg in \
  891. X        -r {
  892. X            set repeat 1
  893. X        } -t {
  894. X            set tracks [lindex $args [incr i]]
  895. X        } -s {
  896. X            set speed [lindex $args [incr i]]
  897. X        } default {
  898. X            lappend filenames $arg
  899. X        }
  900. X    }
  901. X}
  902. X
  903. Xparse_arg $argv
  904. X
  905. X#set midi_file_name /u/durian/midi/songs/chorale.mid
  906. X
  907. Xif {$repeat} {
  908. X    set repeat repeat
  909. X} else {
  910. X    set repeat ""
  911. X}
  912. X
  913. Xif {[llength $tracks] != 0} {
  914. X    set tracks "tracks \"$tracks\""
  915. X} else {
  916. X    set tracks ""
  917. X}
  918. X
  919. Xif {$speed != 1.0} {
  920. X    set speed "reltempo $speed"
  921. X} else {
  922. X    set speed ""
  923. X}
  924. X
  925. Xif {[llength $filenames] == 0} {
  926. X    set midi_file stdin
  927. X    set done 0
  928. X    while {1} {
  929. X        if {[catch {midiread $midi_file} mfile]} {
  930. X            if {[string compare "$mfile" "EOF"] == 0} {
  931. X                exit 0
  932. X            } else {
  933. X                puts stderr $mfile
  934. X                exit 1
  935. X            }
  936. X        }
  937. X        eval "midiplay $repeat $tracks $speed $mfile"
  938. X        midifree $mfile
  939. X    }
  940. X} else {
  941. X    foreach file $filenames {
  942. X        if {[catch {open $file} midi_file]} {
  943. X            puts stderr $midi_file
  944. X            exit 1
  945. X        }
  946. X        if {[catch {midiread $midi_file} mfile]} {
  947. X            puts stderr $mfile
  948. X            exit 1
  949. X        }
  950. X        eval "midiplay $repeat $tracks $speed $mfile"
  951. X        midifree $mfile
  952. X        close $midi_file
  953. X    }
  954. X}
  955. END-of-tclm0.1/mplay
  956. exit
  957.  
  958.