home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / lang / tcl / 2359 < prev    next >
Encoding:
Text File  |  1993-01-12  |  27.6 KB  |  1,025 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 (7/7)
  5. Message-ID: <1993Jan12.203139.20129@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:31:39 GMT
  10. Lines: 1013
  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/minfo
  20. #    tclm0.1/mlib/mplayutil.c
  21. #
  22. echo x - tclm0.1/minfo
  23. sed 's/^X//' >tclm0.1/minfo << 'END-of-tclm0.1/minfo'
  24. X#!/usr/local/bin/tclm -f
  25. X#
  26. X# Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  27. X#
  28. X# Redistribution and use in source and binary forms, with or without
  29. X# modification, are permitted provided that the following conditions
  30. X# are met:
  31. X# 1. Redistributions of source code must retain the above copyright
  32. X#    notice, this list of conditions and the following disclaimer.
  33. X# 2. Redistributions in binary form must reproduce the above copyright
  34. X#    notice, this list of conditions and the following disclaimer in the
  35. X#    documentation and/or other materials provided with the distribution.
  36. X# 3. All advertising materials mentioning features or use of this software
  37. X#    must display the following acknowledgement:
  38. X#    This product includes software developed by Michael B. Durian.
  39. X# 4. The name of the the Author may be used to endorse or promote 
  40. X#    products derived from this software without specific prior written 
  41. X#    permission.
  42. X#
  43. X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  44. X# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  45. X# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  46. X# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  47. X# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  48. X# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  49. X# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  50. X# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  51. X# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  52. X# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  53. X# SUCH DAMAGE.
  54. X#
  55. X
  56. X# get filename arg
  57. Xif {[string compare [lindex $argv 0] "-f"] == 0} {
  58. X    set midi_file_name [lindex $argv 2]
  59. X} else {
  60. X    set midi_file_name [lindex $argv 0]
  61. X}
  62. X
  63. X# info on the different types of events
  64. Xset NORMAL 0xff
  65. Xset SYSEX 0xf0
  66. Xset EVENT(NORMAL) 0xff
  67. Xset EVENT(SYSEX) 0xf0
  68. Xset EVENT(METASEQNUM) 0x00
  69. Xset EVENT(METATEXT) 0x01
  70. Xset EVENT(METACPY) 0x02
  71. Xset EVENT(METASEQNAME) 0x03
  72. Xset EVENT(METAINSTNAME) 0x04
  73. Xset EVENT(METALYRIC) 0x05
  74. Xset EVENT(METAMARKER) 0x06
  75. Xset EVENT(METACUE) 0x07
  76. Xset EVENT(METACHANPREFIX) 0x20
  77. Xset EVENT(METAEOT) 0x2f
  78. Xset EVENT(METATEMPO) 0x51
  79. Xset EVENT(METASMPTE) 0x54
  80. Xset EVENT(METATIME) 0x58
  81. Xset EVENT(METAKEY) 0x59
  82. Xset EVENT(METASEQSPEC) 0x7f
  83. X
  84. X# clear running state
  85. Xset rstate 0
  86. X
  87. X# the different keys
  88. Xset key {"C flat" "G flat" "D flat" "A flat" "E flat" "B flat" "F" "C" "G" \
  89. X    "D" "A" "E" "B" "F sharp" "C sharp"}
  90. Xset key_class {"major" "minor"}
  91. X
  92. X#
  93. X# takes bytes that are in the ascii range and makes a string out of them
  94. X#
  95. Xproc make_string {bytes} {
  96. X
  97. X    foreach byte $bytes {
  98. X        set char [format "%c" $byte]
  99. X        append str $char
  100. X    }
  101. X    return $str
  102. X}
  103. X
  104. X#
  105. X#  etype identifies an event a formats it so it is human readable
  106. X#
  107. Xproc etype {event} {
  108. X    global EVENT
  109. X    global rstate
  110. X
  111. X    # look at the first byte
  112. X    set identifier [lindex $event 0]
  113. X    # if it has the high bit set then it is a new running state
  114. X    # otherwise it uses the previous running state.
  115. X    # if the later is the case we prepend the last running state
  116. X    # so the event looks whole
  117. X    if {[expr {$identifier & 0x80}]} {
  118. X        set rstate $identifier
  119. X    } else {
  120. X        set event [linsert $event 0 $rstate]
  121. X        set identifier $rstate
  122. X    }
  123. X    case $identifier in \
  124. X    0xff {
  125. X        # meta events
  126. X        set meta_type [lindex $event 1]
  127. X        case $meta_type in \
  128. X        $EVENT(METATEXT) {
  129. X            set str [make_string [lrange $event 3 end]]
  130. X            return "METATEXT $str"
  131. X        } $EVENT(METASEQNUM) {
  132. X            set seq_num [expr {[expr {[lindex $event 4] << 8]} + \
  133. X                [lindex $event 5]}]
  134. X            return "METASEQNUM $seq_num"
  135. X        } $EVENT(METACPY) {
  136. X            set str [make_string [lrange $event 3 end]]
  137. X            return "METACPY $str"
  138. X        } $EVENT(METASEQNAME) {
  139. X            set str [make_string [lrange $event 3 end]]
  140. X            return "METASEQNAME $str"
  141. X        } $EVENT(METAINSTNAME) {
  142. X            set str [make_string [lrange $event 3 end]]
  143. X            return "METAINSTNAME $str"
  144. X        } $EVENT(METALYRIC) {
  145. X            set str [make_string [lrange $event 3 end]]
  146. X            return "METALYRIC $str"
  147. X        } $EVENT(METAMARKER) {
  148. X            set str [make_string [lrange $event 3 end]]
  149. X            return "METAMARKER $str"
  150. X        } $EVENT(METACUE) {
  151. X            set str [make_string [lrange $event 3 end]]
  152. X            return "METACUE $str"
  153. X        } $EVENT(METACHANPREFIX) {
  154. X            return "METACHANPREFIX [lrange $event 3 end]"
  155. X        } $EVENT(METAEOT) {
  156. X            return "METAEOT"
  157. X        } $EVENT(METATEMPO) {
  158. X            set e3 [lindex $event 3]
  159. X            set se3 [expr {$e3 * 0x010000}]
  160. X            set e4 [lindex $event 4]
  161. X            set se4 [expr {$e4 * 0x0100}]
  162. X            set e5 [lindex $event 5]
  163. X            set usec [expr {$se3 + $se4 + $e5}]
  164. X            set bpm [expr {60000000 / $usec}]
  165. X            return "METATEMPO $usec usec/beat $bpm beats/min"
  166. X        } $EVENT(METASMPTE) {
  167. X            set hr [format "%d" [lindex $event 3]]
  168. X            set min [format "%d" [lindex $event 4]]
  169. X            set sec [format "%d" [lindex $event 5]]
  170. X            set fr [format "%d" [lindex $event 6]]
  171. X            set ffr [format "%d" [lindex $event 7]]
  172. X            return [concat "METASMPTE Hour $hr, Min. $min, " \
  173. X                "Sec. $sec, Frame $fr, Frac. Frame $ffr"]
  174. X        } $EVENT(METATIME) {
  175. X            set num [lindex $event 3]
  176. X            set dnum [format "%d" $num]
  177. X            set denom [lindex $event 4]
  178. X            set den 1
  179. X            for {set i  0} {$i < $denom} {incr i} {
  180. X                set den [expr {$den * 2}]
  181. X            }
  182. X            set cpmb [lindex $event 5]
  183. X            set dcpmb [format "%d" $cpmb]
  184. X            set _32 [lindex $event 6]
  185. X            set d_32 [format "%d" $_32]
  186. X            return [concat "METATIME $dnum/$den, $dcpmb clocks " \
  187. X                "/ met. beat, $d_32 32nd notes " \
  188. X                "/ 1/4 note"]
  189. X        } $EVENT(METAKEY) {
  190. X            global key
  191. X            global key_class
  192. X            set ind [expr {[lindex $event 3] + 7}]
  193. X            set keyname [lindex $key $ind]
  194. X            set class [lindex $key_class [lindex $event 4]]
  195. X            return "METAKEY $keyname $class"
  196. X        } default {
  197. X            return "UNKNOWN META"
  198. X        }
  199. X    } 0xf0 {
  200. X        # system exclusive event
  201. X        return "SYSEX"
  202. X    } 0x8? {
  203. X        # note off event
  204. X        set chan [expr {$identifier - 0x80}]
  205. X        set pitch [lindex $event 1]
  206. X        set vel [lindex $event 2]
  207. X        return "NOTEOFF channel $chan pitch $pitch velocity $vel"
  208. X    } 0x9? {
  209. X        # note on event
  210. X        set chan [expr {$identifier - 0x90}]
  211. X        set pitch [lindex $event 1]
  212. X        set vel [lindex $event 2]
  213. X        return "NOTEON channel $chan pitch $pitch velocity $vel"
  214. X    } 0xa? {
  215. X        # key pressure event
  216. X        set chan [expr {$identifier - 0xa0}]
  217. X        set pitch [lindex $event 1]
  218. X        set pres [lindex $event 2]
  219. X        return "KEY PRESSURE channel $chan pitch $pitch pressure $pres"
  220. X    } 0xb? {
  221. X        # parameter event
  222. X        set chan [expr {$identifier - 0xb0}]
  223. X        set param [lindex $event 1]
  224. X        set setting [lindex $event 2]
  225. X        return [concat "PARAMETER channel $chan parameter $param " \
  226. X            "setting $setting"]
  227. X    } 0xc? {
  228. X        # program change event
  229. X        set chan [expr {$identifier - 0xc0}]
  230. X        set prog [lindex $event 1]
  231. X        return "PROGRAM channel $chan program $prog"
  232. X    } 0xd? {
  233. X        # channel pressure event
  234. X        set chan [expr {$identifier - 0xd0}]
  235. X        set pres [lindex $event 1]
  236. X        return "CHANNEL PRESSURE channel $chan pressure $pres"
  237. X    } 0xe? {
  238. X        # pitch wheel event
  239. X        set chan [expr {$identifier - 0xe0}]
  240. X        set lo7 [lindex $event 1]
  241. X        set hi7 [lindex $event 2]
  242. X        set wheel [expr {[expr {$lo7 & 0x7f}] | \
  243. X            [expr {[expr {$hi7 << 7}] & 0x3f80}]}]
  244. X        return "PITCH WHEEL channel $chan val $wheel"
  245. X    } default {
  246. X        # anything that fell through the cracks
  247. X        return "DEFAULT $identifier"
  248. X    }
  249. X}
  250. X
  251. Xif {[string length $midi_file_name] == 0} {
  252. X    # if no filename is specified use stdin
  253. X    set midi_file stdin
  254. X    set midi_file_name stdin
  255. X} else {
  256. X    # check to see if the specified file exists and open it
  257. X    if {![file exists $midi_file_name]} then {
  258. X        puts stderr "Bad file name: $midi_file_name"
  259. X        exit 1
  260. X    } else {
  261. X        set midi_file [open $midi_file_name]
  262. X    }
  263. X}
  264. X
  265. X# read the midi file
  266. X# print out error if there is one
  267. Xif {[catch {midiread $midi_file} mfile]} {
  268. X    puts stderr $mfile
  269. X    exit 1
  270. X}
  271. Xputs stdout [format "%-16s = %s" "file name" $midi_file_name]
  272. Xputs stdout [format "%-16s = %s" "format" [midiconfig $mfile format]]
  273. Xputs stdout [format "%-16s = %s" "division" [midiconfig $mfile division]]
  274. Xset num_trks [midiconfig $mfile tracks]
  275. Xputs stdout [format "%-16s = %s" "number of tracks" $num_trks]
  276. X
  277. X# print out all the tracks
  278. Xfor {set track 0} {$track < $num_trks} {incr track} {
  279. X    puts stdout "\nTrack $track"
  280. X    set pos 0
  281. X    while {1} {
  282. X        # get an event
  283. X        set event [midiget $mfile $track]
  284. X        # get the timing part of the event
  285. X        set timing [miditiming $event]
  286. X        # convert timing to fixed length notation
  287. X        set fix [midivartofix $timing]
  288. X        # determine offset from start of track
  289. X        set pos [expr {$fix + $pos}]
  290. X        # get part of event that is not timing
  291. X        set rest [lrange $event [llength $timing] end]
  292. X        # determine the event type
  293. X        set event_type [etype $rest]
  294. X        # print it out
  295. X        set out [format "%6d: %s" $pos $event_type]
  296. X        puts stdout $out
  297. X        # break if it is the end of the file
  298. X        if {[string compare $event_type METAEOT] == 0} break
  299. X    }
  300. X}
  301. END-of-tclm0.1/minfo
  302. echo x - tclm0.1/mlib/mplayutil.c
  303. sed 's/^X//' >tclm0.1/mlib/mplayutil.c << 'END-of-tclm0.1/mlib/mplayutil.c'
  304. X/* mplayutil.c,v 1.3 1993/01/12 19:23:42 durian Exp */
  305. X/*
  306. X * Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  307. X *
  308. X * Redistribution and use in source and binary forms, with or without
  309. X * modification, are permitted provided that the following conditions
  310. X * are met:
  311. X * 1. Redistributions of source code must retain the above copyright
  312. X *    notice, this list of conditions and the following disclaimer.
  313. X * 2. Redistributions in binary form must reproduce the above copyright
  314. X *    notice, this list of conditions and the following disclaimer in the
  315. X *    documentation and/or other materials provided with the distribution.
  316. X * 3. All advertising materials mentioning features or use of this software
  317. X *    must display the following acknowledgement:
  318. X *    This product includes software developed by Michael B. Durian.
  319. X * 4. The name of the the Author may be used to endorse or promote 
  320. X *    products derived from this software without specific prior written 
  321. X *    permission.
  322. X *
  323. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  324. X * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  325. X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  326. X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  327. X * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  328. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  329. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  330. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  331. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  332. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  333. X * SUCH DAMAGE.
  334. X */
  335. X#ifdef MPU
  336. X#include <stdio.h>
  337. X#include <stdlib.h>
  338. X#include <unistd.h>
  339. X#include <sys/file.h>
  340. X#include <string.h>
  341. X#include <errno.h>
  342. X#include <sys/ioctl.h>
  343. X#include <i386/isa/midiioctl.h>
  344. X#include "mutil.h"
  345. X#include "mpu401.h"
  346. X#include "mplayutil.h"
  347. X
  348. X#define MAX_TRACKS 8
  349. X
  350. X/* global */
  351. Xdouble TempoRatio = 1.0;    /* this changes when clocks_per_met change */
  352. Xint StopRecording;
  353. Xint Verbose;
  354. Xint Tempo = 120;
  355. Xchar Key[15][10] = {"C flat", "G flat", "D flat", "A flat", "E flat",
  356. X    "B flat", "F", "C", "G", "D", "A", "E", "B", "F sharp", "C sharp"};
  357. X
  358. Xint
  359. Xplay_tracks(tracks, devs, num, t_scalar, repeat)
  360. X    TCHUNK *tracks;
  361. X    int *devs;
  362. X    int num;
  363. X    int t_scalar;
  364. X    int repeat;
  365. X{
  366. X
  367. X    return (record_tracks(tracks, devs, num, NULL, -1, t_scalar, repeat));
  368. X}
  369. X
  370. Xint
  371. Xrecord_tracks(p_tracks, p_devs, p_num, r_track, r_dev, t_scalar, repeat)
  372. X    TCHUNK *p_tracks;
  373. X    int *p_devs;
  374. X    int p_num;
  375. X    TCHUNK *r_track;
  376. X    int r_dev;
  377. X    int t_scalar;
  378. X    int repeat;
  379. X{
  380. X    struct timeval mwait;
  381. X    fd_set w_select;
  382. X    fd_set r_select;
  383. X    int click_fraction[16];
  384. X    int i;
  385. X#ifdef MIDI_DEBUG
  386. X    int j;
  387. X#endif
  388. X    int num_active;
  389. X    int select_return;
  390. X    int something_open;
  391. X    int *track_active;
  392. X
  393. X    num_active = p_num;
  394. X    if (p_num) {
  395. X        if ((track_active = (int *) malloc(sizeof(int) * p_num))
  396. X            == NULL)
  397. X            return (0);
  398. X        for (i = 0; i < p_num; i++)
  399. X            track_active[i] = 1;
  400. X    }
  401. X
  402. X    for (i = 0; i < 16; i++)
  403. X        click_fraction[i] = 0;
  404. X    something_open = 1;
  405. X    StopRecording = 0;
  406. X    do {
  407. X        while (something_open && !StopRecording) {
  408. X            /* select on open play tracks */
  409. X            FD_ZERO(&w_select);
  410. X            for (i = 0; i < p_num; i++)
  411. X                if (track_active[i])
  412. X                    FD_SET(p_devs[i], &w_select);
  413. X            FD_ZERO(&r_select);
  414. X            if (r_dev != -1)
  415. X                FD_SET(r_dev, &r_select);
  416. X            mwait.tv_sec = 0;
  417. X            mwait.tv_usec = 100000;
  418. X            if ((select_return = select(getdtablesize(), &r_select,
  419. X                &w_select, NULL, &mwait)) == -1) {
  420. X                if (errno == EINTR)
  421. X                    break;
  422. X                else {
  423. X                    sprintf(MidiError,
  424. X                        "Error in select: %s",
  425. X                        sys_errlist[errno]);
  426. X                    return (0);
  427. X                }
  428. X            }
  429. X            if (select_return == 0)
  430. X                continue;
  431. X    
  432. X            /* write event to non-blocked one */
  433. X            for (i = 0; i < p_num && !StopRecording; i++) {
  434. X                if (!track_active[i] || !FD_ISSET(p_devs[i],
  435. X                    &w_select))
  436. X                    continue;
  437. X
  438. X                something_open = process_play_event(i,
  439. X                    &p_tracks[i], p_devs[i], &track_active[i],
  440. X                    &num_active, t_scalar);
  441. X                if (!track_active[i] && repeat) {
  442. X                    rewind_track(&p_tracks[i]);
  443. X                    track_active[i] = 1;
  444. X                    num_active++;
  445. X                    something_open = 1;
  446. X                }
  447. X            }
  448. X            if (r_dev != -1 && FD_ISSET(r_dev, &r_select)) {
  449. X
  450. X                if (!process_record_event(r_dev, r_track))
  451. X                    return (0);
  452. X            }
  453. X        }
  454. X    } while (repeat && !StopRecording);
  455. X
  456. X    if (!StopRecording) {
  457. X        for (i = 0; i < p_num; i++)
  458. X            if (ioctl(p_devs[i], MFLUSHQ, NULL) == -1) {
  459. X                sprintf(MidiError,
  460. X                    "Error flushing queue for track %d", i);
  461. X            }
  462. X    } else {
  463. X        /* flush any delays stuck in board2smf */
  464. X/*
  465. X        flush_event(r_track);
  466. X*/
  467. X    }
  468. X    if (p_num)
  469. X        free(track_active);
  470. X    return (1);
  471. X}
  472. X
  473. Xint
  474. Xprocess_play_event(track_num, p_track, p_dev, track_active, num_active,
  475. X    t_scalar)
  476. X    int track_num;
  477. X    TCHUNK *p_track;
  478. X    int p_dev;
  479. X    int *track_active;
  480. X    int *num_active;
  481. X    int t_scalar;
  482. X{
  483. X    EVENT_TYPE event_type;
  484. X    static int need_event[16] =
  485. X        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 
  486. X    int event_size;
  487. X#ifdef MIDI_DEBUG
  488. X    int j;
  489. X#endif
  490. X    int smf_size;
  491. X    int something_open;
  492. X    int valid_event;
  493. X    unsigned char smf_event[2048];
  494. X    unsigned char event[2048];
  495. X
  496. X    something_open = 1;
  497. X    valid_event = 0;
  498. X    do {
  499. X        if (!need_event[track_num])
  500. X            event_size = smf2board(track_num, NULL, smf_size,
  501. X                event, t_scalar, &need_event[track_num],
  502. X                &event_type);
  503. X        else {
  504. X            smf_size = get_smf_event(p_track, smf_event,
  505. X                &event_type);
  506. X            if (smf_size == -1) {
  507. X                sprintf(MidiError, "Error reading event");
  508. X                return (0);
  509. X            } else if (smf_size == 0) {
  510. X                *track_active = 0;
  511. X                valid_event = 1;
  512. X                if (--(*num_active) == 0)
  513. X                    something_open = 0;
  514. X                break;
  515. X            }
  516. X            event_size = smf2board(track_num, smf_event, smf_size,
  517. X                event, t_scalar, &need_event[track_num],
  518. X                &event_type);
  519. X        }
  520. X
  521. X#ifdef MIDI_DEBUG
  522. X        printf("track %d: ", track_num);
  523. X        for (j = 0; j < event_size; j++)
  524. X            printf("0x%02x ", event[j]);
  525. X        printf("\n");
  526. X        fflush(stdout);
  527. X#endif
  528. X        switch(send_event(p_dev, event, event_size,
  529. X            event_type, track_num == 0)) {
  530. X        case SEND_ERROR:
  531. X            return (0);
  532. X        case SEND_VALID:
  533. X            valid_event = 1;
  534. X            break;
  535. X        case SEND_INVALID:
  536. X            valid_event = 0;
  537. X            break;
  538. X        case SEND_DONE:
  539. X            *track_active = 0;
  540. X            valid_event = 1;
  541. X            if (--(*num_active) == 0)
  542. X                something_open = 0;
  543. X            break;
  544. X        }
  545. X    } while (!valid_event && !StopRecording);
  546. X    return(something_open);
  547. X}
  548. X
  549. Xint
  550. Xprocess_record_event(dev, r_track)
  551. X    int dev;
  552. X    TCHUNK *r_track;
  553. X{
  554. X    int event_size;
  555. X    int events_delta;
  556. X    int events_pos;
  557. X    int events_size;
  558. X#ifdef MIDI_DEBUG
  559. X    int i;
  560. X#endif
  561. X    int smf_size;
  562. X    unsigned char events[256];
  563. X    unsigned char event_data[256];
  564. X    unsigned char smf_event[256];
  565. X    unsigned char *events_ptr;
  566. X
  567. X    if ((events_size = read(dev, events, 256)) == -1) {
  568. X        perror("");
  569. X        sprintf(MidiError, "Couldn't read from MIDI board");
  570. X        return (0);
  571. X    }
  572. X#ifdef MIDI_DEBUG
  573. X    printf("\n");
  574. X    printf("board:");
  575. X    for (i = 0; i < events_size; i++)
  576. X        printf(" 0x%02x", events[i]);
  577. X    printf("\n");
  578. X#endif
  579. X    events_ptr = events;
  580. X    events_pos = 0;
  581. X    do {
  582. X        if((events_delta = get_board_event(events_ptr, events_size,
  583. X            event_data, &event_size)) == -1) {
  584. X            sprintf(MidiError, "Couldn't get board event "
  585. X                "from stream");
  586. X            return (0);
  587. X        }
  588. X        events_ptr += events_delta;
  589. X        events_pos += events_delta;
  590. X#ifdef MIDI_DEBUG
  591. X        printf("single event:");
  592. X        for (i = 0; i < event_size; i++)
  593. X            printf(" 0x%02x", event_data[i]);
  594. X        printf("\n");
  595. X#endif
  596. X
  597. X        board2smf(event_data, event_size, smf_event, &smf_size);
  598. X#ifdef MIDI_DEBUG
  599. X        printf("smf:");
  600. X        for (i = 0; i < smf_size; i++)
  601. X            printf(" 0x%02x", smf_event[i]);
  602. X        printf("\n");
  603. X#endif
  604. X        if (smf_size > 0)
  605. X            if (!put_smf_event(r_track, smf_event, smf_size)) {
  606. X                sprintf(MidiError, "Couldn't put event "
  607. X                    "in record track");
  608. X                return (0);
  609. X            }
  610. X    } while (events_pos < events_size);
  611. X    return(1);
  612. X}
  613. X
  614. Xvoid
  615. Xflush_event(r_track)
  616. X    TCHUNK *r_track;
  617. X{
  618. X    int smf_size;
  619. X    unsigned char flush_event[] = {0x00, 0xf8};
  620. X    unsigned char smf_event[256];
  621. X
  622. X    board2smf(flush_event, sizeof(flush_event), smf_event, &smf_size);
  623. X
  624. X    if (!put_smf_event(r_track, smf_event, smf_size)) {
  625. X        sprintf(MidiError, "Couldn't put flush event");
  626. X    }
  627. X}
  628. X
  629. Xvoid
  630. Xstop_recording()
  631. X{
  632. X    StopRecording = 1;
  633. X}
  634. X
  635. X
  636. XSEND_VAL
  637. Xsend_event(dev, event, event_size, event_type, conductor)
  638. X    int dev;
  639. X    unsigned char *event;
  640. X    int event_size;
  641. X    EVENT_TYPE event_type;
  642. X    int conductor;
  643. X{
  644. X    SEND_VAL return_val;
  645. X    static int clocks_per_beat = 24;
  646. X    int num_written;
  647. X    short seq_num;
  648. X    unsigned char time_event[10];
  649. X
  650. X    switch (event_type) {
  651. X    case NORMAL:
  652. X        if ((num_written = write(dev, event, event_size)) == -1) {
  653. X            sprintf(MidiError, "Couldn't write to MIDI board: %s",
  654. X                sys_errlist[errno]);
  655. X            return_val = SEND_ERROR;
  656. X            break;
  657. X        }
  658. X        return_val = SEND_VALID;
  659. X        break;
  660. X    case METASEQNUM:
  661. X        seq_num = event[4] << 8 + event[5];
  662. X        if (Verbose)
  663. X            printf("Sequence number %d\n", seq_num);
  664. X        if (event[0] == 0)
  665. X            return_val = SEND_INVALID;
  666. X        else {
  667. X            event[1] = MIDI_NOOP;
  668. X            if (write(dev, event, 2) == -1) {
  669. X                sprintf(MidiError, "Couldn't write to "
  670. X                    "MIDI board: %s", sys_errlist[errno]);
  671. X                return_val = SEND_ERROR;
  672. X                break;
  673. X            }
  674. X            return_val = SEND_VALID;
  675. X        }
  676. X        break;
  677. X    case METATEXT:
  678. X        event[event_size] = '\0';
  679. X        if (Verbose)
  680. X            printf("METATEXT: %s\n", &event[4]);
  681. X        if (event[0] == 0)
  682. X            return_val = SEND_INVALID;
  683. X        else {
  684. X            event[1] = MIDI_NOOP;
  685. X            if (write(dev, event, 2) == -1) {
  686. X                sprintf(MidiError, "Couldn't write to "
  687. X                    "MIDI board: %s", sys_errlist[errno]);
  688. X                return_val = SEND_ERROR;
  689. X                break;
  690. X            }
  691. X            return_val = SEND_VALID;
  692. X        }
  693. X        break;
  694. X    case METACPY:
  695. X        event[event_size] = '\0';
  696. X        if (Verbose)
  697. X            printf("METACPY: %s\n", &event[4]);
  698. X        if (event[0] == 0)
  699. X            return_val = SEND_INVALID;
  700. X        else {
  701. X            event[1] = MIDI_NOOP;
  702. X            if (write(dev, event, 2) == -1) {
  703. X                sprintf(MidiError, "Couldn't write to "
  704. X                    "MIDI board: %s", sys_errlist[errno]);
  705. X                return_val = SEND_ERROR;
  706. X                break;
  707. X            }
  708. X            return_val = SEND_VALID;
  709. X        }
  710. X        break;
  711. X    case METASEQNAME:
  712. X        event[event_size] = '\0';
  713. X        if (Verbose)
  714. X            printf("METASEQNAME: %s\n", &event[4]);
  715. X        if (event[0] == 0)
  716. X            return_val = SEND_INVALID;
  717. X        else {
  718. X            event[1] = MIDI_NOOP;
  719. X            if (write(dev, event, 2) == -1) {
  720. X                sprintf(MidiError, "Couldn't write to "
  721. X                    "MIDI board: %s", sys_errlist[errno]);
  722. X                return_val = SEND_ERROR;
  723. X                break;
  724. X            }
  725. X            return_val = SEND_VALID;
  726. X        }
  727. X        break;
  728. X    case METAINSTNAME:
  729. X        event[event_size] = '\0';
  730. X        if (Verbose)
  731. X            printf("METAINSTNAME: %s\n", &event[4]);
  732. X        if (event[0] == 0)
  733. X            return_val = SEND_INVALID;
  734. X        else {
  735. X            event[1] = MIDI_NOOP;
  736. X            if (write(dev, event, 2) == -1) {
  737. X                sprintf(MidiError, "Couldn't write to "
  738. X                    "MIDI board: %s", sys_errlist[errno]);
  739. X                return_val = SEND_ERROR;
  740. X                break;
  741. X            }
  742. X            return_val = SEND_VALID;
  743. X        }
  744. X        break;
  745. X    case METALYRIC:
  746. X        event[event_size] = '\0';
  747. X        if (Verbose)
  748. X            printf("METALYRIC: %s\n", &event[4]);
  749. X        if (event[0] == 0)
  750. X            return_val = SEND_INVALID;
  751. X        else {
  752. X            event[1] = MIDI_NOOP;
  753. X            if (write(dev, event, 2) == -1) {
  754. X                sprintf(MidiError, "Couldn't write to "
  755. X                    "MIDI board: %s", sys_errlist[errno]);
  756. X                return_val = SEND_ERROR;
  757. X                break;
  758. X            }
  759. X            return_val = SEND_VALID;
  760. X        }
  761. X        break;
  762. X    case METAMARKER:
  763. X        event[event_size] = '\0';
  764. X        if (Verbose)
  765. X            printf("METAMARKER: %s\n", &event[4]);
  766. X        if (event[0] == 0)
  767. X            return_val = SEND_INVALID;
  768. X        else {
  769. X            event[1] = MIDI_NOOP;
  770. X            if (write(dev, event, 2) == -1) {
  771. X                sprintf(MidiError, "Couldn't write to "
  772. X                    "MIDI board: %s", sys_errlist[errno]);
  773. X                return_val = SEND_ERROR;
  774. X                break;
  775. X            }
  776. X            return_val = SEND_VALID;
  777. X        }
  778. X        break;
  779. X    case METACUE:
  780. X        event[event_size] = '\0';
  781. X        if (Verbose)
  782. X            printf("METACUE: %s\n", &event[4]);
  783. X        if (event[0] == 0)
  784. X            return_val = SEND_INVALID;
  785. X        else {
  786. X            event[1] = MIDI_NOOP;
  787. X            if (write(dev, event, 2) == -1) {
  788. X                sprintf(MidiError, "Couldn't write to "
  789. X                    "MIDI board: %s", sys_errlist[errno]);
  790. X                return_val = SEND_ERROR;
  791. X                break;
  792. X            }
  793. X            return_val = SEND_VALID;
  794. X        }
  795. X        break;
  796. X    case METACHANPREFIX:
  797. X        /* I have no data on how this is formatted */
  798. X        if (event[0] == 0)
  799. X            return_val = SEND_INVALID;
  800. X        else {
  801. X            event[1] = MIDI_NOOP;
  802. X            if (write(dev, event, 2) == -1) {
  803. X                sprintf(MidiError, "Couldn't write to "
  804. X                    "MIDI board: %s", sys_errlist[errno]);
  805. X                return_val = SEND_ERROR;
  806. X                break;
  807. X            }
  808. X            return_val = SEND_VALID;
  809. X        }
  810. X        break;
  811. X    case METAEOT:
  812. X        event[1] = MIDI_NOOP;
  813. X        if (write(dev, event, 2) == -1) {
  814. X            sprintf(MidiError, "Couldn't write to "
  815. X                "MIDI board:", sys_errlist[errno]);
  816. X            return_val = SEND_ERROR;
  817. X            break;
  818. X        }
  819. X        return_val = SEND_DONE;
  820. X        break;
  821. X    case METATEMPO:
  822. X        /* only do this for the conductor track - pos 0 */
  823. X        if (conductor) {
  824. X            /* just the byte meaningful to the board */
  825. X            event[1] = (unsigned char) (MSETBASETMP & 0xff);
  826. X            /* convert usec / beat to beats / min */
  827. X            event[2] = TempoRatio * (60 * 1000000) /
  828. X                (event[4] * 0x010000 + event[5] * 0x0100 +
  829. X                event[6]);
  830. X            Tempo = event[2];
  831. X            if (Verbose)
  832. X                printf("METATEMPO: Beats Per Minute: %d\n",
  833. X                    event[2]);
  834. X            if (write(dev, event, 3) == -1) {
  835. X                sprintf(MidiError, "Couldn't write to "
  836. X                    "MIDI board: %s", sys_errlist[errno]);
  837. X                return_val = SEND_ERROR;
  838. X                break;
  839. X            }
  840. X            return_val = SEND_VALID;
  841. X        } else {
  842. X            event[1] = MIDI_NOOP;
  843. X            if (write(dev, event, 2) == -1) {
  844. X                sprintf(MidiError, "Couldn't write to "
  845. X                    "MIDI board: %s", sys_errlist[errno]);
  846. X                return_val = SEND_ERROR;
  847. X                break;
  848. X            }
  849. X            return_val = SEND_VALID;
  850. X        }
  851. X        break;
  852. X    case METASMPTE:
  853. X        /* Not sure on this one */
  854. X        if (Verbose) {
  855. X            printf("METASMPTE: Hour %d Minute %d Second %d "
  856. X                "Frame %d Fractional Frame %d\n",
  857. X                event[4], event[5], event[6], event[7],
  858. X                event[8]);
  859. X        }
  860. X        if (event[0] == 0)
  861. X            return_val = SEND_INVALID;
  862. X        else {
  863. X            event[1] = MIDI_NOOP;
  864. X            if (write(dev, event, 2) == -1) {
  865. X                sprintf(MidiError, "Couldn't write to "
  866. X                    "MIDI board: %s", sys_errlist[errno]);
  867. X                return_val = SEND_ERROR;
  868. X                break;
  869. X            }
  870. X            return_val = SEND_VALID;
  871. X        }
  872. X        break;
  873. X    case METATIME:
  874. X        if (conductor) {
  875. X            if (Verbose)
  876. X                printf("METATIME: %d / %d "
  877. X                    "Clocks per met beat = %d\n",
  878. X                    event[4], event[5], event[6]);
  879. X            time_event[0] = event[0];
  880. X            time_event[1] = (unsigned char) (MSETBPM & 0xff);
  881. X            /* bpm = numerator of time sig */
  882. X            time_event[2] = event[4];
  883. X            /* no time delay */
  884. X            time_event[3] = 0;
  885. X            time_event[4] = (unsigned char) (MSETMETFRQ & 0xff);
  886. X            /* met freq = byte seven in time sig */
  887. X            time_event[5] = event[6];
  888. X            /*
  889. X             * if the clocks per met changes we should adjust
  890. X             * the tempo accordingly - at least until I figure
  891. X             * out a better way of doing this.
  892. X             */
  893. X            /* new clock_per_bear over old */
  894. X            TempoRatio = (double)event[6] / clocks_per_beat;
  895. X            Tempo = Tempo * TempoRatio;
  896. X            time_event[6] = 0;
  897. X            time_event[7] = (unsigned char) (MSETBASETMP & 0xff);
  898. X            time_event[8] = Tempo;
  899. X            if (write(dev, time_event, 9) == -1) {
  900. X                sprintf(MidiError, "Couldn't write to "
  901. X                    "MIDI board: %s", sys_errlist[errno]);
  902. X                return_val = SEND_ERROR;
  903. X                break;
  904. X            }
  905. X            clocks_per_beat = event[6];
  906. X            return_val = SEND_VALID;
  907. X        } else {
  908. X            event[1] = MIDI_NOOP;
  909. X            if (write(dev, event, 2) == -1) {
  910. X                sprintf(MidiError, "Couldn't write to "
  911. X                    "MIDI board: %s", sys_errlist[errno]);
  912. X                return_val = SEND_ERROR;
  913. X                break;
  914. X            }
  915. X            return_val = SEND_VALID;
  916. X        }
  917. X        break;
  918. X    case METAKEY:
  919. X        if (Verbose)
  920. X            printf("METAKEY: %s %s\n", Key[(signed char)event[4]
  921. X                + 7], event[5] ? "minor" : "major");
  922. X        if (event[0] == 0)
  923. X            return_val = SEND_INVALID;
  924. X        else {
  925. X            event[1] = MIDI_NOOP;
  926. X            if (write(dev, event, 2) == -1) {
  927. X                sprintf(MidiError, "Couldn't write to "
  928. X                    "MIDI board: %s", sys_errlist[errno]);
  929. X                return_val = SEND_ERROR;
  930. X                break;
  931. X            }
  932. X            return_val = SEND_VALID;
  933. X        }
  934. X        break;
  935. X    default:
  936. X        if (event[0] == 0)
  937. X            return_val = SEND_INVALID;
  938. X        else {
  939. X            event[1] = MIDI_NOOP;
  940. X            if (write(dev, event, 2) == -1) {
  941. X                sprintf(MidiError, "Couldn't write to "
  942. X                    "MIDI board: %s", sys_errlist[errno]);
  943. X                return_val = SEND_ERROR;
  944. X                break;
  945. X            }
  946. X            return_val = SEND_VALID;
  947. X        }
  948. X        break;
  949. X    }
  950. X
  951. X    return (return_val);
  952. X}
  953. X
  954. Xint
  955. Xopen_midi_devices(hchunk, spec_tracks, num, devs, active_mask)
  956. X    HCHUNK *hchunk;
  957. X    TRKS *spec_tracks;
  958. X    int *num;
  959. X    int *devs;
  960. X    unsigned char *active_mask;
  961. X{
  962. X    int cond_on;
  963. X    int dev_counter;
  964. X    int i;
  965. X    int j;
  966. X    char dev_name[100];
  967. X
  968. X    cond_on = 0;
  969. X    j = 0;
  970. X    if (hchunk->format == 0) {
  971. X        if ((devs[j++] = open("/dev/midicond", O_WRONLY | O_NONBLOCK,
  972. X            0)) == -1) {
  973. X            sprintf(MidiError, "Coudln't open conductor track: %s",
  974. X                sys_errlist[errno]);
  975. X            return (-1);
  976. X        }
  977. X        cond_on = 1;
  978. X    }
  979. X
  980. X    for (i = 0; i < spec_tracks->num_tracks && !cond_on; i++)
  981. X        if (spec_tracks->tracks[i] == 0) {
  982. X            if ((devs[j++] = open("/dev/midicond", O_WRONLY |
  983. X                O_NONBLOCK, 0)) == -1) {
  984. X                sprintf(MidiError,
  985. X                    "Coudln't open conductor track: %s",
  986. X                    sys_errlist[errno]);
  987. X                return (-1);
  988. X            }
  989. X            cond_on = 1;
  990. X        }
  991. X
  992. X    dev_counter = 0;
  993. X    *active_mask = 0;
  994. X    for (i = j; i < *num; i++) {
  995. X        if (dev_counter == MAX_TRACKS) {
  996. X            sprintf(MidiError, "Too many play tracks (%d).  "
  997. X               "Only using first %d", *num - cond_on, MAX_TRACKS);
  998. X            *num = MAX_TRACKS + cond_on;
  999. X            break;
  1000. X        }
  1001. X
  1002. X        sprintf(dev_name, "/dev/midi%d", dev_counter);
  1003. X        if ((devs[j++] = open(dev_name, O_WRONLY | O_NONBLOCK, 0))
  1004. X            == -1) {
  1005. X            sprintf(MidiError, "Coudln't open midi track %d: %s",
  1006. X                dev_counter, sys_errlist[errno]);
  1007. X            return (-1);
  1008. X        }
  1009. X        *active_mask |= (unsigned char)(1 << dev_counter++);
  1010. X    }
  1011. X
  1012. X    return (cond_on);
  1013. X}
  1014. X
  1015. Xvoid
  1016. Xset_midi_verbose(v)
  1017. X    int v;
  1018. X{
  1019. X    Verbose = v;
  1020. X}
  1021. X#endif
  1022. END-of-tclm0.1/mlib/mplayutil.c
  1023. exit
  1024.  
  1025.