From: durian@advtech.uswest.com (Mike Durian)
Subject: tclm0.1 - tcl with MIDI extensions (7/7)
Organization: U S WEST Advanced Technologies
Date: Tue, 12 Jan 1993 20:31:39 GMT

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	tclm0.1/minfo
#	tclm0.1/mlib/mplayutil.c
#
echo x - tclm0.1/minfo
sed 's/^X//' >tclm0.1/minfo << 'END-of-tclm0.1/minfo'
X#!/usr/local/bin/tclm -f
X#
X# Copyright (c) 1993 Michael B. Durian.  All rights reserved.
X#
X# Redistribution and use in source and binary forms, with or without
X# modification, are permitted provided that the following conditions
X# are met:
X# 1. Redistributions of source code must retain the above copyright
X#    notice, this list of conditions and the following disclaimer.
X# 2. Redistributions in binary form must reproduce the above copyright
X#    notice, this list of conditions and the following disclaimer in the
X#    documentation and/or other materials provided with the distribution.
X# 3. All advertising materials mentioning features or use of this software
X#    must display the following acknowledgement:
X#	This product includes software developed by Michael B. Durian.
X# 4. The name of the the Author may be used to endorse or promote 
X#    products derived from this software without specific prior written 
X#    permission.
X#
X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
X# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
X# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
X# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X# SUCH DAMAGE.
X#
X
X# get filename arg
Xif {[string compare [lindex $argv 0] "-f"] == 0} {
X	set midi_file_name [lindex $argv 2]
X} else {
X	set midi_file_name [lindex $argv 0]
X}
X
X# info on the different types of events
Xset NORMAL 0xff
Xset SYSEX 0xf0
Xset EVENT(NORMAL) 0xff
Xset EVENT(SYSEX) 0xf0
Xset EVENT(METASEQNUM) 0x00
Xset EVENT(METATEXT) 0x01
Xset EVENT(METACPY) 0x02
Xset EVENT(METASEQNAME) 0x03
Xset EVENT(METAINSTNAME) 0x04
Xset EVENT(METALYRIC) 0x05
Xset EVENT(METAMARKER) 0x06
Xset EVENT(METACUE) 0x07
Xset EVENT(METACHANPREFIX) 0x20
Xset EVENT(METAEOT) 0x2f
Xset EVENT(METATEMPO) 0x51
Xset EVENT(METASMPTE) 0x54
Xset EVENT(METATIME) 0x58
Xset EVENT(METAKEY) 0x59
Xset EVENT(METASEQSPEC) 0x7f
X
X# clear running state
Xset rstate 0
X
X# the different keys
Xset key {"C flat" "G flat" "D flat" "A flat" "E flat" "B flat" "F" "C" "G" \
X    "D" "A" "E" "B" "F sharp" "C sharp"}
Xset key_class {"major" "minor"}
X
X#
X# takes bytes that are in the ascii range and makes a string out of them
X#
Xproc make_string {bytes} {
X
X	foreach byte $bytes {
X		set char [format "%c" $byte]
X		append str $char
X	}
X	return $str
X}
X
X#
X#  etype identifies an event a formats it so it is human readable
X#
Xproc etype {event} {
X	global EVENT
X	global rstate
X
X	# look at the first byte
X	set identifier [lindex $event 0]
X	# if it has the high bit set then it is a new running state
X	# otherwise it uses the previous running state.
X	# if the later is the case we prepend the last running state
X	# so the event looks whole
X	if {[expr {$identifier & 0x80}]} {
X		set rstate $identifier
X	} else {
X		set event [linsert $event 0 $rstate]
X		set identifier $rstate
X	}
X	case $identifier in \
X	0xff {
X		# meta events
X		set meta_type [lindex $event 1]
X		case $meta_type in \
X		$EVENT(METATEXT) {
X			set str [make_string [lrange $event 3 end]]
X			return "METATEXT $str"
X		} $EVENT(METASEQNUM) {
X			set seq_num [expr {[expr {[lindex $event 4] << 8]} + \
X			    [lindex $event 5]}]
X			return "METASEQNUM $seq_num"
X		} $EVENT(METACPY) {
X			set str [make_string [lrange $event 3 end]]
X			return "METACPY $str"
X		} $EVENT(METASEQNAME) {
X			set str [make_string [lrange $event 3 end]]
X			return "METASEQNAME $str"
X		} $EVENT(METAINSTNAME) {
X			set str [make_string [lrange $event 3 end]]
X			return "METAINSTNAME $str"
X		} $EVENT(METALYRIC) {
X			set str [make_string [lrange $event 3 end]]
X			return "METALYRIC $str"
X		} $EVENT(METAMARKER) {
X			set str [make_string [lrange $event 3 end]]
X			return "METAMARKER $str"
X		} $EVENT(METACUE) {
X			set str [make_string [lrange $event 3 end]]
X			return "METACUE $str"
X		} $EVENT(METACHANPREFIX) {
X			return "METACHANPREFIX [lrange $event 3 end]"
X		} $EVENT(METAEOT) {
X			return "METAEOT"
X		} $EVENT(METATEMPO) {
X			set e3 [lindex $event 3]
X			set se3 [expr {$e3 * 0x010000}]
X			set e4 [lindex $event 4]
X			set se4 [expr {$e4 * 0x0100}]
X			set e5 [lindex $event 5]
X			set usec [expr {$se3 + $se4 + $e5}]
X			set bpm [expr {60000000 / $usec}]
X			return "METATEMPO $usec usec/beat $bpm beats/min"
X		} $EVENT(METASMPTE) {
X			set hr [format "%d" [lindex $event 3]]
X			set min [format "%d" [lindex $event 4]]
X			set sec [format "%d" [lindex $event 5]]
X			set fr [format "%d" [lindex $event 6]]
X			set ffr [format "%d" [lindex $event 7]]
X			return [concat "METASMPTE Hour $hr, Min. $min, " \
X			    "Sec. $sec, Frame $fr, Frac. Frame $ffr"]
X		} $EVENT(METATIME) {
X			set num [lindex $event 3]
X			set dnum [format "%d" $num]
X			set denom [lindex $event 4]
X			set den 1
X			for {set i  0} {$i < $denom} {incr i} {
X				set den [expr {$den * 2}]
X			}
X			set cpmb [lindex $event 5]
X			set dcpmb [format "%d" $cpmb]
X			set _32 [lindex $event 6]
X			set d_32 [format "%d" $_32]
X			return [concat "METATIME $dnum/$den, $dcpmb clocks " \
X			    "/ met. beat, $d_32 32nd notes " \
X			    "/ 1/4 note"]
X		} $EVENT(METAKEY) {
X			global key
X			global key_class
X			set ind [expr {[lindex $event 3] + 7}]
X			set keyname [lindex $key $ind]
X			set class [lindex $key_class [lindex $event 4]]
X			return "METAKEY $keyname $class"
X		} default {
X			return "UNKNOWN META"
X		}
X	} 0xf0 {
X		# system exclusive event
X		return "SYSEX"
X	} 0x8? {
X		# note off event
X		set chan [expr {$identifier - 0x80}]
X		set pitch [lindex $event 1]
X		set vel [lindex $event 2]
X		return "NOTEOFF channel $chan pitch $pitch velocity $vel"
X	} 0x9? {
X		# note on event
X		set chan [expr {$identifier - 0x90}]
X		set pitch [lindex $event 1]
X		set vel [lindex $event 2]
X		return "NOTEON channel $chan pitch $pitch velocity $vel"
X	} 0xa? {
X		# key pressure event
X		set chan [expr {$identifier - 0xa0}]
X		set pitch [lindex $event 1]
X		set pres [lindex $event 2]
X		return "KEY PRESSURE channel $chan pitch $pitch pressure $pres"
X	} 0xb? {
X		# parameter event
X		set chan [expr {$identifier - 0xb0}]
X		set param [lindex $event 1]
X		set setting [lindex $event 2]
X		return [concat "PARAMETER channel $chan parameter $param " \
X		    "setting $setting"]
X	} 0xc? {
X		# program change event
X		set chan [expr {$identifier - 0xc0}]
X		set prog [lindex $event 1]
X		return "PROGRAM channel $chan program $prog"
X	} 0xd? {
X		# channel pressure event
X		set chan [expr {$identifier - 0xd0}]
X		set pres [lindex $event 1]
X		return "CHANNEL PRESSURE channel $chan pressure $pres"
X	} 0xe? {
X		# pitch wheel event
X		set chan [expr {$identifier - 0xe0}]
X		set lo7 [lindex $event 1]
X		set hi7 [lindex $event 2]
X		set wheel [expr {[expr {$lo7 & 0x7f}] | \
X		    [expr {[expr {$hi7 << 7}] & 0x3f80}]}]
X		return "PITCH WHEEL channel $chan val $wheel"
X	} default {
X		# anything that fell through the cracks
X		return "DEFAULT $identifier"
X	}
X}
X
Xif {[string length $midi_file_name] == 0} {
X	# if no filename is specified use stdin
X	set midi_file stdin
X	set midi_file_name stdin
X} else {
X	# check to see if the specified file exists and open it
X	if {![file exists $midi_file_name]} then {
X		puts stderr "Bad file name: $midi_file_name"
X		exit 1
X	} else {
X		set midi_file [open $midi_file_name]
X	}
X}
X
X# read the midi file
X# print out error if there is one
Xif {[catch {midiread $midi_file} mfile]} {
X	puts stderr $mfile
X	exit 1
X}
Xputs stdout [format "%-16s = %s" "file name" $midi_file_name]
Xputs stdout [format "%-16s = %s" "format" [midiconfig $mfile format]]
Xputs stdout [format "%-16s = %s" "division" [midiconfig $mfile division]]
Xset num_trks [midiconfig $mfile tracks]
Xputs stdout [format "%-16s = %s" "number of tracks" $num_trks]
X
X# print out all the tracks
Xfor {set track 0} {$track < $num_trks} {incr track} {
X	puts stdout "\nTrack $track"
X	set pos 0
X	while {1} {
X		# get an event
X		set event [midiget $mfile $track]
X		# get the timing part of the event
X		set timing [miditiming $event]
X		# convert timing to fixed length notation
X		set fix [midivartofix $timing]
X		# determine offset from start of track
X		set pos [expr {$fix + $pos}]
X		# get part of event that is not timing
X		set rest [lrange $event [llength $timing] end]
X		# determine the event type
X		set event_type [etype $rest]
X		# print it out
X		set out [format "%6d: %s" $pos $event_type]
X		puts stdout $out
X		# break if it is the end of the file
X		if {[string compare $event_type METAEOT] == 0} break
X	}
X}
END-of-tclm0.1/minfo
echo x - tclm0.1/mlib/mplayutil.c
sed 's/^X//' >tclm0.1/mlib/mplayutil.c << 'END-of-tclm0.1/mlib/mplayutil.c'
X/* mplayutil.c,v 1.3 1993/01/12 19:23:42 durian Exp */
X/*
X * Copyright (c) 1993 Michael B. Durian.  All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by Michael B. Durian.
X * 4. The name of the the Author may be used to endorse or promote 
X *    products derived from this software without specific prior written 
X *    permission.
X *
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
X * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
X * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X#ifdef MPU
X#include <stdio.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <sys/file.h>
X#include <string.h>
X#include <errno.h>
X#include <sys/ioctl.h>
X#include <i386/isa/midiioctl.h>
X#include "mutil.h"
X#include "mpu401.h"
X#include "mplayutil.h"
X
X#define MAX_TRACKS 8
X
X/* global */
Xdouble TempoRatio = 1.0;	/* this changes when clocks_per_met change */
Xint StopRecording;
Xint Verbose;
Xint Tempo = 120;
Xchar Key[15][10] = {"C flat", "G flat", "D flat", "A flat", "E flat",
X    "B flat", "F", "C", "G", "D", "A", "E", "B", "F sharp", "C sharp"};
X
Xint
Xplay_tracks(tracks, devs, num, t_scalar, repeat)
X	TCHUNK *tracks;
X	int *devs;
X	int num;
X	int t_scalar;
X	int repeat;
X{
X
X	return (record_tracks(tracks, devs, num, NULL, -1, t_scalar, repeat));
X}
X
Xint
Xrecord_tracks(p_tracks, p_devs, p_num, r_track, r_dev, t_scalar, repeat)
X	TCHUNK *p_tracks;
X	int *p_devs;
X	int p_num;
X	TCHUNK *r_track;
X	int r_dev;
X	int t_scalar;
X	int repeat;
X{
X	struct timeval mwait;
X	fd_set w_select;
X	fd_set r_select;
X	int click_fraction[16];
X	int i;
X#ifdef MIDI_DEBUG
X	int j;
X#endif
X	int num_active;
X	int select_return;
X	int something_open;
X	int *track_active;
X
X	num_active = p_num;
X	if (p_num) {
X		if ((track_active = (int *) malloc(sizeof(int) * p_num))
X		    == NULL)
X			return (0);
X		for (i = 0; i < p_num; i++)
X			track_active[i] = 1;
X	}
X
X	for (i = 0; i < 16; i++)
X		click_fraction[i] = 0;
X	something_open = 1;
X	StopRecording = 0;
X	do {
X		while (something_open && !StopRecording) {
X			/* select on open play tracks */
X			FD_ZERO(&w_select);
X			for (i = 0; i < p_num; i++)
X				if (track_active[i])
X					FD_SET(p_devs[i], &w_select);
X			FD_ZERO(&r_select);
X			if (r_dev != -1)
X				FD_SET(r_dev, &r_select);
X			mwait.tv_sec = 0;
X			mwait.tv_usec = 100000;
X			if ((select_return = select(getdtablesize(), &r_select,
X			    &w_select, NULL, &mwait)) == -1) {
X				if (errno == EINTR)
X					break;
X				else {
X					sprintf(MidiError,
X					    "Error in select: %s",
X					    sys_errlist[errno]);
X					return (0);
X				}
X			}
X			if (select_return == 0)
X				continue;
X	
X			/* write event to non-blocked one */
X			for (i = 0; i < p_num && !StopRecording; i++) {
X				if (!track_active[i] || !FD_ISSET(p_devs[i],
X				    &w_select))
X					continue;
X
X				something_open = process_play_event(i,
X				    &p_tracks[i], p_devs[i], &track_active[i],
X				    &num_active, t_scalar);
X				if (!track_active[i] && repeat) {
X					rewind_track(&p_tracks[i]);
X					track_active[i] = 1;
X					num_active++;
X					something_open = 1;
X				}
X			}
X			if (r_dev != -1 && FD_ISSET(r_dev, &r_select)) {
X
X				if (!process_record_event(r_dev, r_track))
X					return (0);
X			}
X		}
X	} while (repeat && !StopRecording);
X
X	if (!StopRecording) {
X		for (i = 0; i < p_num; i++)
X			if (ioctl(p_devs[i], MFLUSHQ, NULL) == -1) {
X				sprintf(MidiError,
X				    "Error flushing queue for track %d", i);
X			}
X	} else {
X		/* flush any delays stuck in board2smf */
X/*
X		flush_event(r_track);
X*/
X	}
X	if (p_num)
X		free(track_active);
X	return (1);
X}
X
Xint
Xprocess_play_event(track_num, p_track, p_dev, track_active, num_active,
X    t_scalar)
X	int track_num;
X	TCHUNK *p_track;
X	int p_dev;
X	int *track_active;
X	int *num_active;
X	int t_scalar;
X{
X	EVENT_TYPE event_type;
X	static int need_event[16] =
X	    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 
X	int event_size;
X#ifdef MIDI_DEBUG
X	int j;
X#endif
X	int smf_size;
X	int something_open;
X	int valid_event;
X	unsigned char smf_event[2048];
X	unsigned char event[2048];
X
X	something_open = 1;
X	valid_event = 0;
X	do {
X		if (!need_event[track_num])
X			event_size = smf2board(track_num, NULL, smf_size,
X			    event, t_scalar, &need_event[track_num],
X			    &event_type);
X		else {
X			smf_size = get_smf_event(p_track, smf_event,
X			    &event_type);
X			if (smf_size == -1) {
X				sprintf(MidiError, "Error reading event");
X				return (0);
X			} else if (smf_size == 0) {
X				*track_active = 0;
X				valid_event = 1;
X				if (--(*num_active) == 0)
X					something_open = 0;
X				break;
X			}
X			event_size = smf2board(track_num, smf_event, smf_size,
X			    event, t_scalar, &need_event[track_num],
X			    &event_type);
X		}
X
X#ifdef MIDI_DEBUG
X		printf("track %d: ", track_num);
X		for (j = 0; j < event_size; j++)
X			printf("0x%02x ", event[j]);
X		printf("\n");
X		fflush(stdout);
X#endif
X		switch(send_event(p_dev, event, event_size,
X		    event_type, track_num == 0)) {
X		case SEND_ERROR:
X			return (0);
X		case SEND_VALID:
X			valid_event = 1;
X			break;
X		case SEND_INVALID:
X			valid_event = 0;
X			break;
X		case SEND_DONE:
X			*track_active = 0;
X			valid_event = 1;
X			if (--(*num_active) == 0)
X				something_open = 0;
X			break;
X		}
X	} while (!valid_event && !StopRecording);
X	return(something_open);
X}
X
Xint
Xprocess_record_event(dev, r_track)
X	int dev;
X	TCHUNK *r_track;
X{
X	int event_size;
X	int events_delta;
X	int events_pos;
X	int events_size;
X#ifdef MIDI_DEBUG
X	int i;
X#endif
X	int smf_size;
X	unsigned char events[256];
X	unsigned char event_data[256];
X	unsigned char smf_event[256];
X	unsigned char *events_ptr;
X
X	if ((events_size = read(dev, events, 256)) == -1) {
X		perror("");
X		sprintf(MidiError, "Couldn't read from MIDI board");
X		return (0);
X	}
X#ifdef MIDI_DEBUG
X	printf("\n");
X	printf("board:");
X	for (i = 0; i < events_size; i++)
X		printf(" 0x%02x", events[i]);
X	printf("\n");
X#endif
X	events_ptr = events;
X	events_pos = 0;
X	do {
X		if((events_delta = get_board_event(events_ptr, events_size,
X		    event_data, &event_size)) == -1) {
X			sprintf(MidiError, "Couldn't get board event "
X			    "from stream");
X			return (0);
X		}
X		events_ptr += events_delta;
X		events_pos += events_delta;
X#ifdef MIDI_DEBUG
X		printf("single event:");
X		for (i = 0; i < event_size; i++)
X			printf(" 0x%02x", event_data[i]);
X		printf("\n");
X#endif
X
X		board2smf(event_data, event_size, smf_event, &smf_size);
X#ifdef MIDI_DEBUG
X		printf("smf:");
X		for (i = 0; i < smf_size; i++)
X			printf(" 0x%02x", smf_event[i]);
X		printf("\n");
X#endif
X		if (smf_size > 0)
X			if (!put_smf_event(r_track, smf_event, smf_size)) {
X				sprintf(MidiError, "Couldn't put event "
X				    "in record track");
X				return (0);
X			}
X	} while (events_pos < events_size);
X	return(1);
X}
X
Xvoid
Xflush_event(r_track)
X	TCHUNK *r_track;
X{
X	int smf_size;
X	unsigned char flush_event[] = {0x00, 0xf8};
X	unsigned char smf_event[256];
X
X	board2smf(flush_event, sizeof(flush_event), smf_event, &smf_size);
X
X	if (!put_smf_event(r_track, smf_event, smf_size)) {
X		sprintf(MidiError, "Couldn't put flush event");
X	}
X}
X
Xvoid
Xstop_recording()
X{
X	StopRecording = 1;
X}
X
X
XSEND_VAL
Xsend_event(dev, event, event_size, event_type, conductor)
X	int dev;
X	unsigned char *event;
X	int event_size;
X	EVENT_TYPE event_type;
X	int conductor;
X{
X	SEND_VAL return_val;
X	static int clocks_per_beat = 24;
X	int num_written;
X	short seq_num;
X	unsigned char time_event[10];
X
X	switch (event_type) {
X	case NORMAL:
X		if ((num_written = write(dev, event, event_size)) == -1) {
X			sprintf(MidiError, "Couldn't write to MIDI board: %s",
X			    sys_errlist[errno]);
X			return_val = SEND_ERROR;
X			break;
X		}
X		return_val = SEND_VALID;
X		break;
X	case METASEQNUM:
X		seq_num = event[4] << 8 + event[5];
X		if (Verbose)
X			printf("Sequence number %d\n", seq_num);
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METATEXT:
X		event[event_size] = '\0';
X		if (Verbose)
X			printf("METATEXT: %s\n", &event[4]);
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METACPY:
X		event[event_size] = '\0';
X		if (Verbose)
X			printf("METACPY: %s\n", &event[4]);
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METASEQNAME:
X		event[event_size] = '\0';
X		if (Verbose)
X			printf("METASEQNAME: %s\n", &event[4]);
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METAINSTNAME:
X		event[event_size] = '\0';
X		if (Verbose)
X			printf("METAINSTNAME: %s\n", &event[4]);
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METALYRIC:
X		event[event_size] = '\0';
X		if (Verbose)
X			printf("METALYRIC: %s\n", &event[4]);
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METAMARKER:
X		event[event_size] = '\0';
X		if (Verbose)
X			printf("METAMARKER: %s\n", &event[4]);
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METACUE:
X		event[event_size] = '\0';
X		if (Verbose)
X			printf("METACUE: %s\n", &event[4]);
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METACHANPREFIX:
X		/* I have no data on how this is formatted */
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METAEOT:
X		event[1] = MIDI_NOOP;
X		if (write(dev, event, 2) == -1) {
X			sprintf(MidiError, "Couldn't write to "
X			    "MIDI board:", sys_errlist[errno]);
X			return_val = SEND_ERROR;
X			break;
X		}
X		return_val = SEND_DONE;
X		break;
X	case METATEMPO:
X		/* only do this for the conductor track - pos 0 */
X		if (conductor) {
X			/* just the byte meaningful to the board */
X			event[1] = (unsigned char) (MSETBASETMP & 0xff);
X			/* convert usec / beat to beats / min */
X			event[2] = TempoRatio * (60 * 1000000) /
X			    (event[4] * 0x010000 + event[5] * 0x0100 +
X			    event[6]);
X			Tempo = event[2];
X			if (Verbose)
X				printf("METATEMPO: Beats Per Minute: %d\n",
X				    event[2]);
X			if (write(dev, event, 3) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		} else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METASMPTE:
X		/* Not sure on this one */
X		if (Verbose) {
X			printf("METASMPTE: Hour %d Minute %d Second %d "
X			    "Frame %d Fractional Frame %d\n",
X			    event[4], event[5], event[6], event[7],
X			    event[8]);
X		}
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METATIME:
X		if (conductor) {
X			if (Verbose)
X				printf("METATIME: %d / %d "
X				    "Clocks per met beat = %d\n",
X				    event[4], event[5], event[6]);
X			time_event[0] = event[0];
X			time_event[1] = (unsigned char) (MSETBPM & 0xff);
X			/* bpm = numerator of time sig */
X			time_event[2] = event[4];
X			/* no time delay */
X			time_event[3] = 0;
X			time_event[4] = (unsigned char) (MSETMETFRQ & 0xff);
X			/* met freq = byte seven in time sig */
X			time_event[5] = event[6];
X			/*
X			 * if the clocks per met changes we should adjust
X			 * the tempo accordingly - at least until I figure
X			 * out a better way of doing this.
X			 */
X			/* new clock_per_bear over old */
X			TempoRatio = (double)event[6] / clocks_per_beat;
X			Tempo = Tempo * TempoRatio;
X			time_event[6] = 0;
X			time_event[7] = (unsigned char) (MSETBASETMP & 0xff);
X			time_event[8] = Tempo;
X			if (write(dev, time_event, 9) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			clocks_per_beat = event[6];
X			return_val = SEND_VALID;
X		} else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	case METAKEY:
X		if (Verbose)
X			printf("METAKEY: %s %s\n", Key[(signed char)event[4]
X			    + 7], event[5] ? "minor" : "major");
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	default:
X		if (event[0] == 0)
X			return_val = SEND_INVALID;
X		else {
X			event[1] = MIDI_NOOP;
X			if (write(dev, event, 2) == -1) {
X				sprintf(MidiError, "Couldn't write to "
X				    "MIDI board: %s", sys_errlist[errno]);
X				return_val = SEND_ERROR;
X				break;
X			}
X			return_val = SEND_VALID;
X		}
X		break;
X	}
X
X	return (return_val);
X}
X
Xint
Xopen_midi_devices(hchunk, spec_tracks, num, devs, active_mask)
X	HCHUNK *hchunk;
X	TRKS *spec_tracks;
X	int *num;
X	int *devs;
X	unsigned char *active_mask;
X{
X	int cond_on;
X	int dev_counter;
X	int i;
X	int j;
X	char dev_name[100];
X
X	cond_on = 0;
X	j = 0;
X	if (hchunk->format == 0) {
X		if ((devs[j++] = open("/dev/midicond", O_WRONLY | O_NONBLOCK,
X		    0)) == -1) {
X			sprintf(MidiError, "Coudln't open conductor track: %s",
X			    sys_errlist[errno]);
X			return (-1);
X		}
X		cond_on = 1;
X	}
X
X	for (i = 0; i < spec_tracks->num_tracks && !cond_on; i++)
X		if (spec_tracks->tracks[i] == 0) {
X			if ((devs[j++] = open("/dev/midicond", O_WRONLY |
X				O_NONBLOCK, 0)) == -1) {
X				sprintf(MidiError,
X				    "Coudln't open conductor track: %s",
X				    sys_errlist[errno]);
X				return (-1);
X			}
X			cond_on = 1;
X		}
X
X	dev_counter = 0;
X	*active_mask = 0;
X	for (i = j; i < *num; i++) {
X		if (dev_counter == MAX_TRACKS) {
X			sprintf(MidiError, "Too many play tracks (%d).  "
X			   "Only using first %d", *num - cond_on, MAX_TRACKS);
X			*num = MAX_TRACKS + cond_on;
X			break;
X		}
X
X		sprintf(dev_name, "/dev/midi%d", dev_counter);
X		if ((devs[j++] = open(dev_name, O_WRONLY | O_NONBLOCK, 0))
X		    == -1) {
X			sprintf(MidiError, "Coudln't open midi track %d: %s",
X				dev_counter, sys_errlist[errno]);
X			return (-1);
X		}
X		*active_mask |= (unsigned char)(1 << dev_counter++);
X	}
X
X	return (cond_on);
X}
X
Xvoid
Xset_midi_verbose(v)
X	int v;
X{
X	Verbose = v;
X}
X#endif
END-of-tclm0.1/mlib/mplayutil.c
exit

Newsgroups: comp.lang.tcl