当前位置: 首页 > 面试题库 >

读取Java中的MIDI文件

孟安民
2023-03-14
问题内容

我正在尝试将.MID文件读入Java程序,并希望将每个音符/和弦分开,以便在某种UI上显示它们。我在Java中使用Sequencer
API的运气并不好,尝试直接使用MidiFileReader也不适合我。如果有人想看的话,我将附上我在这里使用的代码:

package miditest;
import java.io.File;
import java.io.IOException;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;

public class Main {
    public static void main(String[] args) throws InvalidMidiDataException, IOException, MidiUnavailableException{
    Sequence sequence = MidiSystem.getSequence(new File("test.mid"));

    // Create a sequencer for the sequence
    Sequencer sequencer = MidiSystem.getSequencer();
    sequencer.open();
    sequencer.setSequence(sequence);

    // Start playing
    sequencer.start();
    }
}

问题答案:

我从来没有深入研究过Java对MIDI的支持,而上一次我认真地进行MIDI编程是在Commodore Amiga成为国王的时候。

看来您可能需要做大量的手动工作。这是一个粗略的示例,可解释所有NOTE_ON和NOTE_OFF事件,对于其余事件,它仅显示命令号。

之所以看起来比最初想像的要复杂,是因为MIDI专注于捕获乐器事件(例如,何时按下键盘琴键,何时释放琴键等等),而不是在乐谱符号上。

该代码为每个事件打印出一行,并标明刻度线(这是事件的计时信息),通道,事件类型,音符名称,键,力度

import java.io.File;

import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;

public class Test {
    public static final int NOTE_ON = 0x90;
    public static final int NOTE_OFF = 0x80;
    public static final String[] NOTE_NAMES = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};

    public static void main(String[] args) throws Exception {
        Sequence sequence = MidiSystem.getSequence(new File("test.mid"));

        int trackNumber = 0;
        for (Track track :  sequence.getTracks()) {
            trackNumber++;
            System.out.println("Track " + trackNumber + ": size = " + track.size());
            System.out.println();
            for (int i=0; i < track.size(); i++) { 
                MidiEvent event = track.get(i);
                System.out.print("@" + event.getTick() + " ");
                MidiMessage message = event.getMessage();
                if (message instanceof ShortMessage) {
                    ShortMessage sm = (ShortMessage) message;
                    System.out.print("Channel: " + sm.getChannel() + " ");
                    if (sm.getCommand() == NOTE_ON) {
                        int key = sm.getData1();
                        int octave = (key / 12)-1;
                        int note = key % 12;
                        String noteName = NOTE_NAMES[note];
                        int velocity = sm.getData2();
                        System.out.println("Note on, " + noteName + octave + " key=" + key + " velocity: " + velocity);
                    } else if (sm.getCommand() == NOTE_OFF) {
                        int key = sm.getData1();
                        int octave = (key / 12)-1;
                        int note = key % 12;
                        String noteName = NOTE_NAMES[note];
                        int velocity = sm.getData2();
                        System.out.println("Note off, " + noteName + octave + " key=" + key + " velocity: " + velocity);
                    } else {
                        System.out.println("Command:" + sm.getCommand());
                    }
                } else {
                    System.out.println("Other message: " + message.getClass());
                }
            }

            System.out.println();
        }

    }
}

例如,我躺在这里的毛皮elise.mid在开始时会产生类似以下的内容:

