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

#-------------------------------------------------------------------------------
#
#	妖音リナ Version 0.001
#

timebase = 120

tempo = 120
total_quarts = 0
veloc = 96
length = 1.0

suspend   = false
wave_file = nil
vocal_file = nil

#-------------------------------------------------------------------------------
#
#	ボーカルクラス
#
class Vocal < Array

	@@KEYS = Hash.new; n = -1
	['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'].each {|k|
		@@KEYS[k] = (n += 1)
	}

	def initialize(timebase = 240, ch = nil)
		@timebase = timebase									# タイムベース
		@tempo = 120
		@delta = 0.0
		@bpitch = 72
		@vfreq = 16000
		File.exists?('voices') or Dir.mkdir('voices')
		@voices = Dir.glob('voices/voice_*.wav')
	end

	def tempo(bpm)
		@tempo = bpm
	end

	def pitch(p)												# 声の基本高さ
		@bpitch = p
	end

	def time(d)
		@delta += d
	end

	def tone(t)													# 声色変更(未実装)
#		self.push(0xc0 + @ch, t)
	end

	def note(k, v = 96)
		note0(48 + 12 * k[0, 1].to_i + @@KEYS[k[1, 9]], v)
#		note0(12 + 12 * k[0, 1].to_i + @@KEYS[k[1, 9]], v)
	end

	def note0(n, v = 96)
		@pitch = (n - @bpitch) * 100							# 声の高さ調整
	end

	def freq(f)
		@vfreq = f
	end

	def voice(v, d = 1.0)
		vfn = 'voices/voice_%s_%d_%.5f.wav' % [v, @pitch, d]
		File.exists?(vfn) or system('echo "%s" | text2wave -f %d | sox -t wav - %s pitch %d stretch %.5f silence 1 5 2%%' % [v, @vfreq, vfn, @pitch, d])
		self << 'sox %s -p pad %.5f' % [vfn, @delta / @timebase * 60 / @tempo]
	end

	def off
	end

	def close
	end

	def write(vocal_file, wave_file)
		command = "sox -M #{wave_file} "
		self.each {|v|
			command << '"| %s" ' % v
		}
		command << "#{vocal_file} remix -i"
		system(command)
	end

	def play(vocal_file)
		system("play #{vocal_file}")
	end
end

#-------------------------------------------------------------------------------
#
#	メイン
#
vocal = Vocal.new(timebase)
vocal.tone(0)

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

	quarts = 0

	#-----------------------------------------------------------
	#
	#	制御文字列
	#
	suspend = true				if(l =~ /^<STOP>/)
	suspend = false				if(l =~ /^<CONT>/)
	next if(suspend)

	if(l =~ /^<WAVE\s+([^>]+)>/)
		wave_file = "#{$1}.wav"	
		wave_file.gsub!(/:([SM])/, '') #nd vocal.channel($1)
		wave_file.gsub!(/:(\d+)/, '')  and vocal.freq($1.to_i)
	end
	vocal_file = "#{$1}.wav"	if(l =~ /^<VOCAL\s+([^>]+)>/)
	break						if(l =~ /^<END>/)				# 強制終了

	next if(l =~ /^</)

	#-----------------------------------------------------------
	#
	#	主旋律
	#
	if(l =~ /^!/)
		l.split(/\s+/).each {|e|
			if(e =~ /^\d[A-G]#?$/)
				printf "        %10.3f: %-4s", quarts, e
				vocal.note(e, veloc)
			elsif(e =~ /^([A-G]#?)(\d)$/)
				printf "        %10.3f: %-4s", quarts, e
				vocal.note($2 + $1, veloc)
			elsif(e =~ /^\[([-\w]+):?([\d\.])*\]$/)
				printf "[%s:%s]\n", $1, $2
				vocal.voice($1, $2 ? $2.to_f : length)
			elsif(e =~ /^\d+$/)
				quarts += 1.0 / e.to_i
				vocal.time(timebase * 4 / e.to_i)
			elsif(e =~ /^t(\d+)$/)
				vocal.tempo($1.to_i)
			elsif(e =~ /^v(\d+)$/)
				veloc = $1.to_i
			elsif(e =~ /^p(\d+)$/)
				vocal.pitch($1.to_i)
			elsif(e =~ /^l([\d\.]+)$/)
				length = $1.to_f
			end
		}
		printf "%10.3f ---------------- %10.3f\n", quarts, total_quarts += quarts
	end
}

vocal.off
vocal.close

vocal.write(vocal_file, wave_file)
puts('*** Playing...')
vocal.play(vocal_file)

