#
#	pre_cs2mtx.awk
#
#  -----------------------------------------------------------------------
#  Copyright 2009  Alfred Steffens Jr.
#  -----------------------------------------------------------------------
#  -----------------------------------------------------------------------
#    Copying Permission:
#
#    This program 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.
#
#    This program 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 this program (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.2
#
#   Revision history:
#   1.5     06/17/2009  A. Steffens Jr. BANKDEF statements.
#   1.4     07/16/2008  A. Steffens Jr. bug fix for multiple ports
#   1.3     06/01/2008  A. Steffens Jr. Added SYSEX
#   1.2     05/17/2008  A. Steffens Jr. Added code to fetch reverb setting
#   1.1     05/10/2008  A. Steffens Jr. Added code to fetch bank setting
#  ------------------------------------------------------------------------
#
#	Preprocessor for cs2mtx.awk
#	Specifically, it gathers the information that will be the command-line
#	parameters to run cs2mtx.awk.  It parses the output from ASCORE (the
#	hold.sco csound score file) and outputs a temporary shell script file
#	run_cs2mtx.sh which will call cs2mtx.awk.
#
#
#	Usage:
#
#		cat hold.sco | awk -f pre_cs2mtx.awk \
#
#

BEGIN {
	midi_channel_count=0
	first_tempo_found=1
    reverb_found = 0
	bpm = 100

    k = 1;
    for (i=1; i<=4; i++)
    {
        for (j=1; j<=16; j++)
        {
            midi_channel_bank[k] = -1
            k++
        }
    }

    k = 1;
    for (i=1; i<=4; i++)
    {
        for (j=1; j<=16; j++)
        {
            midi_channel_reverb[k] = -1
            k++
        }
    }

    k = 1;
    for (i=1; i<=4; i++)
    {
        for (j=1; j<=16; j++)
        {
            midi_channel_program[k] = -1
            k++
        }
    }

    k = 1;
    for (i=1; i<=4; i++)
    {
        for (j=1; j<=16; j++)
        {
            midi_channel_sysex[k] = -1
            k++
        }
    }

    bankdef_string = ""
}


#
#	find any line in the score file
#	that begins with ;CS2MTX
#
$1 ~ /;CS2MTX/ {

	#
	#	associate something with a MIDI channel
	#
	#
	if (index($2, "midi_channel") == 1) {

		if (is_an_integer($3)) {
			#
			#	valid midi channel syntax
			#
			chn = $3
			if (exists_midi_channel(chn)) {
				#
				#	good, the channel exists already
				#

			} # if -- there is already a midi channel found
			else {
				#
				#	add another midi channel
				#
				midi_channel_count++
				midi_channel_number[midi_channel_count] = chn
				midi_channel_instruments_count[chn] = 0
				midi_channel_nshift[chn] = 0
				midi_channel_program[chn] = 0
				midi_channel_volume[chn] = 0

			} # else -- first time this midi channel appears


			if (index($4, "instrument") == 1) {

				#
				#	associate an instrument with a midi channel
				#
				for (k=5; k <= NF; k++) {

					if (exists_midi_channel_instrument(chn, int($k))) {
						#
						#	we already know about it
						#
					}
					else {
						#
						#	add this instrument to this midi channel
						#	there can be more than one instrument assigned
						#	to a midi channel
						#
						midi_channel_instruments_count[chn] += 1
						j = midi_channel_instruments_count[chn]
						midi_channel_instruments[chn, j] = int($k)
	
					}

				} # for -- k

			}
			else if (index($4, "nshift") == 1) {

				midi_channel_nshift[chn] = int($5)

			}
			else if (index($4, "program") == 1) {

				midi_channel_program[chn] = int($5)

			}
			else if (index($4, "bank") == 1) {

				midi_channel_bank[chn] = int($5)

			}
			else if (index($4, "sysex") == 1) {

				midi_channel_sysex[chn] = $5
                for (iq=6; iq <= NF; iq++)
                {
				    midi_channel_sysex[chn] = sprintf("%s_%s", midi_channel_sysex[chn], $iq)
                }
			}
			else if (index($4, "reverb") == 1) {

                reverb_found = 1
				midi_channel_reverb[chn] = int($5)

			}
			else if (index($4, "volume") == 1) {

				midi_channel_volume[chn] = int($5)

			}
			else {
				print "ERROR: unknown property (" $4 ") for midi channel", chn | "1>&2"
				exit 1
			}


		} # midi_channel -- value
		else {

			print "ERROR: invalid midi channel (" chn ")" | "1>&2"
			exit 1

		}

	} #  midi_channel -- keyword

	next

} #  ;CS2MTX



