namespace eval vgm {
	variable active false
	variable opl4wave_register
	variable opl4fm_register
	variable opl4bank_Register
	variable music_data
	variable file_name
	variable watchpoint_opl4wave_address
	variable watchpoint_opl4wave_data
	variable watchpoint_opl4fm1_address
	variable watchpoint_opl4fm_data
	variable watchpoint_opl4fm2_address
	variable watchpoint_opl4fm_data_
	variable watchpoint_isr
	variable v
	variable bank7e
	variable bankc4
	variable bankc6
	variable LastBank
	variable LastBankWave

	proc vgm_startrec {{filename "music.vgm"}} {
		variable active
		variable opl4wave_register
		variable opl4fm_register
		variable opl4bank_Register
		variable music_data
		variable file_name
		variable watchpoint_opl4wave_address
		variable watchpoint_opl4wave_data
		variable watchpoint_opl4fm1_address
		variable watchpoint_opl4fm_data
		variable watchpoint_opl4fm2_address
		variable watchpoint_opl4fm_data_
		variable watchpoint_isr
		variable v
		variable bank7e
		variable bankc4
		variable bankc6
		variable LastBank
		variable LastBankWave

		if {$active} {
			error "Already recording."
		}

		set v 0

		while {$v < 256} {

			set bank7e($v) -1
			set bankc4($v) -1
			set bankc6($v) -1

			set v [expr $v + 1]
		}

		set active true
		set opl4wave_register -1
		set opl4fm_register -1
		set opl4bank_Register -1
		set LastBank -1
		set LastBankWave -1
		set music_data ""
		set file_name $filename

		set watchpoint_opl4wave_address [debug set_watchpoint write_io 0x7E {} {vgm::write_opl4wave_address}]
		set watchpoint_opl4wave_data [debug set_watchpoint write_io 0x7F {} {vgm::write_opl4wave_data}]
		set watchpoint_opl4fm1_address [debug set_watchpoint write_io 0xC4 {} {vgm::write_opl4fm1_address}]
		set watchpoint_opl4fm_data [debug set_watchpoint write_io 0xC5 {} {vgm::write_opl4fm_data}]
		set watchpoint_opl4fm2_address [debug set_watchpoint write_io 0xC6 {} {vgm::write_opl4fm2_address}]
		set watchpoint_opl4fm_data_ [debug set_watchpoint write_io 0xC7 {} {vgm::write_opl4fm_data}]
		
		set watchpoint_isr [debug set_watchpoint read_mem 0xFD9F {} {vgm::update_frametime}]

		puts "Recording started"
	}

	proc write_opl4wave_address {} {
		variable opl4wave_register
		set opl4wave_register $::wp_last_value
	}

	proc write_opl4wave_data {} {
		variable opl4wave_register
		variable music_data
		variable bank7e
		variable LastBank
		variable LastBankWave

		set LastBank -1

		if {$opl4wave_register == -1} {
			if {$LastBankWave != 0x7E} {
				set LastBankWave 0x7E
				append music_data [format %c 0xFB]
			}
			append music_data [format %c%c 0xFC $::wp_last_value]
		} else {
			if {$bank7e($opl4wave_register) != $::wp_last_value || $opl4wave_register < 0x20} {
				set bank7e($opl4wave_register) $::wp_last_value
				if {$LastBankWave != 0x7E} {
					set LastBankWave 0x7E
					append music_data [format %c 0xFB]
				}
				append music_data [format %c%c $opl4wave_register $::wp_last_value]
				set opl4wave_register -1
			}
		}

	}

	proc write_opl4fm1_address {} {
		variable opl4fm_register
		variable opl4bank_Register
		set opl4bank_Register 0xC4
		set opl4fm_register $::wp_last_value
	}

	proc write_opl4fm_data {} {
		variable opl4fm_register
		variable opl4bank_Register
		variable music_data
		variable bankc4
		variable bankc6
		variable LastBank
		variable LastBankWave

		set LastBankWave -1

		if {$opl4fm_register == -1} {
			if {$LastBank != $opl4bank_Register} {
				set LastBank $opl4bank_Register
				if {$opl4bank_Register == 0xC4} {
					append music_data [format %c 0xFD]
				} else {
					append music_data [format %c 0xFE]
				}
			}
			append music_data [format %c%c 0xFC $::wp_last_value]
		} else {
			if {$opl4bank_Register == 0xC4} {
				if {$bankc4($opl4fm_register) != $::wp_last_value} {
					set bankc4($opl4fm_register) $::wp_last_value
					if {$LastBank != $opl4bank_Register} {
						set LastBank $opl4bank_Register
						if {$opl4bank_Register == 0xC4} {
							append music_data [format %c 0xFD]
						} else {
							append music_data [format %c 0xFE]
						}
					}
					append music_data [format %c%c $opl4fm_register $::wp_last_value]
					set opl4fm_register -1
				}
			} else {
				if {$bankc6($opl4fm_register) != $::wp_last_value} {
					set bankc6($opl4fm_register) $::wp_last_value
					if {$LastBank != $opl4bank_Register} {
						set LastBank $opl4bank_Register
						if {$opl4bank_Register == 0xC4} {
							append music_data [format %c 0xFD]
						} else {
							append music_data [format %c 0xFE]
						}
					}
					append music_data [format %c%c $opl4fm_register $::wp_last_value]
					set opl4fm_register -1
				}
			}
		}
	}

	proc write_opl4fm2_address {} {
		variable opl4fm_register
		variable opl4bank_Register
		set opl4bank_Register 0xC6
		set opl4fm_register $::wp_last_value
	}


	proc update_frametime {} {
		variable music_data
		append music_data [format %c 0xFF]
	}

	proc vgm_stoprec {} {
		variable active
		variable music_data
		variable file_name
		variable watchpoint_opl4wave_address
		variable watchpoint_opl4wave_data
		variable watchpoint_opl4fm1_address
		variable watchpoint_opl4fm_data
		variable watchpoint_opl4fm2_address
		variable watchpoint_opl4fm_data_
		variable watchpoint_isr

		if {!$active} {
			error "Not recording."
		}

		debug remove_watchpoint $watchpoint_opl4wave_address
		debug remove_watchpoint $watchpoint_opl4wave_data
		debug remove_watchpoint $watchpoint_opl4fm1_address
		debug remove_watchpoint $watchpoint_opl4fm_data
		debug remove_watchpoint $watchpoint_opl4fm2_address
		debug remove_watchpoint $watchpoint_opl4fm_data_

		debug remove_watchpoint $watchpoint_isr

		append music_data [format %c 0xFA]

		set file_handle [open $file_name "w"]
		fconfigure $file_handle -encoding binary -translation binary
		puts -nonewline $file_handle $music_data
		close $file_handle

		set music_data ""

		set active false

		puts "Recording stopped"
	}

	namespace export vgm_startrec
	namespace export vgm_stoprec
}

namespace import vgm::*