#
#	CS2MTX.AWK
#
#  -----------------------------------------------------------------------
#  Copyright 2007  Alfred Steffens Jr.
#  -----------------------------------------------------------------------
#  -----------------------------------------------------------------------
#    Copying Permission:
#
#    mscore 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.
#
#    mscore 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 mscore (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
#
#	rev. 1.1    4/4/2007   A. Steffens
#		Fixed bug that suddenly appeared (?) when reading the csound
#		instrument number and assigning the midi channel.  The instr
#		variable was being used in 2 different ways, so I changed the
#		instr to instr_id when parsing the csound instrument number.
#
#   Description:
#
#	Csound to MTX converter  (MTX is a text representation of MIDI)
#
#	Usage:
#
#		cat <csound_score>  | awk -f cs2mtx.awk  bpm=<beats_per_minute>
#				[optional arguments]
#			 	pitchtype=<0 or 1>
#			 	drums=<instr list>
#				pf_amp=<pfield>
#				pf_pan=<pfield>
#				instr_max=<max instr number>
#				tracks=<track list>
#				nshift=<shift list (per track)>
#				alias<N>=<alias list>
#
#	1.	Instruments are truncated to whole numbers
#
#	2.	bmp = "beats per minute", where 1 beat is a quarter note (per ascore)
#
#	3.	(optional) pitchtype= either 0 or 1.  If pitchtype=0, then it is a
#				 Csound pitch (8.00, etc)
#		If pitchtype=1, then it is in Hz.
#		Default is pitchtype not given (is 0), therefore use Csound pitch
#
#	4.	(optional) drums= list of instrument numbers that all are overwritten
#			 as CH10.	For example,  drums=51,52,53
#		means that any occurence of instr 51 or 52 or 53 is automatically
#		written as CH10 instead of CH51, CH52, or CH53
#
#	5.	(optional) pf_amp= which csound score field contains amplitude (default
#			is field 6
#	6.	(optional) pf_pan= which csound score field contains pan (default is
#			field 7
#	7.	(optional)	maximum instrument number, above which to ignore.  This
#			would be needed where there are special instruments, such as
#			reverb, that have high instrument numbers, but are meaningless
#			in the MIDI output.  Default=100.
#	8.	(optional) list of instrument numbers to be assigned to separate midi
#			tracks.  For example,  
#
#					tracks=1,2,3,10,12
#
#			would assign ch1 to track 1, ch2 to track 2, ch3 to track 3,
#			ch10 to track 4, ch12 to track 5.
#
#	9.	(optional) nshift
#
#					nshift=0,0,12,0,-12
#
#			shifts tracks 3 up my 12 semi tones, track 5 down by 12 semi tones
#
#	10.	(optional)	alias<N>
#
#					alias2=30,31,32
#
#			causes instr 30, 31, 32 to be written to CH2
#
#					alias5=20,21,22
#
#			causes instr 20, 21, 22 to be written to CH5
#
#	-----------------------------------------------------------------------
#	The default CSOUND score line format will be:
#
#		1		2			3			4		5			6		7
#		instr	start_time	duration	pitch	attack		amp		pan
#
#	-----------------------------------------------------------------------


#
#	MIDI note numbers to Musical scale
#   Csound's 8.00 == middle C  == midi C5
#   Csound's 8.09 == concert A == midi A5
#
#   Octave||                     Note Numbers
#      #  ||
#         || C   | C#  | D   | D#  | E   | F   | F#  | G   | G#  | A   | A#  | B
#   ------------------------------------------------------------------------------
#      0  ||   0 |   1 |   2 |   3 |   4 |   5 |   6 |   7 |   8 |   9 |  10 |  11
#      1  ||  12 |  13 |  14 |  15 |  16 |  17 |  18 |  19 |  20 |  21 |  22 |  23
#      2  ||  24 |  25 |  26 |  27 |  28 |  29 |  30 |  31 |  32 |  33 |  34 |  35
#      3  ||  36 |  37 |  38 |  39 |  40 |  41 |  42 |  43 |  44 |  45 |  46 |  47
#      4  ||  48 |  49 |  50 |  51 |  52 |  53 |  54 |  55 |  56 |  57 |  58 |  59
#      5  ||  60 |  61 |  62 |  63 |  64 |  65 |  66 |  67 |  68 |  69 |  70 |  71
#      6  ||  72 |  73 |  74 |  75 |  76 |  77 |  78 |  79 |  80 |  81 |  82 |  83
#      7  ||  84 |  85 |  86 |  87 |  88 |  89 |  90 |  91 |  92 |  93 |  94 |  95
#      8  ||  96 |  97 |  98 |  99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107
#      9  || 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119
#     10  || 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 |