@0 Channel: 1 Note on, E5 key=76 velocity: 127
@192 Channel: 1 Note off, E5 key=76 velocity: 64
@192 Channel: 1 Note on, D#5 key=75 velocity: 127
@384 Channel: 1 Note off, D#5 key=75 velocity: 64
@384 Channel: 1 Note on, E5 key=76 velocity: 127
@576 Channel: 1 Note off, E5 key=76 velocity: 64
@576 Channel: 1 Note on, D#5 key=75 velocity: 127
@768 Channel: 1 Note off, D#5 key=75 velocity: 64
@768 Channel: 1 Note on, E5 key=76 velocity: 127
@960 Channel: 1 Note off, E5 key=76 velocity: 64
@960 Channel: 1 Note on, B4 key=71 velocity: 127
@1152 Channel: 1 Note off, B4 key=71 velocity: 64
@1152 Channel: 1 Note on, D5 key=74 velocity: 127
@1344 Channel: 1 Note off, D5 key=74 velocity: 64
@1344 Channel: 1 Note on, C5 key=72 velocity: 127
@1536 Channel: 1 Note off, C5 key=72 velocity: 64
@1536 Channel: 1 Note on, A4 key=69 velocity: 127
@1920 Channel: 1 Note off, A4 key=69 velocity: 64

更新:通道是MIDI规范的16个通道。

http://www.midi.org/techspecs/gm.php

通道:支持所有16个MIDI通道。每个通道可以播放可变数量的声音(复音)。每个通道可以演奏不同的乐器(声音/音色/音色)。基于键的打击乐始终在MIDI通道10上。

速度是用于控制声音的属性之一。例如,在键盘上捕获MIDI数据就是您按下琴键的力量。通常,它控制声音的音量。详情请参阅这里:http :
//audio.tutsplus.com/tutorials/production/7-ways-to-use-and-edit-midi-
velocity/



 类似资料:
  • 问题内容: 我有一个文本文件。我想从一行到另一行检索内容。例如,文件可以是200K行。我想从第78行到第2735行读取内容。由于文件可能很大,所以我不想将整个内容读取到内存中。 问题答案: 这是一个可能的解决方案的开始:

  • 问题内容: 我需要在Java应用程序中读取Excel 2007 XLSX文件。有谁知道一个很好的API来完成这项任务? 问题答案: AFAIK还没有可用的xlsx库。但是有些旧的xls: 一个库是jxls,它内部使用已经提到的POI。 其他2个链接:处理Excel文件,用于读写Excel XLS文档文件的Java库 。

  • 问题内容: 我需要非常了解Java和内存问题的人的建议。我有一个大文件(大约1.5GB),我需要将此文件切成许多小文件(例如100个小文件)。 我通常知道如何做到这一点(使用),但是我想知道你是否对内存有任何建议,或者提示如何更快地做到这一点。 我的文件包含文本,它不是二进制文件,每行大约有20个字符。 问题答案: 首先,如果你的文件包含二进制数据,则使用将是一个大错误(因为你会将数据转换为Str

  • 我现在找了一段时间,想做什么都找不到答案。 我想播放一个midi文件,并在播放时在屏幕上显示音符。当一个音符停止播放时,它应该从屏幕上消失。 我可以用音序器播放midi,但不知道如何让音符播放,或者何时停止播放音符。 我研究过ControllerEventListeners和MetaEventListeners,但仍然不知道如何做到这一点。 任何帮助都将不胜感激。

  • 问题内容: 我会尽量保持清楚,但如果我的问题不完美,请原谅我。我有一个包含多行数据的txt文件。例: 123拉尔夫·玻色20000 200 1 2 256 ed shane 30000 100 2 4 … 我需要按顺序读取每一行,并将其传递回单独类中的方法进行处理。我知道如何通过使用StringTokenizer将每一行分解为元素。 但是,我不确定如何一次读取一行,将元素传递回另一类,然后在完成处

  • 我的项目中有这样一段代码: 没有错误,应用程序运行正常,但是变量中从来没有任何文本,我确信txt文件中有文本! 我已经尝试过不同的方法来读取文本文件(使用BufferedReader、Scanner、FileInputStream和FileReader),但都不起作用。 另外,我几乎可以肯定问题不在变量中,因为我尝试通过代码(使用运行时)打开文件,它正常打开了正确的文件。 好的,我尝试添加,但是仍