Java MIDI Track 播放重复音符

发布于 2024-10-11 16:53:38 字数 2531 浏览 3 评论 0原文

我正在创建一个应用程序,用户可以在其中将多个 MIDI 音符添加到集合中,从这里他们可以按“播放”按钮,应用程序将迭代每个音符并通过扬声器播放它们。

我创建了一个 MIDIMessage 类,它保存用户选择添加到列表中的音符的详细信息,存储的详细信息是音高、速度、延迟和通道。

每条消息都保存到类型为 MIDIMessage 的 ArrayList 中。

然后,我继续将集合的迭代器附加到迭代器对象并播放声音,同时集合中仍然有一个元素尚未使用。

由于某种原因,即使我只向集合中添加一个音符,总会有两个音符以完全相同的音高、长度和速度演奏。

此外,无论集合中有多少个音符,每个音符都会同时播放,我认为它们之间会有某种延迟。

以下是我目前使用的代码:

MIDIMessage:

package javatest;

public class MIDIMessage
{
    private int pitch;
    private int velocity;
    private int channel;

    public MIDIMessage(int p, int v, int c)
    {
        pitch = p;
        velocity = v;
        channel = c;
    }

    public int GetPitch()
    {
        return this.pitch;
    }

    public int GetVelocity()
    {
        return this.velocity;
    }

    public int GetChannel()
    {
        return this.channel;
    }
}

向集合添加音符:

public void AddToList()
    {
        int channel = jComboBoxChannels.getSelectedIndex();
        int pitch = jComboBoxPitch.getSelectedIndex();
        int velocity = ((Integer)jSpinnerVelocity.getValue());    
        collection.add(new MIDIMessage(pitch,velocity,channel));
    }

播放音符:

try
        {
            jButton1.setEnabled(false);
            Sequencer sequencer = MidiSystem.getSequencer();
            sequencer.open();
            Sequence sequence = new Sequence(Sequence.PPQ,1);
            Track track = sequence.createTrack();

            Iterator itr = collection.iterator();
            int i = 0;

            while(itr.hasNext())
            {
                MIDIMessage msg = (MIDIMessage)itr.next();

                ShortMessage noteOnMsg = new ShortMessage();
                //Signal/Channel/Pitch/Velocity
                noteOnMsg.setMessage(ShortMessage.NOTE_ON, msg.GetChannel(),msg.GetPitch(),msg.GetVelocity());

                ShortMessage noteOffMsg = new ShortMessage();
                //Signal/Channel/Pitch/Velocity
                noteOffMsg.setMessage(ShortMessage.NOTE_OFF,msg.GetChannel(),msg.GetPitch(),msg.GetVelocity());

                track.add(new MidiEvent(noteOnMsg,0));
                track.add(new MidiEvent(noteOffMsg,1));
                //i = i+1;
            }

            sequencer.setSequence(sequence);
            sequencer.setTempoInBPM(120);
            sequencer.setLoopCount(1);

            sequencer.start();

            Thread.sleep(1000);
        }

I am creating an application where the user can add multiple MIDI notes to a collection, from here they can press the "Play" button and the application will iterate through each note and play them through the speakers.

I've created a MIDIMessage class that holds details of the note the user has chose to add to the list, the details stored being the Pitch,Velocity,Delay and Channel.

Each of these messages is saved to an ArrayList with the type as MIDIMessage.

I then go on to attatch the iterator of the collection to an iterator object and play a sound whilst there is still an element in the collection that hasn't been used.

For some reason even if I only add one note to the collection there is always two notes playing with exactly the same pitch, length and velocity.

Also each note plays at the same time no matter how many are present in the collection, I assumed there would be some sort of delay in between them.

Following is the code I am using at the moment:

MIDIMessage:

package javatest;

public class MIDIMessage
{
    private int pitch;
    private int velocity;
    private int channel;

    public MIDIMessage(int p, int v, int c)
    {
        pitch = p;
        velocity = v;
        channel = c;
    }

    public int GetPitch()
    {
        return this.pitch;
    }

    public int GetVelocity()
    {
        return this.velocity;
    }

    public int GetChannel()
    {
        return this.channel;
    }
}

Adding a note to the collection:

public void AddToList()
    {
        int channel = jComboBoxChannels.getSelectedIndex();
        int pitch = jComboBoxPitch.getSelectedIndex();
        int velocity = ((Integer)jSpinnerVelocity.getValue());    
        collection.add(new MIDIMessage(pitch,velocity,channel));
    }

Playing the notes:

try
        {
            jButton1.setEnabled(false);
            Sequencer sequencer = MidiSystem.getSequencer();
            sequencer.open();
            Sequence sequence = new Sequence(Sequence.PPQ,1);
            Track track = sequence.createTrack();

            Iterator itr = collection.iterator();
            int i = 0;

            while(itr.hasNext())
            {
                MIDIMessage msg = (MIDIMessage)itr.next();

                ShortMessage noteOnMsg = new ShortMessage();
                //Signal/Channel/Pitch/Velocity
                noteOnMsg.setMessage(ShortMessage.NOTE_ON, msg.GetChannel(),msg.GetPitch(),msg.GetVelocity());

                ShortMessage noteOffMsg = new ShortMessage();
                //Signal/Channel/Pitch/Velocity
                noteOffMsg.setMessage(ShortMessage.NOTE_OFF,msg.GetChannel(),msg.GetPitch(),msg.GetVelocity());

                track.add(new MidiEvent(noteOnMsg,0));
                track.add(new MidiEvent(noteOffMsg,1));
                //i = i+1;
            }

            sequencer.setSequence(sequence);
            sequencer.setTempoInBPM(120);
            sequencer.setLoopCount(1);

            sequencer.start();

            Thread.sleep(1000);
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

宣告ˉ结束 2024-10-18 16:53:38

我不确定为什么音符会播放两次,但这绝对是错误的:

            track.add(new MidiEvent(noteOnMsg,0));
            track.add(new MidiEvent(noteOffMsg,1));

如您所见 此处,一个 MidiEvent 由消息和一个 MIDI 刻度组成。您始终在刻度 0 上添加一个 noteOnMsg 并在刻度 1 上添加一个 noteOffMsg,这解释了为什么多个音符会同时播放。您想做这样的事情:

startTick = 0;

while(itr.hasNext()) {
   [...]
   track.add(new MidiEvent(noteOnMsg,startTick));
   track.add(new MidiEvent(noteOffMsg,startTick + how_long_the_note_is_played));
   startTick += difference_between_this_note_and_the_next;
   [...]
}

我不确定您的 delay 意味着什么以及您是否可以在此处使用它,因此我使用描述性变量名称。

请注意,您必须在此处使用 MIDI 刻度 - 如果您想将秒转换为 MIDI 刻度,请参阅 这个问题(或者更确切地说是它的答案):

[一个 MIDI 滴答声有多长?]

公式为60000 / (BPM * PPQ)
(毫秒)。

I'm not sure why the notes are played twice, but this is definitely wrong:

            track.add(new MidiEvent(noteOnMsg,0));
            track.add(new MidiEvent(noteOffMsg,1));

As you can see here, a MidiEvent consists of the message and a MIDI tick. You always add a noteOnMsg on tick 0 and a noteOffMsg on tick 1, which explains why for multiple notes, they are all played at the same time. You want to do something like this instead:

startTick = 0;

while(itr.hasNext()) {
   [...]
   track.add(new MidiEvent(noteOnMsg,startTick));
   track.add(new MidiEvent(noteOffMsg,startTick + how_long_the_note_is_played));
   startTick += difference_between_this_note_and_the_next;
   [...]
}

I'm not sure what your delay means and if you can use it here, so I'm using descriptive variable names instead.

Note that you'll have to use MIDI ticks here - if you want to convert seconds in MIDI ticks, see this SO question (or rather its answer):

[How long is one MIDI tick?]

The formula is 60000 / (BPM * PPQ)
(milliseconds).

星光不落少年眉 2024-10-18 16:53:38

我遇到了同样的问题,对我来说问题是我没有考虑默认音序器(通过 MidiSystem.getSequencer() 检索)连接到默认合成器(通过 MidiSystem.getSequencer() 检索)。 getSynthesizer())。

因此,当我另外手动连接两者时,

sequencer.getTransmitter().setReceiver(synthesizer.getReceiver());

序列被发送到合成器两次,从而创建重复的播放。

因此,可以通过保留默认连接并删除上面的行或调用 MidiSystem.getSequencer(false) 来检索音序器(这会忽略默认连接)来防止这种情况。

I encountered the same issue and for me the problem was that I didn't consider the default sequencer (retrieved through MidiSystem.getSequencer()) is connected to the default synthesizer (retrieved through MidiSystem.getSynthesizer()).

So when I additionally connected the two manually with

sequencer.getTransmitter().setReceiver(synthesizer.getReceiver());

the sequence was sent to the synth twice, creating the duplicate playback.

This can thus be prevented by either leaving the default connection and removing above line or by calling MidiSystem.getSequencer(false) to retrieve the sequencer, which omits the default connection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文