#
#	mid2score.awk
#
#
#  -----------------------------------------------------------------------
#  Copyright 2007  Alfred Steffens Jr.
#  -----------------------------------------------------------------------
#  -----------------------------------------------------------------------
#    Copying Permission:
#
#    mid2score is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation.
#
#    mid2score is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with mid2score (see file called "COPYING"); if not, write to the
#	 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
#    02111-1307  USA
#  ------------------------------------------------------------------------
#
#   Mscore release 1.1
#
#	ver. 1.03	9/22/2007		A. Steffens Jr.		Fixed bug with
#                                                   sequencer-specific event
#	ver. 1.02	3/23/2005		A. Steffens Jr.		Fixed bug with single track
#	ver. 1.01	2/09/2005		A. Steffens Jr.		Fixed end-of-track bug
#	ver. 1.0	2/08/2005		A. Steffens Jr.
#
#



BEGIN {

	version_no = "1.03 (package 1.1)"
	#
	#	header flags
	#
	header_done=0
	header_id_bytes=0
	header_length_done=0
	header_len_byte_cnt=0
	header_format_done=0
	header_fmt_byte_cnt=0
	format_type=0
	header_no_trk_cnt=0
	header_tracks_done=0
	no_tracks=0
	header_div_done=0
	header_div_cnt=0
	division=0

	#
	#	track flags
	#
	curr_track_no = 0	# don't "clear" this each time
	curr_event=0		#	clear this for each track
	track_id_done=0
	track_id_bytes=0
	track_length_done=0
	track_len_byte_cnt=0
	track_length=0
	track_byte_count=0
	curr_time=0

	#
	#	event flags
	#
	event_vtime_done=0
	event_vtime=0
	event_byte_cnt=0
	event_type_done=0
	event_type=0
	last_event_type=0
	event_end=0

	#
	#	meta event specific
	#
	meta_event_type=0
	last_meta_event_type=0
	meta_length_done=0
	meta_length_cnt=0
	meta_length=0
	meta_data_done=0
	meta_data_cnt=0

	#
	#	MIDI event specific
	#
	midi_byte=0
	last_midi_byte=0
	midi_hex_byte=0
	last_midi_hex_byte=0
	midi_control_number=0
	midi_note_number=0
	midi_program_number=0
	midi_channel_pressure=0
	midi_pitch_bend_high=0
	midi_velocity=0
	midi_key_pressure=0
	midi_control_value=0

	#
	#	sysex event specific
	#
	sysex_data_cnt=0
	sysex_data_done=1


	sequence_number=0
	tempo_bpm=0
	midi_pitch_bend_14=1
	total_events=0
	debug_messages=0
	dos_eol=0
	dos_test_done=0

	print "#	--------------------------------------------------------------"
	print "#	MIDI SCORE FILE"
	print "#	generated by mid2score.awk	(Alfred Steffens Jr.	2007)"
	print "#	mid2score ver. " version_no
	print "#	--------------------------------------------------------------"
	print "#"
}


