#!/usr/bin/env ruby
# coding: utf-8

#-------------------------------------------------------------------------------
#
#	プレクサー (player + chord-rithym-mixer + midi-enchordr = plexor?)
#

require 'socket'
require './midi'
require './chord'

timebase = 120

socket = UDPSocket.new()
socket.connect('localhost', 47624)

tempo = 120
delta = 60.0 * 4 / tempo
total_quarts = 0
veloc = 96

dsp_mode  = true
suspend   = false
midi_file = nil
wave_file = nil; wave_ch = 'M'; wave_fq = 16000					# --output-mono --sampling-freq=16000

track  = Track.new(timebase)
track.tone(0)

ctrack = Chord_track.new(timebase)
ctrack.chord_pattern()

rtrack = Rhythm_track.new(timebase, 10)
rtrack.rhythm_pattern()

$stdin.each {|l|
	next if(l =~ /^#|^\s*$/)									# コメント/空行

	quarts = 0

	#-----------------------------------------------------------
	#
	#	制御文字列
	#
	dsp_mode = true				if(l =~ /^<DSP ON>/)
	dsp_mode = false			if(l =~ /^<DSP OFF>/)

	suspend = true				if(l =~ /^<STOP>/)
	suspend = false				if(l =~ /^<CONT>/)
	next if(suspend)

	midi_file = "#{$1}.mid"		if(l =~ /^<MIDI\s+([^>]+)>/)
	if(l =~ /^<WAVE\s+([^>]+)>/)
		wave_file = "#{$1}.wav"
		wave_file.gsub!(/:([SM])/, '') and wave_ch = $1
		wave_file.gsub!(/:(\d+)/, '')  and wave_fq = $1.to_i
	end
	break						if(l =~ /^<END>/)				# 強制終了

	next if(l =~ /^</)

	#-----------------------------------------------------------
	#
	#	主旋律
	#
	if(l =~ /^!/)
		socket.send(l, 0) if(dsp_mode)
		l.split(/\s+/).each {|e|
			if(e =~ /^\d[A-G]#?$/)
				printf "        %10.3f: %s\n", quarts, e
				track.note(e, veloc)
			elsif(e =~ /^([A-G]#?)(\d)$/)
				printf "        %10.3f: %s\n", quarts, e
				track.note($2 + $1, veloc)
			elsif(e =~ /^\d+$/)
				quarts += 1.0 / e.to_i
				track.time(timebase * 4 / e.to_i)
			elsif(e =~ /^t(\d+)$/)
				tempo = $1.to_i
				delta = 60.0 * 4 / tempo
			elsif(e =~ /^v(\d+)$/)
				veloc = $1.to_i
			elsif(e =~ /^@(\d+)$/)
				track.tone($1.to_i)
			end
		}
		printf "%10.3f ---------------- %10.3f\n", quarts, total_quarts += quarts

	#-----------------------------------------------------------
	#
	#	伴奏(コード)
	#
	elsif(l =~ /^@/)
		l.split(/\s+/).each {|e|
			if(e =~ /^[A-G].*$/)
				chord = Guiter_chord.new(e)
				pats = chord.sort_patterns
				print "Chord: #{e}\n#{chord.diagram(pats[0])}"
				ctrack.chord(chord.keys(pats[0]))
				rtrack.rhythm
			elsif(e =~ /^\((.+)\)(\d?)$/)
				ctrack.chord_pattern(Hash['pattern', $1, 'length', $2 == '' ? 4 : $2.to_i, 'volume', 80])
			elsif(e =~ /^<(.+)>(\d?)$/)
				rtrack.rhythm_pattern(Hash['pattern', $1, 'length', $2 == '' ? 4 : $2.to_i, 'volume', 80])
			end
		}

	#-----------------------------------------------------------
	#
	#	DSPリアルタイム演奏
	#
	else
		l.split(/\s+/).each {|e|
			if(e =~ /^\d[A-G]#?$/)
				socket.send(e, 0) if(dsp_mode)
				printf "        %10.3f: %s\n", quarts, e
			elsif(e =~ /^\d+$/)
				quarts += 1.0 / e.to_i
				sleep delta / e.to_i
			end
		}
		printf "%10.3f ---------------- %10.3f\n", quarts, total_quarts += quarts
	end
}

track.off
track.close

ctrack.off
ctrack.close

rtrack.off
rtrack.close

midi = Midi.new(timebase)
midi.tempo(tempo)
midi.track(track)
midi.track(ctrack)
midi.track(rtrack)
midi.close

if(midi_file)
	File.exists?('midi') or Dir.mkdir('midi')
	midi.write(midi_file)
	wave_file and system("timidity -Ow#{wave_ch} -s#{wave_fq} #{midi_file} -o #{wave_file}")
	puts('*** Playing...')
	midi.play(midi_file)
end