BEGIN {
	cline = 1
	mline = 1
	curr_time = 0
	del_time = 0
	last_time = 0
	curr_ticks = 0
	del_ticks = 0
	last_ticks = 0
	derr=0
	terr=0
	init_flag=0
	instr_max = 100	# default for input parameter
	alias1 = ""
	alias2 = ""
	alias3 = ""
	alias4 = ""
	alias5 = ""
	alias6 = ""
	alias7 = ""
	alias8 = ""
	alias9 = ""
	alias10 = ""
	alias11 = ""
	alias12 = ""
	alias13 = ""
	alias14 = ""
	alias15 = ""
	alias16 = ""

	#
	#	array used in Freq_to_Note()
	#
	freq[0] = 8.1757989
	freq[1] = 8.6619572
	freq[2] = 9.1770240
	freq[4] = 10.30086115
	freq[5] = 10.91338223
	freq[6] = 11.56232571
	freq[7] = 12.24985737
	freq[8] = 12.97827180
	freq[9] = 13.75
	freq[10] = 14.5676175
	freq[11] = 15.4338532
	freq[12] = 16.3515978
	freq[13] = 17.3239144
	freq[14] = 18.3540480
	freq[15] = 19.4454365
	freq[16] = 20.6017223
	freq[17] = 21.8267645
	freq[18] = 23.1246514
	freq[19] = 24.4997147
	freq[20] = 25.9565436
	freq[21] = 27.5
	freq[22] = 29.1352351
	freq[23] = 30.8677063
	freq[24] = 32.7031957
	freq[25] = 34.6478289
	freq[26] = 36.7080960
	freq[27] = 38.8908730
	freq[28] = 41.2034446
	freq[29] = 43.6535289
	freq[30] = 46.2493028
	freq[31] = 48.9994295
	freq[32] = 51.9130872
	freq[33] = 55.0
	freq[34] = 58.2704702
	freq[35] = 61.7354127
	freq[36] = 65.4063913
	freq[37] = 69.2956577
	freq[38] = 73.4161920
	freq[39] = 77.7817459
	freq[40] = 82.4068892
	freq[41] = 87.3070579
	freq[42] = 92.4986057
	freq[43] = 97.9988590
	freq[44] = 103.8261744
	freq[45] = 110.0
	freq[46] = 116.5409404
	freq[47] = 123.4708253
	freq[48] = 130.8127827
	freq[49] = 138.5913155
	freq[50] = 146.8323840
	freq[51] = 155.5634919
	freq[52] = 164.8137785
	freq[53] = 174.6141157
	freq[54] = 184.9972114
	freq[55] = 195.9977180
	freq[56] = 207.6523488
	freq[57] = 220.0
	freq[58] = 233.0818808
	freq[59] = 246.9416506
	freq[60] = 261.6255653

	freq[61] = 277.1826309
	freq[62] = 293.6647679
	freq[63] = 311.1269837
	freq[64] = 329.6275569
	freq[65] = 349.2282314
	freq[66] = 369.9944227
	freq[67] = 391.9954360
	freq[68] = 415.3046976
	freq[69] = 440.0
	freq[70] = 466.1637615
	freq[71] = 493.8833012
	freq[72] = 523.2511306
	freq[73] = 554.3652620
	freq[74] = 587.3295358
	freq[75] = 622.2539674
	freq[76] = 659.2551138
	freq[77] = 698.4564629
	freq[78] = 739.9888454
	freq[79] = 783.9908720
	freq[80] = 830.6093952
	freq[81] = 880.0 
	freq[82] = 932.3275230
	freq[83] = 987.7666025
	freq[84] = 1046.502261
	freq[85] = 1108.730523
	freq[86] = 1174.659072
	freq[87] = 1244.507934
	freq[88] = 1318.510227
	freq[89] = 1396.912925
	freq[90] = 1479.977690
	freq[91] = 1567.981743
	freq[92] = 1661.218790
	freq[93] = 1760.0
	freq[94] = 1864.655046
	freq[95] = 1975.533205
	freq[96] = 2093.004522

	freq[97] = 2217.461047
	freq[98] = 2349.318143
	freq[99] = 2489.015869
	freq[100] = 2637.020455
	freq[101] = 2793.825851
	freq[102] = 2959.955381
	freq[103] = 3135.963487
	freq[104] = 3322.437580
	freq[105] = 3520.0
	freq[106] = 3729.310092
	freq[107] = 3951.066410
	freq[108] = 4186.009044
	freq[109] = 4434.922095
	freq[110] = 4698.636286
	freq[111] = 4978.031739
	freq[112] = 5274.040910
	freq[113] = 5587.651702
	freq[114] = 5919.910763
	freq[115] = 6271.926975
	freq[116] = 6644.875161
	freq[117] = 7040.0
	freq[118] = 7458.620184
	freq[119] = 7902.132820
	freq[120] = 8372.018090
	freq[121] = 8869.844191
	freq[122] = 9397.272573
	freq[123] = 9956.063479
	freq[124] = 10548.081821
	freq[125] = 11175.303405
	freq[126] = 11839.821526
	freq[127] = 12543.853951

	#
	#	array used in Pitch_to_Note
	#
	pchnote[3,0] = 0		# C_0 in midi
	pchnote[3,1] = 1
	pchnote[3,2] = 2
	pchnote[3,3] = 3
	pchnote[3,4] = 4
	pchnote[3,5] = 5
	pchnote[3,6] = 6
	pchnote[3,7] = 7
	pchnote[3,8] = 8
	pchnote[3,9] = 9
	pchnote[3,10] = 10
	pchnote[3,11] = 11
	pchnote[4,0] = 12		# C_1 in midi
	pchnote[4,1] = 13
	pchnote[4,2] = 14
	pchnote[4,3] = 15
	pchnote[4,4] = 16
	pchnote[4,5] = 17
	pchnote[4,6] = 18
	pchnote[4,7] = 19
	pchnote[4,8] = 20
	pchnote[4,9] = 21
	pchnote[4,10] = 22
	pchnote[4,11] = 23
	pchnote[5,0] = 24			# C_2 in midi
	pchnote[5,1] = 25
	pchnote[5,2] = 26
	pchnote[5,3] = 27
	pchnote[5,4] = 28
	pchnote[5,5] = 29
	pchnote[5,6] = 30
	pchnote[5,7] = 31
	pchnote[5,8] = 32
	pchnote[5,9] = 33
	pchnote[5,10] = 34
	pchnote[5,11] = 35
	pchnote[6,0] = 36			# C_3 in midi
	pchnote[6,1] = 37
	pchnote[6,2] = 38
	pchnote[6,3] = 39
	pchnote[6,4] = 40
	pchnote[6,5] = 41
	pchnote[6,6] = 42
	pchnote[6,7] = 43
	pchnote[6,8] = 44
	pchnote[6,9] = 45
	pchnote[6,10] = 46
	pchnote[6,11] = 47
	pchnote[7,0] = 48			# C_4 in midi
	pchnote[7,1] = 49
	pchnote[7,2] = 50
	pchnote[7,3] = 51
	pchnote[7,4] = 52
	pchnote[7,5] = 53
	pchnote[7,6] = 54
	pchnote[7,7] = 55
	pchnote[7,8] = 56
	pchnote[7,9] = 57
	pchnote[7,10] = 58
	pchnote[7,11] = 59
	pchnote[8,0] = 60			# middle C  (C_5)
	pchnote[8,1] = 61
	pchnote[8,2] = 62
	pchnote[8,3] = 63
	pchnote[8,4] = 64
	pchnote[8,5] = 65
	pchnote[8,6] = 66
	pchnote[8,7] = 67
	pchnote[8,8] = 68
	pchnote[8,9] = 69
	pchnote[8,10] = 70
	pchnote[8,11] = 71
	pchnote[9,0] = 72			# C_6 in midi
	pchnote[9,1] = 73
	pchnote[9,2] = 74
	pchnote[9,3] = 75
	pchnote[9,4] = 76
	pchnote[9,5] = 77
	pchnote[9,6] = 78
	pchnote[9,7] = 79
	pchnote[9,8] = 80
	pchnote[9,9] = 81
	pchnote[9,10] = 82
	pchnote[9,11] = 83
	pchnote[10,0] = 84			# C_7 in midi
	pchnote[10,1] = 85
	pchnote[10,2] = 86
	pchnote[10,3] = 87
	pchnote[10,4] = 88
	pchnote[10,5] = 89
	pchnote[10,6] = 90
	pchnote[10,7] = 91
	pchnote[10,8] = 92
	pchnote[10,9] = 93
	pchnote[10,10] = 94
	pchnote[10,11] = 95
	pchnote[11,0] = 96			# C_8 in midi
	pchnote[11,1] = 97
	pchnote[11,2] = 98
	pchnote[11,3] = 99
	pchnote[11,4] = 100
	pchnote[11,5] = 101
	pchnote[11,6] = 102
	pchnote[11,7] = 103
	pchnote[11,8] = 104
	pchnote[11,9] = 105
	pchnote[11,10] = 106
	pchnote[11,11] = 107
	pchnote[12,0] = 108			# C_9 in midi
	pchnote[12,1] = 109
	pchnote[12,2] = 110
	pchnote[12,3] = 111
	pchnote[12,4] = 112
	pchnote[12,5] = 113
	pchnote[12,6] = 114
	pchnote[12,7] = 115
	pchnote[12,8] = 116
	pchnote[12,9] = 117
	pchnote[12,10] = 118
	pchnote[12,11] = 119
	pchnote[13,0] = 120		# C_10 in midi
	pchnote[13,1] = 121
	pchnote[13,2] = 122
	pchnote[13,3] = 123
	pchnote[13,4] = 124
	pchnote[13,5] = 125
	pchnote[13,6] = 126
	pchnote[13,7] = 127

}


