Nano Hash - криптовалюты, майнинг, программирование

Почему не работают тайминги миди-нот?

Я создаю редактор MIDI-роликов для фортепиано. Класс Note создает и содержит объект NOTE_ON и связанный с ним объект NOTE_OFF, а также прямоугольник, которым пользователь манипулирует на экране, чтобы управлять высотой звука, временем и продолжительностью нот. Ниже приведен код этого класса без кода прямоугольника. Я не могу понять, почему он не работает должным образом. Тестовая программа создает пять таких объектов Note и отображает их на сетке пианино, и они воспроизводятся правильно. Метод изменения высоты тона также работает правильно, когда прямоугольник перемещается вверх или вниз. Но заметки начинают плохо себя вести, когда я вызываю методы для изменения времени или продолжительности. Во-первых, они не играют там, где им говорят, когда их перемещают, а затем, если ноты перетаскиваются друг на друга или растягиваются друг над другом, перемещенная нота не позволит играть нотам под ней. Моя единица движения, отправляемая этим методам в качестве аргумента, установлена ​​на 16, поэтому нота всегда будет привязана к позиции 16-й доли. Может ли кто-нибудь заметить что-нибудь не так с моим кодом?

public class Note {
MidiEvent noteOn;
MidiEvent noteOff;

private int channel;
private int pitch;
private int vel;

// Constructor calls methods to create NOTE_ON, NOTE_OFF, and graphical rectangle
public Note(MidiMessage on, long tickPos) {
    noteOn = createNoteOn(on, tickPos);
    ShortMessage shortMessage = (ShortMessage) on;
    noteOff = createNoteOff(shortMessage.getChannel(), shortMessage.getData1(), tickPos);
}

public MidiEvent createNoteOn(MidiMessage on, long tickPos) {
    noteOn = new MidiEvent(on, tickPos);
    return noteOn;
}

public MidiEvent createNoteOff(int chan, int pitch, long tickPos) {
    try {
        noteOff = new MidiEvent(new ShortMessage(ShortMessage.NOTE_OFF, chan, pitch, 0), tickPos + 2);
    } catch (InvalidMidiDataException e) {
            e.printStackTrace();
    }
    return noteOff;
}

// Method for moving musical pitch of this note up or down for both NOTE_ON and NOTE_OFF
public void setPitch(int pitchUpOrDown) {
    MidiMessage message = noteOn.getMessage();
    ShortMessage shortMessage = (ShortMessage) message;
        channel = shortMessage.getChannel();
        pitch = shortMessage.getData1();
        vel = shortMessage.getData2();
        try {
            shortMessage.setMessage(ShortMessage.NOTE_ON, channel, pitch + pitchUpOrDown, vel);
        } catch (InvalidMidiDataException e) {
            e.printStackTrace();
        }
        message = noteOff.getMessage();
        shortMessage = (ShortMessage) message;
        try {
            shortMessage.setMessage(ShortMessage.NOTE_OFF, channel, pitch + pitchUpOrDown, 0);
        } catch (InvalidMidiDataException e) {
            e.printStackTrace();
        }
}

// Moves entire note without changing duration of note
public void shiftLocation(int diff) {
    noteOn.setTick(noteOn.getTick() + diff);
    noteOff.setTick(noteOff.getTick() + diff);
}

// Moves start time of note while leaving end time in place, changes duration of note
public void setStartTime(long start) {
    noteOn.setTick(start);
}

// Moves end time of note while leaving start time in place, changes duration of note
public void setDuration(int duration) {
    noteOff.setTick(noteOff.getTick() + duration);
}

MIDI-секвенсор и синтезатор:

import javax.sound.midi.*;

public class MusicEngine {
Sequencer sequencer;
Sequence sequence;
Synthesizer synthesizer;
Track track;
MidiEvent event;
// PPQ, or ticks per beat
int ticksPerBeat = 16;
int tempoBPM = 120;

// Constructor
public MusicEngine() {      
    createMidi();
}

// Get sequencer and sequence and track
public void createMidi() {
    try {
        sequencer =  MidiSystem.getSequencer();
        if (sequencer == null) {
            System.out.println("Cannot get a sequencer");
            System.exit(0);
        }
        sequencer.open();

        // If sequencer is not the same as synthesizer, link the two 
        // (required in J2SE 5.0)
        if (!(sequencer instanceof Synthesizer)) {
            System.out.println("Linking the sequencer to the synthesizer");
            synthesizer = MidiSystem.getSynthesizer();
            synthesizer.open();
            Receiver synthReceiver = synthesizer.getReceiver();
            Transmitter seqTransmitter = sequencer.getTransmitter();
            seqTransmitter.setReceiver(synthReceiver);
        } else 
            synthesizer = (Synthesizer)sequencer;
        sequence = new Sequence(Sequence.PPQ, ticksPerBeat);
        track = sequence.createTrack();
        sequencer.setTempoInBPM(tempoBPM);
    } catch(MidiUnavailableException e) {
        System.out.println("No sequencer available");
        System.exit(0);
    } catch(Exception e) {
        e.printStackTrace();
        System.exit(0);
    }

}

// Create an individual MIDI event
public MidiEvent createEvent(int command, int channel, int one, int two, int tick) {
    event = null;
    try {
        ShortMessage a = new ShortMessage();
        a.setMessage(command, channel, one, two);
        event = new MidiEvent(a, tick);
    } catch(InvalidMidiDataException e) {
        e.printStackTrace();
    }
    return event;
}

public void add(MidiEvent event) {
    track.add(event);
}

public void playSong(int tempo) {
    try {
        sequencer.setSequence(sequence);
    }
    catch (InvalidMidiDataException e) {
        e.printStackTrace();
    }

    sequencer.start();
}

public void stopSong() {
    sequencer.stop();
}
}

  • Может помочь размещение кода, который вы используете для воспроизведения последовательности? Кроме того, можете ли вы сначала выделить вещи в простой тестовый пример, когда вы создаете трек с парой нот, изменяете время / продолжительность одной из нот, а затем воспроизводите последовательность? 04.12.2012
  • Я добавил движок синтезатора и секвенсора. Мне нужно ненадолго отойти. Когда я вернусь, я попытаюсь упростить код и извлечь простой тестовый код из моего более сложного кода, который у меня есть. 04.12.2012

Ответы:


1

Возможно, я неправильно понимаю ваш код здесь, но кажется, что вы только увеличиваете длину заметок в своем setDuration() методе. Разве это не должно выглядеть так?

public void setDuration(int duration) {
    noteOff.setTick(noteOn.getTick() + duration);
}
05.12.2012
  • Да, это цель этого метода: увеличить длину ноты. Чуть выше это отдельный метод для фактического перемещения заметки (setStartTime). Я все еще работаю над предоставлением сжатой формы кода, но у меня возникают проблемы, заставляющие этот код работать. Это мой первый настоящий проект, поэтому прошу терпения, пока я выясню, как это сделать. 05.12.2012
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..