MIDI音乐编程那些事儿

本文介绍了在Windows系统中通过win32 API函数实现MIDI音乐播放的方法,包括获取MIDI函数、理解参数和返回值,以及如何使用MIDI短消息函数播放音乐。详细讲解了MidiOutOpen、MidiOutShortMsg和MidiOutClose等函数的使用,并提供了Delphi和C++ Builder环境中的代码示例。同时,解析了MidiOutShortMsg的参数格式和MIDI消息的构造方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

新冠疫情期间没事儿,玩起了音乐和电脑。因为正在利用老旧电子琴学弹 “我爱你中国” (简谱的眼睛),手上较为完整的曲谱却是五线谱,无奈!把它翻译成简谱。本来想通过电脑帮我把输入的五线谱转换成指定大调的简谱(转成不同调的简谱,这do re me 就不一样了,手工转换很烧脑的),这不需要MIDI的。可是,后来想让电脑在每转换好一个音后立刻把音发出来,然后就有了下面的文章。

一、Windows系统的 win32 API MIDI函数

在Windows系统中要演奏MIDI音乐,可以通过API函数进行。我们要做的只是调用它们,并通过它们发送MIDI消息给Windows,其余的事都由Windows在后台完成。为了要调用API函数,首先要做的就是获取这些MIDI函数,并了解它们的参数要求及其返回值。基本的MIDI函数有3个:midiOutOpen 、MidiOutShortMsg、MidiOutClose,分别用来打开MIDI设备、操作MIDI设备和关闭MIDI设备。

1、win32 API MIDI函数的获取

Windows的MIDI函数在系统动态链接库winmm.dll中。在Borland C++ builder环境中代码如下:
注:下面的代码结合了多位作者的代码示例才启发了我,并且在时间上也持续了2-3天,特别是函数的转换上。所以这里无法给出具体作者,如有作者向我指出,我会加上其引用。

//在获取函数地址前,先说明其在相应开发环境中的函数原型
int __stdcall (*MidiOutOpen)(int &hMidiOut, int uDeviceID,int dwCallBack,int dwInstance,int dwFlags);
int __stdcall (*MidiOutClose)(int hMidiOut );
int __stdcall (*MidiOutShortMsg)(int hMidiOut, int dwMsg);


HINSTANCE h=NULL;
int MidiOut=0;
void __fastcall TForm1::FormCreate(TObject *Sender)
{
   
     h=::LoadLibrary("winmm.dll");	//载入动态链接库,LoadLibrary函数会自动定位其所在目录
     if(NULL != h) 
     {
   
          MidiOutOpen= (int __stdcall (*)(int &, int,int,int,int)) GetProcAddress(h,"midiOutOpen");
          
### 关于MIDI音乐编程的知识与示例 #### MIDI文件解析与可视化 通过`music21`库可以轻松实现对MIDI文件的操作,例如将其转换为可视化的形式。以下是具体的代码示例: ```python from music21 import converter, midi # 加载并解析MIDI文件 midi_file = converter.parse('path/to/your/midifile.mid') # 将MIDI文件转化为流对象以便进一步操作 midi_stream = midi.translate.midiFileToStream(midi_file) # 显示MIDI文件的内容(通常会弹出一个窗口展示乐谱) midi_stream.show('midi') ``` 上述代码展示了如何加载MIDI文件,并利用`show()`方法对其进行可视化[^1]。 --- #### 获取MIDI中的元事件 尽管MIDI规范支持某些类型的元事件(如歌词或文本),但在实际应用中,这些事件可能被忽略或者需要特殊处理。例如,在Java MIDI API中可以通过特定机制捕获这些元事件,而其他工具(如FluidSynth)则可能会丢弃它们[^2]。 如果希望提取MIDI文件中的元数据,可以尝试如下方式: ```python from music21 import metadata # 提取MIDI文件的元数据 meta_data = metadata.Metadata() meta_data.addTitle("Example Title") meta_data.addComposer("Unknown Composer") print(meta_data.title) print(meta_data.composer) ``` 此代码片段演示了如何向MIDI文件添加或读取元数据信息。 --- #### 构建训练集用于AI模型开发 为了构建基于MIDI文件的人工智能模型,首先需要准备足够的高质量训练数据。这一步骤涉及从互联网上下载大量MIDI文件或将现有音频素材转录为MIDI格式[^3]。 假设已经拥有一批MIDI文件作为输入源,下一步便是预处理这些数据以适应机器学习框架的需求。以下是一个简单的脚本,用来统计每首曲子中使用的唯一音符数量: ```python from music21 import corpus def count_unique_notes(midifile_path): score = converter.parse(midifile_path) notes = set() for element in score.flat.notesAndRests: if 'Note' in element.classes: notes.add(element.nameWithOctave) return len(notes), notes unique_count, note_set = count_unique_notes('example.mid') print(f"Unique Notes Count: {unique_count}") print(note_set) ``` 该函数接收单个MIDI路径参数,并返回其中包含的不同音符总数及其集合列表。 --- #### 使用PyGame播放MIDI音符 除了分析和生成MIDI内容之外,有时还需要实时播放声音效果。借助第三方库——比如PyGame——能够快速达成这一目标[^4]。 下面是一段基础示例,它定义了一个基本的功能来触发指定频率的声音输出: ```python import pygame pygame.mixer.init() # 初始化混响引擎 frequency = 440 # A4标准音高(Hz) duration_ms = 500 # 声波持续时间(ms) sound_array = numpy.sin(2 * numpy.pi * numpy.arange(duration_ms * 44100 / 1000.) * frequency / 44100.) audio_signal = numpy.int16(sound_array * (2 ** 15 - 1)) play_obj = pygame.mixer.Sound(audio_signal).play(-1) # 循环播放直到停止命令发出 input("Press Enter to Stop...") play_obj.stop() ``` 注意这里仅提供理论上的思路指导;具体实现细节取决于项目需求和个人偏好。 --- #### 蓝牙低功耗技术(BLE)扩展可能性 随着物联网(IoT)领域的发展壮大,越来越多硬件平台开始集成无线通信能力。特别是针对便携式电子乐器而言,采用Bluetooth Low Energy协议栈传输控制信号变得越来越普遍[^5]。 这意味着开发者不仅可以专注于软件层面的设计优化,还可以探索更多跨平台交互场景的可能性! ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值