$1 ~ /;;;(.)*/ {
	#
	# print comments
	#
	cmtstr = substr( $1, (index($1, ";")+3) )
	print "# " cmtstr
	next
}


$1 ~ /;(.)*/ {
	#
	# ignore ordinary comments
	#
	next
}



#
#	match only instrument lines (i1, i2, i3.4, i12, etc)
#
$1 ~ /i(.)*/ {

	if (init_flag==0) {
		if (drums != "") {
			derr = split(drums, dary, ",")
		}
		if (tracks != "") {
			terr = split(tracks, tary, ",")
		}
		serr = 0
		if (nshift != "") {
			serr = split(nshift, sary, ",")
		}
		if (alias1 != "") {
			a1err = split(alias1, a1ary, ",")
		}
		if (alias2 != "") {
			a2err = split(alias2, a2ary, ",")
		}
		if (alias3 != "") {
			a3err = split(alias3, a3ary, ",")
		}
		if (alias4 != "") {
			a4err = split(alias4, a4ary, ",")
		}
		if (alias5 != "") {
			a5err = split(alias5, a5ary, ",")
		}
		if (alias6 != "") {
			a6err = split(alias6, a6ary, ",")
		}
		if (alias7 != "") {
			a7err = split(alias7, a7ary, ",")
		}
		if (alias8 != "") {
			a8err = split(alias8, a8ary, ",")
		}
		if (alias9 != "") {
			a9err = split(alias9, a9ary, ",")
		}
		if (alias10 != "") {
			a10err = split(alias10, a10ary, ",")
		}
		if (alias11 != "") {
			a11err = split(alias11, a11ary, ",")
		}
		if (alias12 != "") {
			a12err = split(alias12, a12ary, ",")
		}
		if (alias13 != "") {
			a13err = split(alias13, a13ary, ",")
		}
		if (alias14 != "") {
			a14err = split(alias14, a14ary, ",")
		}
		if (alias15 != "") {
			a15err = split(alias15, a15ary, ",")
		}
		if (alias16 != "") {
			a16err = split(alias16, a16ary, ",")
		}
		init_flag=1
	}

	#
	#	instrument field
	#
	instr_id = int(substr($1, (index($1, "i")+1)))
	if (instr_max) {
		if (instr_id > instr_max) {
			next
		}
	}

	instr = -1     # default
	#
	#	check if this is a drum instr to be aliased as CH10
	#
	if (derr) {
		for (i=1; i<=derr; i++) {
			if (dary[i] == instr_id) {
				instr = 10
				break
			}
		}
	}
	#
	#	alias instruments to a certain channel
	#
	if (a1err) {
		for (i=1; i<=a1err; i++) {
			if (a1ary[i] == instr_id) {
				instr = 1
				break
			}
		}
	}
	if (a2err) {
		for (i=1; i<=a2err; i++) {
			if (a2ary[i] == instr_id) {
				instr = 2
				break
			}
		}
	}
	if (a3err) {
		for (i=1; i<=a3err; i++) {
			if (a3ary[i] == instr_id) {
				instr = 3
				break
			}
		}
	}
	if (a4err) {
		for (i=1; i<=a4err; i++) {
			if (a4ary[i] == instr_id) {
				instr = 4
				break
			}
		}
	}
	if (a5err) {
		for (i=1; i<=a5err; i++) {
			if (a5ary[i] == instr_id) {
				instr = 5
				break
			}
		}
	}
	if (a6err) {
		for (i=1; i<=a6err; i++) {
			if (a6ary[i] == instr_id) {
				instr = 6
				break
			}
		}
	}
	if (a7err) {
		for (i=1; i<=a7err; i++) {
			if (a7ary[i] == instr_id) {
				instr = 7
				break
			}
		}
	}
	if (a8err) {
		for (i=1; i<=a8err; i++) {
			if (a8ary[i] == instr_id) {
				instr = 8
				break
			}
		}
	}
	if (a9err) {
		for (i=1; i<=a9err; i++) {
			if (a9ary[i] == instr_id) {
				instr = 9
				break
			}
		}
	}
	if (a10err) {
		for (i=1; i<=a10err; i++) {
			if (a10ary[i] == instr_id) {
				instr = 10
				break
			}
		}
	}
	if (a11err) {
		for (i=1; i<=a11err; i++) {
			if (a11ary[i] == instr_id) {
				instr = 11
				break
			}
		}
	}
	if (a12err) {
		for (i=1; i<=a12err; i++) {
			if (a12ary[i] == instr_id) {
				instr = 12
				break
			}
		}
	}
	if (a13err) {
		for (i=1; i<=a13err; i++) {
			if (a13ary[i] == instr_id) {
				instr = 13
				break
			}
		}
	}
	if (a14err) {
		for (i=1; i<=a14err; i++) {
			if (a14ary[i] == instr_id) {
				instr = 14
				break
			}
		}
	}
	if (a15err) {
		for (i=1; i<=a15err; i++) {
			if (a15ary[i] == instr_id) {
				instr = 15
				break
			}
		}
	}
	if (a16err) {
		for (i=1; i<=a16err; i++) {
			if (a16ary[i] == instr_id) {
				instr = 16
				break
			}
		}
	}



	#
	#	start time
	#
	curr_time = $2


	#
	#	duration
	#
	duration = $3


	#
	#	pitch	-- expected to be in pitch number
	#
	pitch = $4


	#
	#	amplitude
	#
	attack = $5


	#
	#	pan	--	expected to be 0--1
	#
	if (pf_amp) {
		amplitude = $pf_amp
	}
	else {
		amplitude = $6
	}

	#
	#	attack	-- 0--127
	#
	if (pf_pan) {
		pan = $pf_pan
	}
	else {
		pan = $7
	}


	#
	#	calculations for converting time
	#
	if (bpm == 0) {
		print "WARNING: using default TEMPO 120 beats per minute"
		bpm = 120
	}

	if (cline > 1) {
		#
		#	2nd MTX line or after
		#
		del_time = curr_time - last_time	# time since previous
		#
		#	update the previous line's score time
		#
		m_score_time[mline-1] = seconds_to_score(del_time, bpm)

		# print "DEBUGGER: instr (" instr "), curr_time (" curr_time "), del_time (" del_time "), bpm (" bpm ")"
	}
	else {

		#
		#	first MTX line
		#
		#
		#	score time cannot be filled yet -- put a placeholder
		#
		m_score_time[mline] = 0
	}
	m_duration[mline] = seconds_to_score(duration, bpm)

	#
	#	MTX channel -- from the instr number
	#
	m_channel[mline] = instr


	#
	#	convert the frequency in Hz into a MIDI note number
	#
	if (pitchtype == 1) {
		if (pitch == 0) {
			m_notenumber[mline] = 0
		}
		else {
			m_notenumber[mline] = Freq_to_Note(pitch)
		}
	}
	else {
		if (pitch == 0) {
			m_notenumber[mline] = 0
		}
		else {
			m_notenumber[mline] = Pitch_to_Note(pitch)
		}
	}


	#
	#	pan
	#
	m_pan[mline] = pan

	#
	#	attack
	#
	m_attack[mline] = attack


	last_time = curr_time
	cline++
	mline++
}



