#!/usr/bin/python
"""A library to manipulate music and note data to be burned to a ROM chip

Fun stuff, eh?
"""

from copy import deepcopy

NUMLIGHTS = 14

wav_bytes = []
wav_framerate = None
notes = [set(), set(), set(), set()]

def set_waveform(bytes, framerate):
	"""Set the waveform data

	Sets the waveform data to the specified array of bytes at the
	specified sampling frequency
	"""
	global wav_bytes, wav_framerate
	wav_bytes = deepcopy(bytes)
	wav_framerate = framerate

def import_waveform(wav_file):
	"""Imports the waveform data from a Wave_read object

	Imports the waveform data and the framerate
	"""
	global wav_bytes, wav_framerate
	wav_framerate = wav_file.getframerate()
	pos = wav_file.tell()
	wav_file.setpos(0)
	wav_bytes = wav_file.readframes(wav_file.getnframes())
	wav_file.setpos(pos)

def get_waveform():
	"""Returns the current waveform data as an array of bytes"""

	return deepcopy(wav_bytes)

def get_waverate():
	"""Returns the current waveform framerate"""

	return  deepcopy(wav_framerate)

def set_notes(newnotes):
	"""Sets the sequence of notes
	
	The argument should be a sequence of four sequences, each corresponding
	to one button in the game
	"""
	global notes
	for i in range(len(notes)):
		notes[i] = set(newnotes[i])

def add_notes(newnotes, button=None):
	"""Add new notes to the sequence

	Can be called with either one or two arguments. The one-argument
	versionacts like set_notes() except that the current sequence of notes
	is augmented rather than replaced. The two-argument version takes as
	the first argument a sequence of notes for the button specified by the
	second argument
	"""
	global notes
	if button == None:
		for i in range(len(newnotes)):
			notes[i].update(newnotes[i])
	else:
		notes[button].update(newnotes)

def get_notes():
	"""Returns the current notes

	Returns notes in the format wanted by set_notes(); here, the sequence
	type is a list.
	"""
	listnotes = [[], [], [], []]
	for i in range(len(notes)):
		listnotes[i] = list(notes[i])
		listnotes[i].sort()
	return listnotes

def export(name, bpm=120, scrollrate=4, outrate=11025, split=1):
	"""Export the current data

	Dumps the notes and waveform to either one or two binary 
	files, ready to be burned to ROM.

	bpm -- beats per minute -- not actually used

	scrollrate -- how many times the picture changes per second (how fast
		the "arrows" are scrolling up).
	
	outrate -- rows per second

	split -- two ROMs?
	"""
	mynotes = get_notes()
	noteframes = []
	lightframes = len(wav_bytes) / wav_framerate * scrollrate
	print len(wav_bytes), wav_framerate, scrollrate
	print "splitting column frames"
	for buttonnotes in mynotes:
		buttonframes = []
		for i in range(lightframes):
			buttonframe = []
			for n in range(NUMLIGHTS):
				buttonframe.append(not (i + NUMLIGHTS - n in buttonnotes))
			buttonframes.append(buttonframe)
		noteframes.append(buttonframes)
	print len(noteframes[0])
	#print "converting to clock cycles"
	for framenum in range(len(noteframes[0])):
		#print "BEGIN FRAME", framenum
		for row in range(len(noteframes[0][0])):
			#print row,
			for col in range(len(noteframes)):
				pass
				#print int(noteframes[col][framenum][row]),
			#print
		#print "END FRAME"
		#print
		#raw_input()
	lightrows = []
	print "converting to clock cycles and rows"
	for i in range(len(wav_bytes)):
		t = float(i) / wav_framerate
		num = t * scrollrate
		framenum = int(num)
		rownum = i % 7
		row = []
		#print t, framenum, rownum,
		for c in range(len(noteframes)):
			#print int(noteframes[c][framenum][rownum]),
			row.append(int(noteframes[c][framenum][rownum]))
		for c in range(len(noteframes)):
			#print int(noteframes[c][framenum][rownum + 7]),
			row.append(int(noteframes[c][framenum][rownum + 7]))
		#print
		lightrows.append(row)
		#raw_input()
	notesfile = open(name+'.notes.hex', 'w')
	print "writing note output"
	for row in lightrows:
		byte = 0
		for bit in range(len(row)):
			byte |= row[bit] << bit
		notesfile.write(chr(byte))
	notesfile.close()
	musicfile = open(name+'.music.hex', 'w')
	print "writing music output"
	for byte in wav_bytes:
		if type(byte) == type(1):
			musicfile.write(chr(byte))
		else:
			musicfile.write(byte)
	musicfile.close()
	print "done"