#
#	parse each line (containing a byte)
#
{

	if (debug_messages) {
		print "input: " $1
	}

	#	count track bytes
	if (track_id_done && track_length_done) {
		track_byte_count++
	}


	#
	#	------------------------------------------------------------------
	#	Header read
	#	------------------------------------------------------------------
	#
	#
	if (header_done == 0) {

		#
		#	determine if this is a MS text file (has 0D 0A at the end of line)
		#
		if (dos_test_done==0) {
			if (match($1, /\r/)) {
				print "#	MS Text"
				dos_eol=1
			}
			else {
				print "#	Unix Text"
			}
			dos_test_done=1
		}


		#
		#	identify the header ID string "MThd"
		#
		if (header_id_bytes != 4) {
			if (header_id_bytes==0 && $1 == "4d") {
				header_id_bytes =1
				next
			}
			else if (header_id_bytes==1 && $1 == "54") {
				header_id_bytes =2
				next
			}
			else if (header_id_bytes==2 && $1 == "68") {
				header_id_bytes =3
				next
			}
			else if (header_id_bytes==3 && $1 == "64") {
				header_id_bytes =4
				next
			}
		} # if -- header ID

		#
		#	parse the header length bytes
		#
		if (header_length_done==0 && header_id_bytes == 4) {

			if (header_len_byte_cnt == 0) {
				if ($1 == "00") {
					header_len_byte_cnt = 1
					next
				}
			} # if
			else if (header_len_byte_cnt == 1) {
				if ($1 == "00") {
					header_len_byte_cnt = 2
					next
				}
			} # if
			else if (header_len_byte_cnt == 2) {
				if ($1 == "00") {
					header_len_byte_cnt = 3
					next
				}
			} # if
			else if (header_len_byte_cnt == 3) {
				if ($1 == "06") {
					header_len_byte_cnt = 4
					header_length_done = 1
					next
				}
			} # if

		} # if -- header length

		#
		#	header format word
		#
		if (header_length_done && header_format_done == 0) {

			if (header_fmt_byte_cnt == 0) {
				if ($1 == "00") {
					header_fmt_byte_cnt = 1
					next
				}
			}
			else if (header_fmt_byte_cnt == 1) {
				if ($1 == "00") {
					header_fmt_byte_cnt = 2
					format_type = 0		# single track
					# print "#	midi file format:	single track"
					print "MIDI_FORMAT single_track (0)"
					header_format_done = 1
					next
				}
				else if ($1 == "01") {
					header_fmt_byte_cnt = 2
					format_type = 1		# multi track
					# print "#	midi file format:	multi track (1)"
					print "MIDI_FORMAT multi_track"
					header_format_done = 1
					next
				}
				else if ($1 == "02") {
					header_fmt_byte_cnt = 2
					format_type = 2		# multi song
					# print "#	midi file format:	multi song (2)"
					print "MIDI_FORMAT multi_song"
					header_format_done = 1
					next
				}
			}

		} # if -- header format


		#
		#	read number of track chunks
		#
		if (header_format_done && header_tracks_done == 0) {
			if (header_no_trk_cnt == 0) {
				#
				#	read high-order byte
				#
				err = split($1,ary,"\n")
				hbyte = hex_byte_to_decimal(ary[1])
				header_no_trk_cnt = 1
				next
			}
			else if (header_no_trk_cnt == 1) {
				err = split($1,ary,"\n")
				lbyte = hex_byte_to_decimal(ary[1])
				header_no_trk_cnt = 2
				no_tracks = hbyte * 256
				no_tracks += lbyte
				# print "#	number of tracks: " no_tracks
				print "TRACKS " no_tracks
				header_tracks_done=1
				next
			} # else
		} # if


		#
		#	read the "division"  (ticks per beat)
		#
		if (header_tracks_done && header_div_done==0) {

			if (header_div_cnt == 0) {
				#
				#	read high-order byte
				#
				err = split($1,ary,"\n")
				err = hex_byte_sign_bit(ary[1])
				if (err) {
					print "ERROR: can't read SMPTE time divisions"
					exit
				}
				hbyte = hex_byte_to_decimal(ary[1])
				header_div_cnt = 1
				next
			}
			else if (header_div_cnt == 1) {
				err = split($1,ary,"\n")
				lbyte = hex_byte_to_decimal(ary[1])
				header_div_cnt = 2
				division = hbyte * 256
				division += lbyte
				# print "#	time division: " division
				print "TICS_PER_BEAT " division
				header_div_done=1
				header_done = 1
				next
			} # else

		} # if -- read the time division

	} # if -- header not done






	#
	#	------------------------------------------------------------------
	#	Track read
	#	------------------------------------------------------------------
	#
	#

	#
	#	track ID
	#
	if (track_id_done == 0) {

		if (track_id_bytes==0 && $1 == "4d") {
			track_id_bytes =1
			next
		}
		else if (track_id_bytes==1 && $1 == "54") {
			track_id_bytes =2
			next
		}
		else if (track_id_bytes==2 && $1 == "72") {
			track_id_bytes =3
			next
		}
		else if (track_id_bytes==3 && $1 == "6b") {
			track_id_bytes =4
			track_id_done=1
			next
		}

	} # if -- track_id


	#
	#	track length
	#
	if (track_id_done && track_length_done==0) {

		if (track_len_byte_cnt < 4) {

			err = split($1,ary,"\n")
			hbyte = hex_byte_to_decimal(ary[1])

			if (track_len_byte_cnt==0) {
				hbyte *= 16777216
				track_length += hbyte
				track_len_byte_cnt += 1
				next
			}
			else if (track_len_byte_cnt==1) {
				hbyte *= 65536
				track_length += hbyte
				track_len_byte_cnt += 1
				next
			}
			else if (track_len_byte_cnt==2) {
				hbyte *= 256
				track_length += hbyte
				track_len_byte_cnt += 1
				next
			}
			else if (track_len_byte_cnt==3) {
				track_length += hbyte
				track_len_byte_cnt += 1
				track_length_done=1
				curr_track_no += 1	# track counting starts from 1
				# print "#	track " curr_track_no ",  length " track_length
				next
			}

		} # if

	} # if -- track length


	#	----------------------
	#	Start reading an event
	#	----------------------
	#

	#
	#	read the "v_time" that begins an event
	#
	if (track_length_done && event_vtime_done==0) {

		err = split($1,ary,"\n")
		if (hex_byte_sign_bit(ary[1])) {
			#
			#	not the last byte
			#
			nib = hex_byte_lower_7_bits(ary[1])
			event_byte_cnt += 1
			event_byte_array[event_byte_cnt] = nib
			next
		}
		else {
			#
			#	the last byte in the time code
			#
			nib = hex_byte_lower_7_bits(ary[1])
			event_byte_cnt += 1
			event_byte_array[event_byte_cnt] = nib

			event_vtime_done=1
		} # else -- last byte

		#
		#	put the bytes together
		#
		if (event_vtime_done) {
			vfac = 1
			for (i=event_byte_cnt; i>=1; i--) {

				#
				#	each higher-order byte must be shifted up
				#	by 7 more bits
				#
				event_vtime += (event_byte_array[i]*vfac)

				vfac *= 128
			} # -- for


			#
			#	save the delta time for this event in this track
			#
			curr_event += 1		# event counting starts from 1
			total_events += 1
			curr_time += event_vtime
			TrackEvents_vtime[curr_track_no, curr_event] = event_vtime
			TrackEvents_currtime[curr_track_no, curr_event] = curr_time
			if (debug_messages) {
				print "#	vtime " event_vtime ", curr_time " curr_time ", event " curr_event
			}
			next
		} # if -- done bytes

	} # if -- start an event


	#
	#	Look for MIDI EVENT, or META EVENT, or SYSEX EVENT
	#
	#
	#
	if (event_vtime_done && event_type_done==0) {

		err = split($1,ary,"\n")
		byte = hex_byte_to_decimal(ary[1])

		if (byte == 255) {	# "FF"
			#
			#	META EVENT
			#
			event_type = 2
			event_byte_cnt = 1
			event_type_done = 1
			if (debug_messages) {
				print "#	META EVENT"
			}
			TrackEvents_eventtype[curr_track_no, curr_event] = event_type
			next

		} # if -- META EVENT
		else if (byte == 240) {  # "F0"
			#
			#	SYSEX EVENT
			#
			event_type = 3
			event_byte_cnt = 1
			event_type_done = 1
			TrackEvents_eventtype[curr_track_no, curr_event] = event_type
			if (debug_messages) {
				print "#	SYSEX EVENT"
			}
			sysex_data_done = 0		# start counting data
			next

		} # if -- META EVENT
		else if (byte >= 241 && byte <= 246) {  # "F1 -- F6"
			#
			#	SYSTEM COMMON MESSAGE
			#
			event_type = 4
			event_byte_cnt = 1
			event_type_done = 1
			TrackEvents_eventtype[curr_track_no, curr_event] = event_type
			if (debug_messages) {
				print "#	SYS COMMON EVENT"
			}
			next

		} # if -- META EVENT
		else if (byte >= 248 && byte <= 254) {  # "F8 -- FE"
			#
			#	SYSTEM REAL-TIME MESSAGE
			#
			event_type = 5
			event_byte_cnt = 1
			event_type_done = 1
			TrackEvents_eventtype[curr_track_no, curr_event] = event_type
			if (debug_messages) {
				print "#	SYS REAL-TIME EVENT"
			}
			next

		} # if -- META EVENT
		else if (byte >= 128 && byte <= 239) {
			#
			#	MIDI EVENT
			#
			event_type = 1
			event_byte_cnt = 1
			midi_byte = byte
			midi_hex_byte = ary[1]
			event_type_done = 1
			TrackEvents_eventtype[curr_track_no, curr_event] = event_type
			if (debug_messages) {
				print "#	MIDI EVENT " midi_hex_byte
			}
			next

		} # if -- midi event
		else {
			#
			#	continuation of previous event
			#
			event_type = last_event_type
			if (last_event_type==1) {
				midi_byte = last_midi_byte
				midi_hex_byte = last_midi_hex_byte
			}
			else if (last_event_type==2) {
				meta_event_type = last_meta_event_type
			}
			TrackEvents_eventtype[curr_track_no, curr_event] = event_type
			TrackEvents_running[curr_track_no, curr_event] = 1  # running status
			event_byte_cnt = 1
			event_type_done = 1
			# print "#	Continuation of event type " event_type ", currnt byte is " $1

			#
			#	don't "next" here because the current byte here is the second
			#	event byte which must be parsed below
			#
		} # else


	} # find event type



	#
	#	handle bytes until event ended
	#
	if (event_type_done) {

		if (event_type == 1) {
			#
			#	MIDI EVENT
			#
			if (event_byte_cnt==1) {
				#
				#	interpret the midi_byte
				#
				midi_channel = hex_byte_to_midi_channel(midi_hex_byte)
				midi_chex = midi_channel+1
				midi_command = hex_byte_to_midi_command(midi_hex_byte)

				#
				#	save the (midi) command for this event in this track
				#
				TrackEvents_midicommand[curr_track_no, curr_event] = midi_command
				TrackEvents_midichannel[curr_track_no, curr_event] = midi_channel

				#
				# the 2nd byte
				#
				err = split($1,ary,"\n")
				byte =  hex_byte_lower_7_bits(ary[1])
				TrackEvents_midibyte2[curr_track_no, curr_event] = byte

				if (midi_command==8) {
					#
					#	note off (0x80 to 0x8f)
					#
					midi_note_number = byte
					event_byte_cnt = 2

				} # if -- note off
				else if (midi_command==9) {
					#
					#	note on (0x90 to 0x9f)
					#
					midi_note_number = byte
					event_byte_cnt = 2

				} # if -- note on
				else if (midi_command==10) {
					#
					#	key pressure (0xa0 to 0xaf)
					#
					midi_note_number = byte
					event_byte_cnt = 2

				} # if -- key pressure
				else if (midi_command==11) {
					#
					#	control (0xb0 to 0xbf)
					#
					midi_control_number = byte
					event_byte_cnt = 2

				} # if -- control
				else if (midi_command==12) {
					#
					#	program ("patch")(0xc0 to 0xcf)
					#
					midi_program_number = byte
					event_byte_cnt = 2
					# print "MIDI TK" curr_track_no " CH" midi_chex " PG" midi_program_number+1
					#
					#	quit early
					#
					event_end=1
					clear_event_flags()
					next

				} # if -- program
				else if (midi_command==13) {
					#
					#	channel pressure (0xd0 to 0xdf)
					#
					midi_channel_pressure = byte
					event_byte_cnt = 2
					# print "MIDI TK" curr_track_no " CH" midi_chex " CP" midi_channel_pressure
					#
					#	quit early
					#
					event_end=1
					clear_event_flags()
					next

				} # if -- channel pressure
				else if (midi_command==14) {
					#
					#	pitch bend (0xe0 to 0xef)
					#
					midi_pitch_bend_high = byte
					event_byte_cnt = 2

					if (midi_pitch_bend_14) {
						#	wait until next byte
					}
					else {
						# print "MIDI TK" curr_track_no " CH" midi_chex " PB" midi_pitch_bend_high
						#
						#	quit early
						#
						event_end=1
						clear_event_flags()
						next
					}

				} # if -- pitch bend

				next
			}
			else if (event_byte_cnt==2) {

				#
				# the 3rd byte
				#
				err = split($1,ary,"\n")
				byte =  hex_byte_lower_7_bits(ary[1])
				TrackEvents_midibyte3[curr_track_no, curr_event] = byte

				if (midi_command==8) {
					#
					#	note off (0x80 to 0x8f)
					#
					midi_velocity = byte
					event_byte_cnt = 3
					#
					#	add an entry into the midi score
					#
					# print "#	NOTE OFF,   note " midi_note_number ", vel " midi_velocity

					event_end=1
					clear_event_flags()
					next

				} # if -- note off
				else if (midi_command==9) {
					#
					#	note on (0x90 to 0x9f)
					#
					midi_velocity = byte
					event_byte_cnt = 3
					#
					#	add an entry into the midi score
					#
					# print "#	NOTE ON,   note " midi_note_number ", vel " midi_velocity

					event_end=1
					clear_event_flags()
					next

				} # if -- note on
				else if (midi_command==10) {
					#
					#	key pressure (0xa0 to 0xaf)
					#
					midi_key_pressure = byte
					event_byte_cnt = 3
					# print "MIDI TK" curr_track_no " CH" midi_chex " KP" midi_note_number " VL" midi_key_pressure

					event_end=1
					clear_event_flags()
					next

				} # if -- key pressure
				else if (midi_command==11) {
					#
					#	control (0xb0 to 0xbf)
					#
					midi_control_value = byte
					event_byte_cnt = 3
					# print "MIDI TK" curr_track_no " CH" midi_chex " CT" midi_control_number+1 " VL" midi_control_value

					event_end=1
					clear_event_flags()
					next


				} # if -- control
				else if (midi_command==12) {
					#
					#	program ("patch")(0xc0 to 0xcf)
					#

					#
					#	this should never happen
					#
					print "ERROR: third byte on program change?"
					exit

				} # if -- program
				else if (midi_command==13) {
					#
					#	channel pressure (0xd0 to 0xdf)
					#

					#
					#	this should never happen
					#
					print "ERROR: third byte on channel pressure?"
					exit

				} # if -- channel pressure
				else if (midi_command==14) {
					#
					#	pitch bend (0xe0 to 0xef)
					#
					if (midi_pitch_bend_14) {
						midi_pitch_bend_low = byte
						event_byte_cnt = 3
						# print "MIDI TK" curr_track_no " CH" midi_chex " PB" midi_pitch_bend_high " VL" midi_pitch_bend_low
						event_end=1
						clear_event_flags()
						next
					}
					else {
						print "ERROR: 3rd pitch bend byte-but not in 14-bit mode"
						exit
					}

				} # if -- pitch bend


				event_end=1
			} # else -- event_byte_cnt==2

		} # MIDI EVENT
		else if (event_type == 2) {
			#
			#	META EVENT
			#
			err = split($1,ary,"\n")
			byte = hex_byte_to_decimal(ary[1])

			if (event_byte_cnt==1) {
				#
				#	we have only seen the leading 0xFF yet
				#
				meta_event_type = byte
				event_byte_cnt = 2
				#
				#	save the (meta) event type for this event in this track
				#
				TrackEvents_metatype[curr_track_no, curr_event] = meta_event_type
				next

			} # if -- event byte 1
			else if (event_byte_cnt >= 2) {
				#
				#	we have already seen the meta event type
				#	we start reading the v_length
				#

				if (meta_length_done == 0) {

					if (hex_byte_sign_bit(ary[1])) {
						#
						#	not the last byte
						#
						nib = hex_byte_lower_7_bits(ary[1])
						meta_length_cnt += 1
						event_byte_array[meta_length_cnt] = nib
						event_byte_cnt += 1
						next
					}
					else {
						#
						#	the last byte in the time code
						#
						nib = hex_byte_lower_7_bits(ary[1])
						meta_length_cnt += 1
						event_byte_array[meta_length_cnt] = nib
						event_byte_cnt += 1
			
						meta_length_done=1
						#	don't "next" here--we need to drop down
						#	to assemble the v_length bytes
					} # else -- last byte

					#
					#	if we are done reading the v_length
					#	assemble it here
					#
					if (meta_length_done) {

						vfac = 1
						for (i=meta_length_cnt; i>=1; i--) {
			
							
							#	each higher-order byte must be shifted up
							#	by 7 more bits
							#
							meta_length += (event_byte_array[i]*vfac)
			
							vfac *= 128
						} # -- for

					} # if -- meta_length_done

					if (meta_length == 0) {
						meta_data_done = 1
						#	we can't do a "next" in this case
					}
					else {
						next
					}

				} # if -- meta_length_done==0


				#
				#	if we have already read the length of the following
				#	meta data
				#	read the data
				#
				if (meta_length_done && meta_data_done == 0) {

					meta_data_cnt += 1
					event_byte_array[meta_data_cnt] = byte
					if (meta_data_cnt == meta_length) {
						meta_data_done = 1
					}

					event_byte_cnt += 1
					# don't do "next" yet, we must assemble the data
				} # if -- meta_data


				#
				#	interpret the META EVENT
				#
				if (meta_data_done) {

					if (meta_event_type == 0) {
						#
						#	sequence number
						#
						if (debug_messages) {
							print "#	ignoring SEQUENCE NUMBER"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- sequence number
					else if (meta_event_type == 1) {
						#
						#	text
						#
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s%c", tmpstring, event_byte_array[i])
						}
						sub(/\n/, "", tmpstring) # remove extra lfcr
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	TEXT (" tmpstring  ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- text
					else if (meta_event_type == 2) {
						#
						#	copyright notice
						#
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s%c", tmpstring, event_byte_array[i])
						}
						sub(/\n/, "", tmpstring) # remove extra lfcr
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	COPYRIGHT NOTICE (" tmpstring ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- copyright notice
					else if (meta_event_type == 3) {
						#
						#	track name
						#
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s%c", tmpstring, event_byte_array[i])
						}
						sub(/\n/, "", tmpstring) # remove extra lfcr
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	TRACK NAME (" tmpstring ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- track name
					else if (meta_event_type == 4) {
						#
						#	instrument name
						#
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s%c", tmpstring, event_byte_array[i])
						}
						sub(/\n/, "", tmpstring) # remove extra lfcr
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	INSTRUMENT NAME (" tmpstring ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- instrument name
					else if (meta_event_type == 5) {
						#
						#	Lyric text
						#
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s%c", tmpstring, event_byte_array[i])
						}
						sub(/\n/, "", tmpstring) # remove extra lfcr
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	LYRIC TEXT (" tmpstring ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- Lyric text
					else if (meta_event_type == 6) {
						#
						#	Marker text
						#
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s%c", tmpstring, event_byte_array[i])
						}
						sub(/\n/, "", tmpstring) # remove extra lfcr
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	MARKER TEXT (" tmpstring ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- Marker text
					else if (meta_event_type == 7) {
						#
						#	Cue point
						#
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s%c", tmpstring, event_byte_array[i])
						}
						sub(/\n/, "", tmpstring) # remove extra lfcr
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	CUE POINT (" tmpstring ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- Cue point
					else if (meta_event_type == 32) {
						#
						#	MIDI channel prefix assignment
						#
						if (debug_messages) {
							print "#	ignoring MIDI CHANNEL PREFIX (data cnt " meta_data_cnt ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- MIDI channel prefix assignment
					else if (meta_event_type == 33) {
						#
						#	MIDI channel prefix assignment
						#
						if (debug_messages) {
							print "#	ignoring META event 0x21"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- MIDI channel prefix assignment
					else if (meta_event_type == 47) {
						#
						#	end of track
						#
						if (debug_messages) {
							print "#	end of track " curr_track_no
						}
						event_end = 1	# done with event
						clear_event_flags()
						clear_track_flags()
						next

					} # -- end of track
					else if (meta_event_type == 81) {
						#
						#	tempo
						#

						#
						#	convert the data into a TEMPO in BPM
						#
						vfac = 1
						tempo_bpm = 0
						for (i=meta_data_cnt; i>=1; i--) {

							tempo_bpm += (event_byte_array[i]*vfac)
			
							vfac *= 256

						} # for -- loop through meta data
						if (tempo_bpm == 0) {
							print "ERROR: tempo META EVENT finds 0 BPM"
							exit
						}
						tempo_bpm = 60000000/tempo_bpm

						# print "TEMPO " tempo_bpm

						#
						#	save the (meta) TEMPO for this event in this track
						#
						TrackEvents_metavalue[curr_track_no, curr_event] = tempo_bpm

						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- tempo
					else if (meta_event_type == 84) {
						#
						#	SMPTE offset
						#
						print "#	smpte offset"
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s %x", tmpstring, event_byte_array[i])
						}
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	SMPTE OFFSET (" tmpstring ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- SMPTE offset
					else if (meta_event_type == 88) {
						#
						#	time signature
						#
						if (debug_messages) {
							print "#	time signature TBD"
						}
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s %02d", tmpstring, event_byte_array[i])
						}
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- time signature
					else if (meta_event_type == 89) {
						#
						#	key signature
						#
						if (debug_messages) {
							print "#	key signature"
						}
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s %02d", tmpstring, event_byte_array[i])
						}
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- key signature
					else if (meta_event_type == 127) {
						#
						#	sequencer specific event
						#
						print "#	sequencer specific event"
						tmpstring = ""
						for (i=1; i<=meta_data_cnt; i++) {
							tmpstring = sprintf("%s %x", tmpstring, event_byte_array[i])
						}
						TrackEvents_metavalue[curr_track_no, curr_event] = tmpstring
						if (debug_messages) {
							print "#	SEQUENCER SPECIFIC (" tmpstring ")"
						}
						event_end = 1	# done with event
						clear_event_flags()
						next

					} # -- sequencer specific event
					else {
						print "ERROR: unknown META EVENT type " byte
						exit
					}

				} # if -- meta_data_done


			} # else if -- event_byte_cnt >= 2



		} # META EVENT
		else if (event_type == 3) {
			#
			#	SYSEX EVENT
			#
			if (sysex_data_done==0) {

				err = split($1, ary, "\n")

				if ($1 == "f7") {
					event_end = 1	# done with event
					clear_event_flags()
					sysex_data_done = 1
				}
				else {
					sysex_data_cnt++
					sysex_data_array[sysex_data_cnt] = ary[1]
				}
			}
			next

		} # SYSEX EVENT
		else if (event_type == 4) {
			#
			#	SYS COMMON EVENT
			#

		} # SYS COMMON EVENT
		else if (event_type == 5) {
			#
			#	SYS REAL-TIME EVENT
			#

		} # SYS REAL-TIME EVENT
		else {
		}


	} # -- event not ended



}


END {

	#
	#	now that all the tracks have been read, print the track events
	#	in parallel columns down the page
	#

	if (no_tracks != curr_track_no) {
		print "ERROR: didn't find " no_tracks " tracks in file (found " curr_track_no " tracks)"
		print "	---------------------------------------------------------------------------"
		print "	------------ DEBUG OUTPUT -------------------------------------------------"
		print "	---------------------------------------------------------------------------"
		for (i=1; i<=no_tracks; i++) {
			print "track " i
			events_this_track = track_size[i]
			for (j=1; j<=events_this_track; j++) {
				event_type = TrackEvents_eventtype[i,j]
				if (event_type==1) {
					midi_command = TrackEvents_midicommand[i, j]
					midi_channel = TrackEvents_midichannel[i, j]
					print "MIDI command " midi_command ", channel " midi_channel
				}
				else if (event_type==2) {
					meta_event_type = TrackEvents_metatype[i, j]
					print "META event, meta type " meta_event_type
				}
				else if (event_type==3) {
					print "SYSEX event"
				}
				else if (event_type==4) {
					print "SYS COMMON event"
				}
				else if (event_type==5) {
					print "SYS REAL-TIME event"
				}
			}
		}
		print "	---------------------------------------------------------------------------"
		print "	------------ end  DEBUG OUTPUT --------------------------------------------"
		print "	---------------------------------------------------------------------------"
		exit
	} # if -- something wrong

	print "#	total events " total_events


	#
	#	find the note durations ( to eliminate the note off events )
	#	we assume that a note-off occurs in the same track
	#
	for (track_index=1; track_index<=no_tracks; track_index++) {
		events_this_track = track_size[track_index]

		j = 1
		while (j <= events_this_track) {
		
			event_type = TrackEvents_eventtype[track_index, j]	
			is_a_note = event_bar_type(event_type, track_index, j)
			if (is_a_note) {
				#
				#	if a note on
				#
				if (TrackEvents_midicommand[track_index,j] == 9) {

					#
					#	but if the attack is 0, then this is a substitute
					#	for a note off...
					#	so ignore it
					#
					if (TrackEvents_midibyte3[track_index,j] == 0) {
						j++
						continue
					}

					k = find_note_off(track_index, j)

					if (k) {
						noteduration = TrackEvents_currtime[track_index,k] -TrackEvents_currtime[track_index,j]
						TrackEvents_duration[track_index, j] = noteduration
					}
					else {

#						k = find_attack_zero(track_index, j)
#						if (k) {
#							noteduration = TrackEvents_currtime[track_index,k] -TrackEvents_currtime[track_index,j]
#							TrackEvents_duration[track_index, j] = noteduration
#						}
#						else {
#							print "ERROR: no note off for note on at track " track_index ", event " j
#							print "note " TrackEvents_midibyte2[track_index,j] ", attack " TrackEvents_midibyte3[track_index,j]
#							exit
#						}

						
						print "ERROR: no note off for note on at track " track_index ", event " j
						print "note " TrackEvents_midibyte2[track_index,j] ", attack " TrackEvents_midibyte3[track_index,j]
						exit

					} # else -- no note off (or attack 0) found

				} # if -- a note on

			} # if -- is_a_note

			j++
		} # while -- j


	} # for track_index
	#
	#	done finding durations
	#



	#	---------------------------------------------
	#	sort all the events in order of occurrence
	#	---------------------------------------------
	#
	#	first store the events in track 1
	#
	max_event = track_size[1]
	for (event_index=1; event_index<=max_event; event_index++) {

		sort_track[1, event_index] = 1
		sort_event[1, event_index] = event_index
		curr_time = TrackEvents_currtime[1, event_index]
		sort_time[1, event_index] = curr_time
		# print "TRACK 1, event " event_index ", time " curr_time

	} # for -- event
	save_last_sort_size = event_index-1

	#
	#	used in case there is only one track--because then we skip the
	#	while lopp below--we don't sort anything
	#
	sort_index = total_events+1

	curr_time = 0
	last_time = 0
	track_last = 1
	track_index = 2				# only used inside "END" section

	while (track_index <= no_tracks) {
		#
		#	this is an iteration loop
		#	it appears, falsely, as if it has to do with tracks
		#	that is because the iteration moves across the track numbers
		#

		sort_index = 1
		sort_last = 1
		event_index = 1				# only used inside "END" section
		while (1) {

			#
			#	read time from second array
			#
			if ( (track_index,event_index) in TrackEvents_currtime ) {
				curr_time = TrackEvents_currtime[track_index, event_index]
				curr_ok = 1
			}
			else {
				curr_ok = 0
			}
			#
			#	read time from first array
			#
			if ( (track_last, sort_last) in sort_time ) {
				last_time = sort_time[track_last, sort_last]
				last_ok = 1
			}
			else {
				last_ok = 0
			}

			#
			#	if both side have been used up
			#
			if (curr_ok==0 && last_ok==0) {
				break
			}

			#
			#	if the "curr" side doesn't exist
			#
			if (curr_ok==0 && last_ok==1) {
				#
				#	store the old event (from the last iteration)
				#
				sort_track[track_index, sort_index] = sort_track[track_last, sort_last]
				sort_event[track_index, sort_index] = sort_event[track_last, sort_last]
				sort_time[track_index, sort_index] = last_time
				# print "DEFAULT OLD1 TRACK " sort_track[track_last, sort_last] ", event " sort_event[track_last, sort_last] ", time " last_time
				# print "----DEBUGGER: info " event_info_string(track_last,sort_last)
				sort_index++
				sort_last++
				continue
			} # if

			if (last_ok==0 && curr_ok==1) {
				#
				#	we went too far -- store the new value
				#
				sort_track[track_index, sort_index] = track_index
				sort_event[track_index, sort_index] = event_index
				sort_time[track_index, sort_index] = curr_time
				# print "DEFAULT NEW1 TRACK " track_index ", event " event_index ", time " curr_time
				# print "----DEBUGGER: info " event_info_string(track_index,event_index)
				sort_index++
				event_index++
				continue
			} # if


			#
			#	if we dropped down to here, then both sides exist
			#

			#
			#	should we place the second event before or after this?
			#
			if (curr_time >= last_time) {
				#
				#	store the old event (from the last iteration)
				#
				sort_track[track_index, sort_index] = sort_track[track_last, sort_last]
				sort_event[track_index, sort_index] = sort_event[track_last, sort_last]
				sort_time[track_index, sort_index] = last_time
				# print "STORING OLD2 TRACK " sort_track[track_last, sort_last] ", event " sort_event[track_last, sort_last] ", time " last_time
				# print "----DEBUGGER: info " event_info_string(track_index,sort_last)
				sort_index++
				sort_last++

				
			} # if -- GE
			else {
				#
				#	we went too far -- store the new value
				#
				sort_track[track_index, sort_index] = track_index
				sort_event[track_index, sort_index] = event_index
				sort_time[track_index, sort_index] = curr_time
				# print "STORING NEW2 TRACK " track_index ", event " event_index ", time " curr_time
				# print "----DEBUGGER: info " event_info_string(track_index,event_index)
				sort_index++
				event_index++

			} # else -- LT

	
		} # while -- event_last


		#
		#	done with the "track last" sort array--free up memory
		#
		for (i=1; i<=save_last_sort_size; i++) {
			delete sort_track[track_last, i]
			delete sort_event[track_last, i]
			delete sort_time[track_last, i]
		}


		save_last_sort_size = sort_index-1
		track_index++
		track_last++
	} # while tracks

	#	---------------------------------------------
	#	Done  sort all the events
	#	---------------------------------------------

	if ((sort_index-1) != total_events) {
		print "ERROR: total events in sorted list (" sort_index-1 ") != total_events (" total_events ")"
		exit
	}

	#
	#	now the sorted list is in
	#		sort_track[no_tracks, j]
	#		sort_event[no_tracks, j]
	#		sort_time[no_tracks, j]
	#

	#
	#	DEBUGGER  display the sorted list
	#
#	for (i=1; i<=total_events; i++) {
#		print "DEBUGGER: event " i ", " event_info_string(no_tracks,i)
#	}


	#
	#	create the output file
	#
	#	each line begins with a time duration
	#	this duration is the time from that line up to the following line
	#	(unlike the midi time delta, which is the time SINCE THE LAST NOTE)
	#
	last_time = 0
	curr_time = 0
	last_is_a_note = 0
	for (i=1; i<=total_events; i++) {

		track_index = sort_track[no_tracks, i]
		event_index = sort_event[no_tracks, i]
		if (is_a_noteoff_or_attackzero(track_index,event_index)) {
			continue
		}
		event_type = TrackEvents_eventtype[track_index, event_index]
		if (event_type == 2) {

			if (TrackEvents_metatype[track_index, event_index] == 47) {
				continue
			}
		}
		curr_time = sort_time[no_tracks, i]


		#
		#	if the last event was not a note
		#	then we must print that bar (since we now know its duration)
		#	regardless of whether the current event is a note or not
		#
		if (!last_is_a_note &&  i > 1) {
			if (event_bar != "") {
				#
				#	print the event bar (created for the last event)
				#
				score_dur = curr_time - last_time
				dursym = make_duration_string(score_dur)
				score_bar = sprintf("%10s %16s", dursym, event_bar)
				print score_bar

			} # if
			else {
				print "ERROR: empty event bar"
				exit
			}
		} # if -- !last_is_a_note

		#
		#	dump this event into either the event bar or the notes bar
		#
		is_a_note = event_bar_type(event_type, track_index, event_index)
		if (is_a_note) {

			if (!last_is_a_note) {
				print "#	------------------------------------------------------------------"
			}

			#
			#	put into the note bar
			#
			byte3 = TrackEvents_midibyte3[track_index,event_index]
			if (TrackEvents_midicommand[track_index,event_index]==9 && byte3 > 0) {
				#
				#	we don't show NOTE OFF events, because their effect
				#	has been accounted for by the note duration
				#

				note_bar = make_note_bar(track_index, event_index)
				# print "DEBUGGER: curr_time= " curr_time ", note bar = (" note_bar "), last_time= (" last_time ")"

				same_track_as_before = (track_index in note_bar_array)
				if ((curr_time == last_time || !last_is_a_note) && !same_track_as_before) {
					#
					#	same time as last event
					#
					note_bar_array[track_index] = note_bar
		
				} # if
				else {
					#
					#	the time jumped  (between notes)
					#
					#
					score_dur = curr_time - last_time	# duration of the bar about to be printed
					dursym = make_duration_string(score_dur)
	
					#
					#	print the last note bar (if there was one)
					#
					score_bar = sprintf("%10s  ", dursym)	# pad up to 6 characters
					for (j=1; j<=no_tracks; j++) {
						if ( j in note_bar_array ) {
							#
							#	print the note spec, formatted
							#
							#	the center of text should be at character number:
							#	--- the duration stamp takes up 14 at the left
							#	--- each track takes up 20 and 1 on each side = 22
							#	---	the track center is therefore 11 from the beginning
							#		of its location
							#
							#	(14 + j*22) - 11
							#
							score_bar = sprintf("%s %16s ", score_bar, note_bar_array[j])
							delete note_bar_array[j]
						}
						else {
							score_bar = sprintf("%s       |        ", score_bar)
						} # else -- empty track
					} # for -- j over tracks
					

					#
					#	output the tracks across the screen
					#
					print score_bar
	
					#
					#	re-init the bar
					#
					#	clear the note_bar_array
					#
					for (j=1; j<=no_tracks; j++) {
						delete note_bar_array[j]
					}
					#
					#	the first note in the new bar
					#
					note_bar_array[track_index] = note_bar
		
				} # else -- time jumped

				last_note_on = 1
			} # if -- note on
			else {
				# print "DEBUGGER: not a note on ( " event_info_string(track_index,event_index) " )"
				last_note_on = 0
			}

			last_is_a_note = 1

		} # if -- is_a_note
		else {
			#
			#	not a note -- put into an event bar
			#
			# print "DEBUGGER: not a note (event " event_info_string(track_index,event_index) " )"

			if (last_is_a_note) {
				#
				#	we encountered a non-note before the time changed
				#	so we must print the notes before we go on to this
				#	status event
				#
				score_dur = curr_time - last_time	# duration of the last bar
				dursym = make_duration_string(score_dur)
				score_bar = sprintf("%10s  ", dursym)	# pad up to 6 characters
				for (j=1; j<=no_tracks; j++) {
					if ( j in note_bar_array ) {
						#
						#	print the note spec, formatted
						#

						#
						#	the center of text should be at character number:
						#	--- the duration stamp takes up 14 at the left
						#	--- each track takes up 20 and 1 on each side = 22
						#	---	the track center is therefore 11 from the beginning
						#		of its location
						#
						#	(14 + j*22) - 11
						#
						score_bar = sprintf("%s %16s ", score_bar, note_bar_array[j])
						delete note_bar_array[j]

					}
					else {

						score_bar = sprintf("%s       |        ", score_bar)

					} # else -- empty track

				} # for
				#
				#	output the tracks across the screen
				#
				print score_bar
				print "#	------------------------------------------------------------------"

			} # if -- last_is_a_note


			event_bar = make_event_bar(track_index, event_index)

			last_is_a_note = 0
		} # else


		last_time = curr_time

	} # for -- i




} # END


#	---------------------------------------------------------------------
#	---------------------------------------------------------------------
#	---------------------------------------------------------------------
#	---------------------------------------------------------------------
#	---------------------------------------------------------------------
#	---------------------------------------------------------------------



function hex_digit_to_decimal(hexdig)
{

	if (hexdig == "0") {
		return 0
	}
	else if (hexdig == "1") {
		return 1
	}
	else if (hexdig == "2") {
		return 2
	}
	else if (hexdig == "3") {
		return 3
	}
	else if (hexdig == "4") {
		return 4
	}
	else if (hexdig == "5") {
		return 5
	}
	else if (hexdig == "6") {
		return 6
	}
	else if (hexdig == "7") {
		return 7
	}
	else if (hexdig == "8") {
		return 8
	}
	else if (hexdig == "9") {
		return 9
	}
	else if (hexdig == "a") {
		return 10 
	}
	else if (hexdig == "A") {
		return 10 
	}
	else if (hexdig == "b") {
		return 11 
	}
	else if (hexdig == "B") {
		return 11 
	}
	else if (hexdig == "c") {
		return 12 
	}
	else if (hexdig == "C") {
		return 12 
	}
	else if (hexdig == "d") {
		return 13 
	}
	else if (hexdig == "D") {
		return 13 
	}
	else if (hexdig == "e") {
		return 14 
	}
	else if (hexdig == "E") {
		return 14 
	}
	else if (hexdig == "f") {
		return 15 
	}
	else if (hexdig == "F") {
		return 15 
	}
	else {
		return -1
	}
}
#	---------------- hex_digit_to_decimal --------------------------------



function hex_byte_to_decimal(hexbyte,   ch1,ch2,d1,d2)
{
	#
	#	hexbyte is assumed to be a character string
	#
	ch1 = substr(hexbyte, 1, 1)
	ch2 = substr(hexbyte, 2, 1)

	d1 = hex_digit_to_decimal(ch1)
	d2 = hex_digit_to_decimal(ch2)

	val = d1 * 16
	val += d2
	return val
}
#	--------------- hex_byte_to_decimal ---------------------------------



function hex_byte_sign_bit(hexbyte,   ch1,d1)
{
	#
	#	test the hex byte as a 2-character string
	#	return 1 if the sign bit is set
	#


	#
	#	high-order nibble
	#
	ch1 = substr(hexbyte, 1, 1)
	d1 = hex_digit_to_decimal(ch1)
	if (d1 >= 8) {
		return 1
	}


	return 0
}
#	---------------- hex_byte_sign_bit ----------------------------------



function hex_byte_lower_7_bits(hexbyte,   ch1,ch2,d1,d2)
{

	#
	#	test the hex byte as a 2-character string
	#	return the byte integer value without the MSB
	#
	#
	#	high-order nibble
	#
	ch1 = substr(hexbyte, 1, 1)
	ch2 = substr(hexbyte, 2, 1)
	d2 = hex_digit_to_decimal(ch2)

	if (ch1 == "0") {
		d1 = 0
	}
	else if (ch1 == "1") {
		d1 = 1
	}
	else if (ch1 == "2") {
		d1 = 2
	}
	else if (ch1 == "3") {
		d1 = 3
	}
	else if (ch1 == "4") {
		d1 = 4
	}
	else if (ch1 == "5") {
		d1 = 5
	}
	else if (ch1 == "6") {
		d1 = 6
	}
	else if (ch1 == "7") {
		d1 = 7
	}
	else if (ch1 == "8") {
		#	ignore high bit
		d1 = 0
	}
	else if (ch1 == "9") {
		#	ignore high bit
		d1 = 1
	}
	else if (ch1 == "a") {
		#	ignore high bit
		d1 = 2
	}
	else if (ch1 == "A") {
		#	ignore high bit
		d1 = 2
	}
	else if (ch1 == "b") {
		#	ignore high bit
		d1 = 3
	}
	else if (ch1 == "B") {
		#	ignore high bit
		d1 = 3
	}
	else if (ch1 == "c") {
		#	ignore high bit
		d1 = 4
	}
	else if (ch1 == "C") {
		#	ignore high bit
		d1 = 4
	}
	else if (ch1 == "d") {
		#	ignore high bit
		d1 = 5
	}
	else if (ch1 == "D") {
		#	ignore high bit
		d1 = 5
	}
	else if (ch1 == "e") {
		#	ignore high bit
		d1 = 6
	}
	else if (ch1 == "E") {
		#	ignore high bit
		d1 = 6
	}
	else if (ch1 == "f") {
		#	ignore high bit
		d1 = 7
	}
	else if (ch1 == "F") {
		#	ignore high bit
		d1 = 7
	}


	val = d1 * 16
	val += d2
	return val
}
#	---------------- hex_byte_lower_7_bits ------------------------------



function hex_byte_to_midi_channel(hexbyte,   ch2,d2)
{
	#
	#	Given a byte as a hexidecimal string, converts the low-order
	#	nibble to a decimal integer (midi channel)
	#
	ch2 = substr(hexbyte, 2, 1)
	d2 = hex_digit_to_decimal(ch2)
	return d2
}
#	------------------- hex_byte_to_midi_channel -----------------------



function hex_byte_to_midi_command(hexbyte,   ch1,d1)
{
	#
	#	Given a byte as a hexidecimal string, converts the high-order
	#	nibble to a decimal integer (midi command)
	#
	ch1 = substr(hexbyte, 1, 1)
	d1 = hex_digit_to_decimal(ch1)
	return d1
}
#	------------------- hex_byte_to_midi_command -----------------------


function clear_event_flags()
{

	#
	#	event flags
	#
	event_vtime_done=0
	event_vtime=0
	event_byte_cnt=0
	event_type_done=0
	last_event_type = event_type
	event_type=0
	event_end=0

	#
	#	meta event specific
	#
	last_meta_event_type = meta_event_type
	meta_event_type=0
	meta_length_done=0
	meta_length_cnt=0
	meta_length=0
	meta_data_done=0
	meta_data_cnt=0

	#
	#	MIDI event specific
	#
	last_midi_byte = midi_byte
	midi_byte=0
	last_midi_hex_byte = midi_hex_byte
	midi_hex_byte=0
	midi_control_number=0
	midi_note_number=0
	midi_program_number=0
	midi_channel_pressure=0
	midi_pitch_bend_high=0
	midi_velocity=0
	midi_key_pressure=0
	midi_control_value=0

}
#	------------------------ clear_event_flags -------------------------


function clear_track_flags()
{

	track_size[curr_track_no] = curr_event 

	if (debug_messages) {
		print "# track " curr_track_no " has " track_byte_count " bytes"
	}

	track_id_done=0
	track_id_bytes=0
	track_length_done=0
	track_len_byte_cnt=0
	track_length=0
	track_byte_count=0
	curr_event = 0
	curr_time=0
}
#	---------------------- clear_track_flags ---------------------------


function event_bar_type(eventtype, itrack, ievent,    cmd)
{

	#
	#	return 1 if this is a NOTE ON or NOTE OFF
	#
	if (eventtype == 1) {
		#
		#	MIDI event
		#
		cmd = TrackEvents_midicommand[itrack, ievent]
		if (cmd == 8 || cmd == 9) {
			return 1
		}
	}
	return 0
}
#	--------------------- event_bar_type --------------------------------



function make_event_bar(itrack, ievent,    eventtype,cmd,chn,retstring,byte2,byte3,metatype,metavalue)
{

	#
	#	return a formatted string
	#

	eventtype = TrackEvents_eventtype[itrack, ievent]
	if (eventtype==1) {
		#
		#	MIDI event
		#

		cmd = TrackEvents_midicommand[itrack, ievent]
		chn = TrackEvents_midichannel[itrack, ievent]
		byte2 =	TrackEvents_midibyte2[itrack, ievent]
		if ( (itrack,ievent) in TrackEvents_midibyte3 ) {
			byte3 =	TrackEvents_midibyte3[itrack, ievent]
		}
		else {
			byte3 = 0
		}

		retstring = sprintf("MIDI    TK%d    CH%d", itrack, chn+1)

		if (cmd == 10) {
			#
			#	key pressure (0xa0 to 0xaf)
			#
			retstring = sprintf("%s    KP%d    VL%d", retstring, byte2, byte3)
		}
		else if (cmd == 11) {
			#
			#	control (0xb0 to 0xbf)
			#
			retstring = sprintf("%s    CT%d    VL%d", retstring, byte2, byte3)
		}
		else if (cmd == 12) {
			#
			#	program ("patch")(0xc0 to 0xcf)
			#
			retstring = sprintf("%s    PG%d", retstring, byte2)
		}
		else if (cmd == 13) {
			#
			#	channel pressure (0xd0 to 0xdf)
			#
			retstring = sprintf("%s    CP%d", retstring, byte2)
		}
		else if (cmd == 14) {
			#
			#	pitch bend (0xe0 to 0xef)
			#
			retstring = sprintf("%s    PB%d", retstring, byte2)
			if (byte3) {
				retstring = sprintf("%s    VL%d", retstring, byte3)
			}
			else {
				retstring = sprintf("%s    VL0", retstring)
			}
		}
		else {
			print "ERROR: make_event_bar: MIDI command " cmd " doesn't belong here"
			exit
		}

	} # if
	else if (eventtype==2) {
		#
		#	META event
		#
		retstring = sprintf("META    TK%d", itrack)

		metatype = TrackEvents_metatype[itrack, ievent]
		if ( (itrack,ievent) in TrackEvents_metavalue ) {
			metavalue = TrackEvents_metavalue[itrack, ievent]
		}
		else {
			metavalue = 0
		}

		if (metatype == 0) {
			#	sequence number
			sequence_number = metavalue
			retstring = sprintf("%s    SEQNUM%d", retstring, sequence_number)
		}
		else if (metatype == 1) {
			#	text
			retstring = sprintf("%s    TEXT    %s", retstring, metavalue)
		}
		else if (metatype == 2) {
			#	Copyright notice
			retstring = sprintf("%s    COPYRIGHT    %s", retstring, metavalue)
		}
		else if (metatype == 3) {
			#	track name
			retstring = sprintf("%s    TRACKNAME    %s", retstring, metavalue)
		}
		else if (metatype == 4) {
			#	instrument name
			retstring = sprintf("%s    INSTRNAME    %s", retstring, metavalue)
		}
		else if (metatype == 5) {
			#	lyrics
			retstring = sprintf("%s    LYRICS    %s", retstring, metavalue)
		}
		else if (metatype == 6) {
			#	marker text
			retstring = sprintf("%s    MARKER    %s", retstring, metavalue)
		}
		else if (metatype == 7) {
			#	cue point
			retstring = sprintf("%s    CUE    %s", retstring, metavalue)
		}
		else if (metatype == 32) {
			#	midi channel prefix
			retstring = sprintf("%s    CHANNEL    %s", retstring, metavalue)
		}
		else if (metatype == 33) {
			#	midi port
			retstring = sprintf("%s    MIDIPORT    %s", retstring, metavalue)
		}
		else if (metatype == 47) {
			#	end of track
			retstring = "END_OF_TRACK"
		}
		else if (metatype == 81) {
			#	tempo
			retstring = sprintf("%s    TEMPO    %d", retstring, metavalue)
		}
		else if (metatype == 84) {
			#	SMPTE offset
			retstring = sprintf("%s    SMPTE_OFFSET    %s", retstring, metavalue)
		}
		else if (metatype == 88) {
			#	time signature
			retstring = sprintf("%s    TIME_SIGNATURE    %s", retstring, metavalue)
		}
		else if (metatype == 89) {
			#	key signature
			retstring = sprintf("%s    KEY_SIGNATURE    %s", retstring, metavalue)
		}
		else if (metatype == 127) {
			#	sequencer-specific
			retstring = sprintf("%s    SEQUENCER_SPECIFIC    %s", retstring, metavalue)
        }
		else {
			print "ERROR: unknown meta event type (" metatype ")"
			exit
		}
	}
	else if (eventtype==3) {
		#
		#	SYSEX event
		#
		print "ERROR: unknown sysex event"
		exit
	}
	else if (eventtype==4) {
		#
		#	SYS COMMON event
		#
		print "ERROR: unknown sysex event"
		exit
	}
	else if (eventtype==5) {
		#
		#	SYS REALTIME event
		#
		print "ERROR: unknown sysex event"
		exit
	}
	else {
		print "ERROR: unknown event type (" eventtype ")"
		exit
	}


	return retstring
}
#	-------------------- make_event_bar ----------------------------------



function make_note_bar(itrack, ievent,    eventtype,cmd,chn,retstring,byte2,byte3,dur,durstr)
{

	#
	#	return a formatted string
	#

	eventtype = TrackEvents_eventtype[itrack, ievent]
	if (eventtype==1) {
		#
		#	MIDI event
		#

		cmd = TrackEvents_midicommand[itrack, ievent]
		chn = TrackEvents_midichannel[itrack, ievent]
		byte2 =	TrackEvents_midibyte2[itrack, ievent]
		if ( (itrack,ievent) in TrackEvents_midibyte3 ) {
			byte3 =	TrackEvents_midibyte3[itrack, ievent]
		}
		else {
			byte3 = 0
		}


		if (cmd == 9) {
			#
			#	note on
			#
			dur = TrackEvents_duration[itrack,ievent]
			durstr = make_duration_string(dur)
			retstring = sprintf("@%d{%d__%s}%d", chn+1, byte2, durstr, byte3)
		}
		else {
			print "ERROR: make_note_bar: MIDI command " cmd " doesn't belong here"
			exit
		}

	} # if
	else {
		print "ERROR: make_note_bar: event not MIDI"
		exit
	}

	return retstring
}
#	-------------------- make_note_bar ----------------------------------



function find_note_off(itrack, after_event,    ncmd,chn,i,nnum,mnum,sevent)
{
	#
	#	returns the event number
	#	of the note off
	#	this track, this channel, this note number
	#	that comes after "after_event"
	#
	#	find attack 0 as well as note off
	#	(try to avoid spurious long notes that find spurious note offs)
	#
	chn = TrackEvents_midichannel[itrack, after_event]
	nnum = TrackEvents_midibyte2[itrack, after_event]

	sevent = after_event+1
	for (i=sevent; i<=track_size[itrack]; i++) {

		#
		#	break out if we have exceeded the index limit
		#
		if ( (itrack,i) in TrackEvents_eventtype ) {

			if (TrackEvents_eventtype[itrack,i]==1) {

				if ( (itrack,i) in TrackEvents_midibyte2 ) {
		
					mnum = TrackEvents_midibyte2[itrack, i]
		
					if ( (itrack,i) in TrackEvents_midichannel ) {
						nchn = TrackEvents_midichannel[itrack,i]
		
						if ( (itrack,i) in TrackEvents_midicommand ) {
							ncmd = TrackEvents_midicommand[itrack, i]
		
							if (ncmd==8 && nnum==mnum && chn==nchn) {
								#
								# note off, note number and channel agrees
								#
								return i
							} # if
							else if (ncmd==9 && nnum==mnum && chn==nchn) {
								#
								# note on, note number and channel agrees
								#
								if ( (itrack,i) in TrackEvents_midibyte3 ) {
									#
									#	attack 0
									#
									if (TrackEvents_midibyte3[itrack,i]==0) {
										return i
									}
								}
							} # else if
		
						} # if
		
		
					} # if -- midichannel
		
				} # if -- in midibyte2

			} # if -- midi event

		} # if -- in eventtype


	} # for -- i

	return 0
}
#	-------------------  find_note_off  ---------------------------------



function find_attack_zero(itrack, after_event,    ncmd,chn,i,nnum,mnum,sevent)
{
	#
	#	returns the event number
	#	of the note off (attack zero)
	#	this track, this channel, this note number
	#	that comes after "after_event"
	#
	chn = TrackEvents_midichannel[itrack, after_event]
	nnum = TrackEvents_midibyte2[itrack, after_event]

	sevent = after_event+1
	for (i=sevent; i<=track_size[itrack]; i++) {

		#
		#	break out if we have exceeded the index limit
		#
		if ( (itrack,i) in TrackEvents_eventtype ) {

			if (TrackEvents_eventtype[itrack,i]==1) {

				if ( (itrack,i) in TrackEvents_midibyte2 ) {
		
					mnum = TrackEvents_midibyte2[itrack, i]
		
					if ( (itrack,i) in TrackEvents_midichannel ) {
						nchn = TrackEvents_midichannel[itrack,i]
		
						if ( (itrack,i) in TrackEvents_midicommand ) {
							ncmd = TrackEvents_midicommand[itrack, i]
		
							if (ncmd==9 && nnum==mnum && chn==nchn) {
								#
								# note on, note number and channel agrees
								# but attack is zero
								if ( (itrack,i) in TrackEvents_midibyte3 ) {
									if (TrackEvents_midibyte3[itrack,i]==0) {
										return i
									}
								}
								#
							} # if
		
						} # if
		
		
					} # if -- midichannel
		
				} # if -- in midibyte2

			} # if -- midi event

		} # if -- in eventtype


	} # for -- i

	return 0
}
#	-------------------  find_attack_zero  ---------------------------------




function make_duration_string_1(duration,   tbeats,retstr)
{
	#
	#	duration is assumed to be in units of midi ticks
	#
	#	uses global time constants, "division", and "tempo_bpm"
	#

	tbeats = duration / division	#	beats (1 beat = quarter note)

	if (tbeats == 0) {
		retstr = sprintf("0")
	}
	else {
		retstr = sprintf("%gq", tbeats)
	}
	return retstr
}
#	------------------ make_duration_string_1 -----------------------------



function make_duration_string(duration,   tbeats,retstr)
{
	#
	#	duration is assumed to be in units of midi ticks
	#
	#	uses global time constants, "division", and "tempo_bpm"
	#

	tbeats = duration / division	#	beats (1 beat = quarter note)

	if (tbeats == 0) {
		retstr = sprintf("0")
	}
	else {

		#
		#	in whole notes?
		#
		if (tbeats >= 4) {
			twholes = tbeats / 4
			if (twholes == 1) {
				retstr = sprintf("o")
			}
			else {
				retstr = sprintf("%go", twholes)
			}
		}
		else if (tbeats >= 2) {
			thalves = tbeats / 2
			if (thalves == 1) {
				retstr = sprintf("h")
			}
			else {
				retstr = sprintf("%gh", thalves)
			}
		}
		else if (tbeats >= 1) {
			if (tbeats == 1) {
				retstr = sprintf("q")
			}
			else {
				retstr = sprintf("%gq", tbeats)
			}
		}
		else if (tbeats >= 0.5) {
			teights = tbeats * 2
			if (teights == 1) {
				retstr = sprintf("*")
			}
			else {
				retstr = sprintf("%g*", teights)
			}
		}
		else  {
			tsixteenth = tbeats * 4
			if (tsixteenth == 1) {
				retstr = sprintf("!")
			}
			else {
				retstr = sprintf("%g!", tsixteenth)
			}
		}

	} # else -- tbeats > 0

	return retstr
}
#	------------------ make_duration_string -----------------------------



function event_info_string(tracknum, eventnum,    tmpstr)
{

	if (TrackEvents_eventtype[tracknum,eventnum] == 1) {
		tmpstr = sprintf("midi");
		tmpstr = sprintf("%s command %d", tmpstr, TrackEvents_midicommand[tracknum,eventnum])
	}
	else if (TrackEvents_eventtype[tracknum,eventnum] == 2) {
		tmpstr = sprintf("meta");
	}
	else {
	}

	return tmpstr
}
#	------------------- event_info_string -------------------------------



function is_a_noteoff_or_attackzero(tracknum, eventnum)
{

	if (TrackEvents_eventtype[tracknum, eventnum] == 1) {
		#
		#	is a MIDI event
		#
		if (TrackEvents_midicommand[tracknum,eventnum]==8) {
			return 1
		} # if -- note ooff
		else if (TrackEvents_midicommand[tracknum,eventnum]==9) {
			if (TrackEvents_midibyte3[tracknum,eventnum] == 0) {

				return 1

			}
		} # if -- note on

	} # if -- is MIDI

	return 0
}
#	------------------ is_a_noteoff_or_attackzero -----------------------