END {

	total_lines = mline - 1
	same_line_flag = 0


	#
	#	shift any notes if needed
	#
	for (i=1; i<= total_lines; i++) {
		#
		#	shifting only workd for multi-track files
		#
		if (serr) {
			for (j=1; j<=terr; j++) {
				if (m_channel[i] == tary[j]) {
					m_notenumber[i] = shift_pitch_if_needed(m_notenumber[i], serr, sary, j)
				}
			}
		}
	}


	#
	#	print the output
	#
	for (i=1; i<= total_lines; i++) {

		#
		#	if we want a multi-track file
		#
		if (terr) {
			#
			#	multi-track
			#	printing tracks into the track_array goes on until a
			#	a termination condition:
			#	1.	The score_time (time until following note) is non-zero
			#	2.	More than one simultaneous note into the same channel
			#		is found.
			#
			#
			if ((m_score_time[i] == "") || (m_score_time[i] != 0)) {
				#
				#	this might be the last line in a simultaneous sequence
				#
				if (m_score_time[i] == "") {
					m_score_time[i] = 0
				}

				#
				if (same_line_flag) {
					#
					#	finish the simultaneous line
					#
					for (j=1; j<=terr; j++) {
						#
						#	find what track it goes into
						#
						if (m_channel[i] == tary[j]) {
							#
							#	this note spec goes into track "j" (j==column)
							#
							if (track_used[j]==1) {
								#
								#	track duplication:
								#	we already have a simultaneous note for
								#	this channel. Before we can add this note,
								#	we must print what we already have and
								#	empty the note buffer
								#
								score_string = sprintf("	0	")	# score time
								for (k=1; k<=terr; k++) {
									score_string = sprintf("%s	%s", 
											score_string, track_array[k])
								}
								print score_string
								#
								#	we're done with a simultaneous line--re-init for the
								#	next one
								#
								for (k=1; k<=terr; k++) {
									track_array[k] = sprintf("		|		")
									track_used[k] = 0
								} # for -- k
							} # if -- track duplication


							track_array[j] = sprintf("@%d{%d__%s}%d", m_channel[i],
								m_notenumber[i], m_duration[i], m_attack[i])

						} # if -- match

					} # for -- j

					#
					#	prepare to print
					#
					score_string = sprintf("	%s	", m_score_time[i])	# score time
					for (k=1; k<=terr; k++) {
						score_string = sprintf("%s	%s", 
								score_string, track_array[k])
					}
					print score_string

					#
					#	we're done with a simultaneous line--re-init for the
					#	next one
					#
					same_line_flag = 0
					for (k=1; k<=terr; k++) {
						track_array[k] = sprintf("		|		")
						track_used[k] = 0
					} # for -- k

				} # if -- last note of a simultaneous sequence
				else {
					#
					#	not simultaneous
					#	not the last note of a simultaneous sequence
					#	only one track gets filled
					#
					jfound = 0
					for (j=1; j<=terr; j++) {
						#
						#	find what track it goes into
						#
						if (m_channel[i] == tary[j]) {

							track_array[j] = sprintf("@%d{%d__%s}%d", m_channel[i],
								m_notenumber[i], m_duration[i], m_attack[i])
							jfound = 1

						} # if -- match

					} # for -- j

					#
					#	prepare to print
					#
					score_string = sprintf("	%s	", m_score_time[i])	# score time
					if (jfound==1) {
						for (k=1; k<=terr; k++) {
							score_string = sprintf("%s	%s", 
									score_string, track_array[k])
						}
					} # if -- jfound
					else {
						#	channel 0 ?
						score_string = sprintf("%s	META  TK1 TEXT Dummy Note", score_string)
					}
					print score_string

					#
					#	clean-up for the next line
					#
					same_line_flag = 0
					for (k=1; k<=terr; k++) {
						track_array[k] = sprintf("		|		")
						track_used[k] = 0
					}

				} # else -- isolated, non-simultaneous

			} # if -- not simultaneous
			else if (m_score_time[i] == 0) {
				#
				#	this line is simultaneous with the following line
				#	--as long as we don't get two consequtive lines in the
				#	same channel, they go on the same mtx line
				#
				for (j=1; j<=terr; j++) {

					if (m_channel[i] == tary[j]) {
						#
						#	this note spec goes into track "j" (j==column)
						#
						if (track_used[j]==1) {
							#
							#	track duplication:
							#	we already have a simultaneous note for this channel
							#	Before we can add this note, we must print what we
							#	already have and empty the note buffer
							#
							score_string = sprintf("	0	")	# score time
							for (k=1; k<=terr; k++) {
								score_string = sprintf("%s	%s", 
										score_string, track_array[k])
							}
							print score_string
							#
							#	we're done with a simultaneous line--re-init for the
							#	next one
							#
							for (k=1; k<=terr; k++) {
								track_array[k] = sprintf("		|		")
								track_used[k] = 0
							} # for -- k

						} # if -- track duplication
						#
						#	first note into this track
						#
						track_array[j] = sprintf("@%d{%d__%s}%d", m_channel[i],
							m_notenumber[i], m_duration[i], m_attack[i])
						track_used[j] = 1
						#
						#	we DO NOT re-init the track_array here because
						#	subsequent lines will be added to it
						#
						same_line_flag = 1	# the following line is simultaneous

					} # if -- ch match to track

				} # for -- j

			} # else if -- score time is 0
			else {
				print "BUG: unknown score time condition"
				exit
			}

		} # if -- multi-track
		else {
			#
			#	all channels are going into a single track
			#
			if (m_score_time[i] == "") {
				m_score_time[i] = 0
			}
			print 	"	" m_score_time[i] "		@"	m_channel[i] "{" m_notenumber[i] "__" m_duration[i] "}" m_attack[i]
		} # else

	} # for -- i

}
#	-------------------------- END ----------------------------------------




