Golang与MIDI编程指南:从入门到实战

Golang与MIDI编程指南:从入门到实战 是否有人成功编写过一个简单的Go语言应用程序,能够在macOS上读取MIDI文件(最好是MIDI鼓文件)并播放它?我知道有gomidi/midi这个包,但似乎没有关于实际执行读取和播放MIDI文件这种看似显而易见操作的有用示例。

这个想法是为了找到一种简单的方法,从命令行或Finder预览鼓MIDI文件,因为macOS中用于MIDI文件的快速查看功能已被移除(我相信是从v10.8开始被弃用)。

4 回复

嗨,马克,

感谢你的回复。我之前真是走投无路了,甚至都在考虑Python的解决方案!你能想象吗?我一定会去看看那个新包的,不过得等到明天了。冰箱里有些啤酒在等着我,它们可不会自己喝掉 ;)

干杯, 卡尔

更多关于Golang与MIDI编程指南:从入门到实战的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,马克。

感谢你的回复!我目前有点忙,但我一定会查看你新增的内容。如果我有任何问题,我一定会使用问题跟踪器!

祝好,

卡尔

你好 Carl,

我是 https://gitlab.com/gomidi/midi 的作者,偶然看到了你的消息(对于问题或请求,使用 issue 跟踪器会更好)。

我写了一个新的包 gitlab.com/gomidi/midi/player 来简化 SMF/MIDI 文件的播放。 请看一下——在 gitlab.com/gomidi/midi/player/example/smfplayer 中还有一个简单的 CLI 播放器作为示例。

谢谢!

是的,可以使用Go在macOS上读取和播放MIDI文件。以下是一个完整的示例,使用gomidi/midi包读取MIDI文件并通过CoreAudio播放:

package main

import (
    "fmt"
    "os"
    "time"
    
    "gitlab.com/gomidi/midi"
    "gitlab.com/gomidi/midi/reader"
    "gitlab.com/gomidi/midi/writer"
    _ "gitlab.com/gomidi/midi/drivers/portmididrv" // macOS音频驱动
)

func main() {
    // 打开MIDI文件
    file, err := os.Open("drums.mid")
    if err != nil {
        panic(err)
    }
    defer file.Close()
    
    // 创建MIDI读取器
    rd := reader.New(
        reader.NoLogger(),
        reader.Each(func(pos *reader.Position, msg midi.Message) {
            // 处理MIDI消息
            handleMIDIMessage(msg)
        }),
    )
    
    // 读取并播放MIDI文件
    err = reader.ReadSMFFile(rd, file)
    if err != nil {
        panic(err)
    }
}

func handleMIDIMessage(msg midi.Message) {
    // 打开MIDI输出端口
    out, err := midi.FindOutPort("IAC Driver Bus 1") // macOS IAC驱动
    if err != nil {
        // 如果没有IAC驱动,使用虚拟端口
        out, err = midi.NewOut("Virtual MIDI Port", 0)
        if err != nil {
            panic(err)
        }
    }
    defer out.Close()
    
    // 创建写入器
    wr := writer.New(out)
    
    // 发送MIDI消息
    writer.Write(wr, msg)
    
    // 根据MIDI消息类型处理时序
    switch v := msg.(type) {
    case midi.NoteOn:
        fmt.Printf("NoteOn: Channel=%d Key=%d Velocity=%d\n", 
            v.Channel(), v.Key(), v.Velocity())
        time.Sleep(time.Duration(v.Duration()) * time.Millisecond)
    case midi.NoteOff:
        fmt.Printf("NoteOff: Channel=%d Key=%d\n", 
            v.Channel(), v.Key())
    }
}

对于更简单的命令行播放器,这里有一个使用portmidi驱动的版本:

package main

import (
    "flag"
    "log"
    "os"
    
    "gitlab.com/gomidi/midi"
    "gitlab.com/gomidi/midi/reader"
    "gitlab.com/gomidi/midi/smf"
    "gitlab.com/gomidi/portmididrv"
)

func main() {
    // 解析命令行参数
    filePath := flag.String("file", "", "MIDI file path")
    flag.Parse()
    
    if *filePath == "" {
        log.Fatal("请指定MIDI文件路径: -file <path>")
    }
    
    // 初始化portmidi驱动
    drv, err := portmididrv.New()
    if err != nil {
        log.Fatal(err)
    }
    defer drv.Close()
    
    // 打开默认MIDI输出
    out, err := drv.OpenOut(0)
    if err != nil {
        log.Fatal(err)
    }
    defer out.Close()
    
    // 打开MIDI文件
    file, err := os.Open(*filePath)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    
    // 读取SMF文件
    smfReader := smf.NewReader(file)
    smf, err := smfReader.Read()
    if err != nil {
        log.Fatal(err)
    }
    
    // 创建播放器
    play := reader.New(
        reader.NoLogger(),
        reader.Writer(out),
        reader.SMF(smf),
        reader.TicksPerQuarterNote(smf.TimeFormat.(smf.MetricTicks).Ticks4th()),
    )
    
    // 播放MIDI
    err = play.Read()
    if err != nil {
        log.Fatal(err)
    }
    
    log.Println("播放完成")
}

安装依赖:

go get gitlab.com/gomidi/midi
go get gitlab.com/gomidi/portmididrv

运行:

go run player.go -file drums.mid

这个实现可以读取标准的MIDI鼓文件,并通过macOS的音频系统播放。对于鼓文件,需要注意MIDI通道10通常用于打击乐(根据GM标准)。

回到顶部