$1 ~ /;TEMPO/ {

	if (first_tempo_found) {
		bpm = $2
		first_tempo_found = 0
	}

    next
}


#
#   BANKDEF
#
#   Expecting to find
#
#       ;BANKDEF   c1 v1  c2 v2  ...
#
$1 ~ /;BANKDEF/ {

    #
    #   Put this line into a string of comma-separated fields
    #
    bankline_string = ""
    nNumber = NF - 1
    nPairs = int(nNumber / 2)
    for (i=1; i <= nPairs; i++)
    {
        ipair = i - 1
        j = (ipair * 2) + 2
        k = j + 1
        if (bankline_string == "")
           bankline_string = sprintf("%d,%d", $j, $k)
        else
           bankline_string = sprintf("%s,%d,%d", bankline_string, $j, $k)
    }

    #
    #   Add this line to previous lines found by separating with a "+"
    #
    if (bankdef_string == "")
        bankdef_string = sprintf("%s", bankline_string)
    else
        bankdef_string = sprintf("%s+%s", bankdef_string, bankline_string)

    next
}
#   BANKDEF




END {

	#
	#	output the run_cs2mtx.sh script
	#
	if (midi_channel_count > 0) {


		print "#" > "run_cs2mtx.sh"
		print "#	run_cs2mtx.sh" >> "run_cs2mtx.sh"
		print "#	created automatically by pre_cs2mtx.awk" >> "run_cs2mtx.sh"
		print "#" >> "run_cs2mtx.sh"

		#
		#	create the "channels" string, which will give the order of the midi
		#	channels to the cs2mtx.awk command line
		#
		channels_string = sprintf("%d", midi_channel_number[1])
		for (i=2; i <= midi_channel_count; i++) {
			#
			#
			#
			channels_string = sprintf("%s,%d", channels_string, midi_channel_number[i])

		}

		#
		#	create the "nshift" string
		#
		nshift_string = sprintf("%d", midi_channel_nshift[midi_channel_number[1]])
		for (i=2; i <= midi_channel_count; i++) {
			#
			#
			#
			nshift_string = sprintf("%s,%d", nshift_string, midi_channel_nshift[midi_channel_number[i]])

		}

		#
		#	create the "program" string
		#
		program_string = sprintf("%d", midi_channel_program[midi_channel_number[1]])
		for (i=2; i <= midi_channel_count; i++) {
			#
			#
			#
			program_string = sprintf("%s,%d", program_string, midi_channel_program[midi_channel_number[i]])

		}

		#
		#	create the "bank" string
		#
		bank_string = sprintf("%d", midi_channel_bank[midi_channel_number[1]])
		for (i=2; i <= midi_channel_count; i++) {
			#
			#
			#
			bank_string = sprintf("%s,%d", bank_string, midi_channel_bank[midi_channel_number[i]])

		}

		#
		#	create the "sysex" string
		#
        if (midi_channel_sysex[midi_channel_number[1]] == "-1")
            sysex_string = sprintf("%d", midi_channel_sysex[midi_channel_number[1]])
        else
            sysex_string = sprintf("%s", midi_channel_sysex[midi_channel_number[1]])

		for (i=2; i <= midi_channel_count; i++) {
			#
			#
			#
            if (midi_channel_sysex[midi_channel_number[i]] == "-1")
                sysex_string = sprintf("%s,%d", sysex_string, midi_channel_sysex[midi_channel_number[i]])
            else
                sysex_string = sprintf("%s,%s", sysex_string, midi_channel_sysex[midi_channel_number[i]])
		}

		#
		#	create the "reverb" string
		#
        if (reverb_found)
        {
            reverb_string = sprintf("%d", midi_channel_reverb[midi_channel_number[1]])
            for (i=2; i <= midi_channel_count; i++) {
                #
                #
                #
                reverb_string = sprintf("%s,%d", reverb_string, midi_channel_reverb[midi_channel_number[i]])

            }
        }

		#
		#	create the "volume" string
		#
		volume_string = sprintf("%d", midi_channel_volume[midi_channel_number[1]])
		for (i=2; i <= midi_channel_count; i++) {
			#
			#
			#
			volume_string = sprintf("%s,%d", volume_string, midi_channel_volume[midi_channel_number[i]])

		}

	} # if -- midi_channel_count



	#
	#	output the "run_cs2mtx.sh" script
	#
	print "#" > "run_cs2mtx.sh"
	print "#   run_cs2mtx.sh" >> "run_cs2mtx.sh"
	print "#" >> "run_cs2mtx.sh"

	print "#"
	print "#"
	print "#	Create an MTX score BODY from the sorted score"
	print "#"

	#
	#	$1 will be $FILE_SORTED_SCORE
	#	$2 will be $FULL_PATH_TO_CS2MTX
	#	$3 will be $FULL_PATH_TO_MALIGN
	#	$4 will be $FULL_PATH_TO_MTXHEADER
	#	$5 will be $main_file_stem
	#
	print "cat $1 | awk -f $2 \\"
	print "   bpm=" bpm " \\"
	print "   tracks=" channels_string " \\"
	print "   nshift=" nshift_string " \\"

	#
	#	alias channel arguments
	#
	for (i=1; i<=midi_channel_count; i++) {

		if (i in midi_channel_number) {

			chn = midi_channel_number[i]

			#
			#	call drums "drums" instead of alias10
			#
			if (chn == 10) {
				#
				#	drums
				#
				if (midi_channel_instruments_count[10] >= 1) {
					drums_string = sprintf("drums=%d", midi_channel_instruments[10,1])
					for (j=2; j<=midi_channel_instruments_count[10]; j++) {

						drums_string = sprintf("%s,%d", drums_string, midi_channel_instruments[10,j])

					} # for -- j

					print "   " drums_string " \\"

				} # if -- there are some drum instruments

				continue

			} # if -- there is a drum

			#
			#	alias a channel
			#
			if (midi_channel_instruments_count[chn] >= 1) {
				alias_string = sprintf("alias%d=%d", chn, midi_channel_instruments[chn,1])
				for (j=2; j<=midi_channel_instruments_count[chn]; j++) {

					alias_string = sprintf("%s,%d", alias_string, midi_channel_instruments[chn,j])

				} # for -- j

				print "   " alias_string " \\"

			} # if -- there are some drum instruments




		}
	}

	print "      | awk -f  $3  > midi/body.mtx"


	print "#"
	print "#"
	print "#	Create an MTX score HEADER from the sorted score"
	print "#"
	print "#"
	print "#"
	print "echo \"junk\" | awk -f $4 \\"
	print "   bpm=" bpm " \\"
	print "   ticks=220 name=$5 \\"
	print "   tracks=" channels_string " \\"
	print "   programs=" program_string " \\"
	print "   banks=" bank_string " \\"
	print "   sysex=" sysex_string " \\"
    if (reverb_found)
    {
	    print "   reverbs=" reverb_string " \\"
    }
    if (bankdef_string != "")
    {
        print "   bankdefs=" bankdef_string " \\"
    }
	print "   volumes=" volume_string " > midi/header.mtx"


	print "#"
	print "#	combine the header and body"
	print "#"
	print "cat midi/header.mtx midi/body.mtx > midi/$5.mtx"

	print "#"
	print "#"
	print ""

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












function is_an_integer(field)
{
	if (match(field, /([\+\-])*([0-9])([0-9])*/)) {
		return 1
	}
	return 0
}
#-------------------------------- is_an_integer --------------------------



function exists_midi_channel(chn,     i)
{
	for (i=1; i<=midi_channel_count; i++) {

		if (i in midi_channel_number) {

			if (midi_channel_number[i] == chn) {
				return 1
			} # if -- matches this channel number

		} # if -- this array element exists

	} # for -- midi_channel_count

	return 0
}
#----------------------------- exists_midi_channel -----------------------



function exists_midi_channel_instrument(chn, instr)
{

	if (exists_midi_channel(chn)) {

		if ((chn, instr) in midi_channel_instruments) {
			return 1
		}

	}
	return 0
}
#---------------------- exists_midi_channel_instrument -------------------