function seconds_to_score(sec, bpm_tempo,     qsec,esec,ssec,hsec,wsec)
{

	#
	#	seconds in a quarter note
	#
	qsec = (1/bpm_tempo) * 60
	esec = qsec / 2				# secs in 8th
	ssec = esec / 2				# secs in 16th
	hsec = qsec * 2				# secs in half
	wsec = hsec * 2				# secs in whole


	if (sec <= ssec) {
		ratio = sec / ssec
		#	remove 0's and 1's
		if (ratio == 0) {
			retstr = sprintf("0")
		}
		else if (ratio < 0.0001) {
			retstr = sprintf("0")
		}
		else if (ratio == 1) {
			retstr = sprintf("!")
		}
		else {
			retstr = sprintf("%g!", ratio)
		}
	}
	else if (sec <= esec) {
		ratio = sec / esec
		#	remove 0's and 1's
		if (ratio == 0) {
			retstr = sprintf("0")
		}
		else if (ratio == 1) {
			retstr = sprintf("*")
		}
		else {
			retstr = sprintf("%g*", ratio)
		}
	}
	else if (sec <= qsec) {
		ratio = sec / qsec
		#	remove 0's and 1's
		if (ratio == 0) {
			retstr = sprintf("0")
		}
		else if (ratio == 1) {
			retstr = sprintf("q")
		}
		else {
			retstr = sprintf("%gq", ratio)
		}
	}
	else if (sec <= hsec) {
		ratio = sec / hsec
		#	remove 0's and 1's
		if (ratio == 0) {
			retstr = sprintf("0")
		}
		else if (ratio == 1) {
			retstr = sprintf("h")
		}
		else {
			retstr = sprintf("%gh", ratio)
		}
	}
	else {
		ratio = sec / wsec
		#	remove 0's and 1's
		if (ratio == 0) {
			retstr = sprintf("0")
		}
		else if (ratio == 1) {
			retstr = sprintf("o")
		}
		else {
			retstr = sprintf("%go", ratio)
		}
	}

	return retstr
}
#	---------------------- seconds_to_score -------------------------------



