如何使用 MIPS 读取 MIDI 文件?
How do I read MIDI files using MIPS?
根据所有给出的建议,我尝试制作一个播放简单钢琴音阶的程序,到目前为止我得到了这个:
.data
pitchC: .byte 60
pitchD: .byte 62
pitchE: .byte 64
pitchF: .byte 65
pitchG: .byte 67
pitchA: .byte 69
pitchB: .byte 71
instrument: .byte 14
volume: .byte 127
duration: .byte 100
.text
main:
addi $t0, $zero, 0
while:
bgt $t0, 7, exit
li $v0, 31
la $a0, pitchA
la $a1, duration
la $a2, instrument
la $a3, volume
syscall
addi $t0, $t0, 1
j while
exit:
li $v0, 10
syscall
它正在播放一个音符,但是如果我尝试在第一个音符之后添加另一个具有不同音高的音符来播放它不会播放,并且如果我更改任何值如 volume/instrument/durantion 它会'影响声音。可能是什么原因造成的?
一切都在系统调用中。使用 #13 服务打开文件,使用 #14 读取文件,使用 #31(异步)或 #33(同步)播放 MIDI 音符。不过,在解析 MIDI 文件格式时,您只能靠自己了。 MIDI 系统调用采用音调、持续时间、音量和乐器。 MIDI 文件对这些进行编码。 The spec is available.
您可以使用系统调用#30(时间)and/or#32(睡眠)来控制音符时间。
Syscall reference with samples is also available.
不过,如果您想只弹奏基本音阶,就像您写的一样,您不需要读取任何 MIDI 文件。只需按间距在循环中使用系统调用 #33。对于 C 大调音阶,音符编号(对应于系统调用中的 $a0
)不会连续;他们会去 60,62,64,65,67,69,71,72。所以你需要一个条件增量,或者一组音符编号。切换到小音阶对喜欢音乐的人来说是一种练习 :)
编辑回复:按键反应。这是可能的,但必须借助 MARS 的可选工具。当 "Keyboard and display MMIO Simulator" 工具 运行ning 并连接到执行(单击 "Connect to MIPS")时,有一个神奇的内存位置 0xffff0000。如果您读取该地址处的字,并且设置了最低位,则意味着刚刚按下了一个键。阅读的行为本身就清除了这一点;它不是传统的内存变量。
如果您 运行 没有键盘工具,则不会检测到 MARS "Run I/O" 区域中的击键(也不会生成中断)。该区域在逻辑上是控制台,而不是键盘。 "read character" 系统调用(#14)会阻塞执行,直到输入一个字符;这不适合在观察击键的同时执行某些操作(例如播放音乐)的程序。
为了完整起见,对于键盘工具,您还可以使用中断处理程序来捕获按键。您可以使用中断中的系统调用,因此如果您希望按键终止程序,这就是您的处理程序应该做的 - 调用 exit (#10) 系统调用。
要连接键盘中断,您必须编写一个中断处理程序,并通过声明内核代码段将其放置在固定地址 0x80000180 中:.ktext 0x80000180
。然后,在程序开头的某处,您必须通过将位于 0xffff0000 的接收器控制寄存器中的第 1 位设置为 1 来启用键盘中断。
在正确编写的处理程序中,您必须检索并询问中断原因寄存器(协处理器 0 寄存器 $13)以区分键盘中断与其他中断、异常和陷阱。然而,在通常为 MARS 编写的那种程序中(即学习练习),键盘中断可能是唯一会遇到的。在撰写本文时,键盘工具是 MARS 上唯一可能的中断源(键盘和显示器),默认情况下禁用显示中断。如果您不明确使用陷阱命令,陷阱也不会发生。至于例外,无论如何都是坏消息,可能也应该作为退出条件。异常后的优雅恢复和继续是可能的,但它是不太可能出现在 MARS 程序中的深奥魔法。
我在这里说的是,一个除了立即退出什么也不做的中断处理程序可能正是您需要的所有处理。
在处理程序中,使用$k0/$k1寄存器来存储中间值,它们是专门为内核保留的。
根据所有给出的建议,我尝试制作一个播放简单钢琴音阶的程序,到目前为止我得到了这个:
.data
pitchC: .byte 60
pitchD: .byte 62
pitchE: .byte 64
pitchF: .byte 65
pitchG: .byte 67
pitchA: .byte 69
pitchB: .byte 71
instrument: .byte 14
volume: .byte 127
duration: .byte 100
.text
main:
addi $t0, $zero, 0
while:
bgt $t0, 7, exit
li $v0, 31
la $a0, pitchA
la $a1, duration
la $a2, instrument
la $a3, volume
syscall
addi $t0, $t0, 1
j while
exit:
li $v0, 10
syscall
它正在播放一个音符,但是如果我尝试在第一个音符之后添加另一个具有不同音高的音符来播放它不会播放,并且如果我更改任何值如 volume/instrument/durantion 它会'影响声音。可能是什么原因造成的?
一切都在系统调用中。使用 #13 服务打开文件,使用 #14 读取文件,使用 #31(异步)或 #33(同步)播放 MIDI 音符。不过,在解析 MIDI 文件格式时,您只能靠自己了。 MIDI 系统调用采用音调、持续时间、音量和乐器。 MIDI 文件对这些进行编码。 The spec is available.
您可以使用系统调用#30(时间)and/or#32(睡眠)来控制音符时间。
Syscall reference with samples is also available.
不过,如果您想只弹奏基本音阶,就像您写的一样,您不需要读取任何 MIDI 文件。只需按间距在循环中使用系统调用 #33。对于 C 大调音阶,音符编号(对应于系统调用中的 $a0
)不会连续;他们会去 60,62,64,65,67,69,71,72。所以你需要一个条件增量,或者一组音符编号。切换到小音阶对喜欢音乐的人来说是一种练习 :)
编辑回复:按键反应。这是可能的,但必须借助 MARS 的可选工具。当 "Keyboard and display MMIO Simulator" 工具 运行ning 并连接到执行(单击 "Connect to MIPS")时,有一个神奇的内存位置 0xffff0000。如果您读取该地址处的字,并且设置了最低位,则意味着刚刚按下了一个键。阅读的行为本身就清除了这一点;它不是传统的内存变量。
如果您 运行 没有键盘工具,则不会检测到 MARS "Run I/O" 区域中的击键(也不会生成中断)。该区域在逻辑上是控制台,而不是键盘。 "read character" 系统调用(#14)会阻塞执行,直到输入一个字符;这不适合在观察击键的同时执行某些操作(例如播放音乐)的程序。
为了完整起见,对于键盘工具,您还可以使用中断处理程序来捕获按键。您可以使用中断中的系统调用,因此如果您希望按键终止程序,这就是您的处理程序应该做的 - 调用 exit (#10) 系统调用。
要连接键盘中断,您必须编写一个中断处理程序,并通过声明内核代码段将其放置在固定地址 0x80000180 中:.ktext 0x80000180
。然后,在程序开头的某处,您必须通过将位于 0xffff0000 的接收器控制寄存器中的第 1 位设置为 1 来启用键盘中断。
在正确编写的处理程序中,您必须检索并询问中断原因寄存器(协处理器 0 寄存器 $13)以区分键盘中断与其他中断、异常和陷阱。然而,在通常为 MARS 编写的那种程序中(即学习练习),键盘中断可能是唯一会遇到的。在撰写本文时,键盘工具是 MARS 上唯一可能的中断源(键盘和显示器),默认情况下禁用显示中断。如果您不明确使用陷阱命令,陷阱也不会发生。至于例外,无论如何都是坏消息,可能也应该作为退出条件。异常后的优雅恢复和继续是可能的,但它是不太可能出现在 MARS 程序中的深奥魔法。
我在这里说的是,一个除了立即退出什么也不做的中断处理程序可能正是您需要的所有处理。
在处理程序中,使用$k0/$k1寄存器来存储中间值,它们是专门为内核保留的。