function Freq_to_Note(frq,    i,up)
{

	for (i=0; i<=127; i++) {

		if (i < 127) {
			up = (freq[i] + freq[i+1])/2
		}
		else {
			up = 0
		}

		if (frq < (freq[i] + up)) {
			return i
		}
	}

	return 0
}
#	---------------------- Freq_to_Note -----------------------------------



function two_to_the_x(x,   lgg2,y)
{
	lgg2 = 0.6931472
	y = x * lgg2
	return exp(y)
}
#	---------------------- two_to_the_x -----------------------------------



function Pitch_to_Note(pth,    oct,semi,midinote)
{
#
#	Convert a Csound "pitch" note into a MIDI note
#	8.00 becomes pchnote[8][0]
#	7.04 becomes pchnote[7][4]
#	etc
#
	oct = int(pth)
	semi = pth - oct
	semi *= 100
	#
	#	ignore anything in the "thousanths" digit
	#	for example a csound pitch given as 8.023 should be read
	#	as simply 8.02
	#
	# semi = int(semi)
	midinote = pchnote[oct, semi]
	return midinote
}
#	---------------------- Pitch_to_Note ---------------------------------



function shift_pitch_if_needed(pth, nums, sarray, tracknumber,     i,tmppth)
{
	if (nums >= 1) {
		for (i=1; i<=nums; i++) {
			if (i == tracknumber) {
				if (sarray[i] != 0) {
					tmppth = pth + sarray[i]
					if (tmppth < 0)
						tmppth = 0
					if (tmppth > 127)
						tmppth = 127
					return tmppth
				}
			}
		}
	}
	return pth
}
#	------------------- shift_pitch_if_needed ------------------------------


