Spec-Zone .ru
спецификации, руководства, описания, API
След: Звук
Введение в Секвенсеры
Домашняя страница > Звук

Введение в Секвенсеры

В мире MIDI секвенсер является любыми аппаратными средствами или устройством программного обеспечения, которое может точно играть или записать последовательность сообщений MIDI с меткой времени. Точно так же в API Звука Java, Sequencer абстрактный интерфейс определяет свойства объекта, который может играть и записать последовательности MidiEvent объекты. A Sequencer обычно загрузки они MidiEvent последовательности от стандартного файла MIDI или сохраняют их к такому файлу. Последовательности могут также быть отредактированы. Следующие страницы объясняют, как использовать Sequencer объекты, наряду со связанными классами и интерфейсами, чтобы выполнить такие задачи.

Разработать интуитивное понимание какой a Sequencer думайте об этом по аналогии с магнитофоном, который секвенсер напоминает во многих отношениях. Принимая во внимание, что магнитофон играет аудио, секвенсер играет данные MIDI. Последовательность является многодорожечной, линейной, упорядоченной временем записью MIDI музыкальные данные, которые секвенсер может играть на различных скоростях, перемотке, шаттле к определенным точкам, записи в, или скопировать в файл для хранения.

Передача и Получение сообщений MIDI объяснили, что устройства обычно имеют Receiver объекты, Transmitter объекты, или оба. Чтобы играть музыку, устройство обычно получает MidiMessages через a Receiver, который поочередно обычно получал их от a Transmitter это принадлежит a Sequencer. Устройство, которому принадлежит это Receiver мог бы быть a Synthesizer, который генерирует аудио непосредственно, или это мог бы быть выходной порт MIDI, который передает данные MIDI через физический кабель к некоторому внешнему элементу оборудования. Точно так же записывать музыку, серию с меткой времени MidiMessages обычно отправляются a Receiver принадлежавший a Sequencer, который размещает их в a Sequence объект. Обычно объект, отправляющий сообщения, является a Transmitter связанный с аппаратным входным портом, и данными MIDI реле порта, которые это получает от внешнего инструмента. Однако, устройство, ответственное за отправку сообщений, могло бы вместо этого быть некоторым другим Sequencer, или любое другое устройство, у которого есть a Transmitter. Кроме того, как ранее описано, программа может отправить сообщения, не используя никого Transmitter вообще.

A Sequencer непосредственно имеет обоих Receivers и Transmitters. Когда это записывает, это фактически получает MidiMessages через Receivers. Во время воспроизведения это использует Transmitters передаться MidiMessages это сохранено в Sequence то, что это записало (или загрузилось от файла).

Один способ думать о роли a Sequencer в Java API Звука как агрегатор и "де-агрегатор" MidiMessages. Серия отдельных MidiMessages, каждый из которых независим, отправляется Sequencer наряду с его собственной меткой времени, которая отмечает синхронизацию звукового события. Они MidiMessages инкапсулируются в MidiEvent объекты и собранный в Sequence объекты посредством действия Sequencer.record метод. A Sequence структура данных, содержащая, агрегируется MidiEvents, и это обычно представляет серию музыкальных нот, часто вся песня или состав. На воспроизведении, Sequencer снова извлечения MidiMessages от MidiEvent объекты в Sequence и затем передает их к одному или более устройствам, которые или представят их в звуке, сохранят их, изменят их, или передадут их на некоторое другое устройство.

У некоторых секвенсеров не могло бы быть ни передатчиков, ни получателей. Например, они могли бы создать MidiEvents с нуля в результате клавиатуры или событий от нажатия мыши, вместо получения MidiMessages через Receivers. Точно так же они могли бы играть музыку, связываясь непосредственно с внутренним синтезатором (который мог фактически быть тем же самым объектом как секвенсер) вместо отправки MidiMessages к a Receiver связанный с отдельным объектом. Однако, остальная часть этого обсуждения принимает нормальный случай секвенсера, который использует Receivers и Transmitters.

Когда Использовать Секвенсер

Для прикладной программы возможно отправить сообщения MIDI непосредственно устройству, не используя секвенсер, как был описан в Передаче и Получении сообщений MIDI. Программа просто вызывает Receiver.send метод каждый раз это хочет отправить сообщение. Это - прямой подход, это полезно, когда сама программа создает сообщения в режиме реального времени. Например, рассмотрите программу, которая позволяет пользователю играть примечания, щелкая по экранной клавиатуре фортепьяно. Когда программа получает событие мыши вниз, она сразу отправляет соответствующее Сообщение На сообщении к синтезатору.

Как ранее упомянуто, программа может включать метку времени с каждым сообщением MIDI, которое она отправляет получателю устройства. Однако, такие метки времени используются только для того, чтобы подстроить синхронизацию, исправить для того, чтобы обработать задержку. Вызывающая сторона не может обычно установить произвольные метки времени; временная стоимость, к которой передают Receiver.send должен быть близко к настоящему времени, или приемное устройство не могло бы быть в состоянии запланировать сообщение правильно. Это означает, что, если прикладная программа, требуемая, чтобы создать очередь MIDI, обменивается сообщениями для всей музыкальной пьесы загодя (вместо того, чтобы создать каждое сообщение в ответ на событие в реальном времени), это должно было бы очень делать все возможное запланировать каждый вызов Receiver.send в течение почти правильного времени.

К счастью, большинство прикладных программ не должно касаться такого планирования. Вместо вызова Receiver.send непосредственно, программа может использовать a Sequencer объект управлять очередью MIDI обменивается сообщениями для этого. Секвенсер заботится о планировании и отправке messages⠀” другими словами, играя музыку с корректной синхронизацией. Обычно, выгодно использовать секвенсер всякий раз, когда Вы должны преобразовать ряд нев реальном времени сообщений MIDI к ряду в реальном времени (как в воспроизведении), или наоборот (как в записи). Секвенсеры обычно используются для того, чтобы играть данные от файлов MIDI и для того, чтобы записать данные от входного порта MIDI.

Понимание Данных Последовательности

Прежде, чем исследовать Sequencer API, это помогает понять вид данных, это сохранено в последовательности.

Последовательности и Дорожки

В API Звука Java секвенсеры близко следуют за Стандартной спецификацией Файлов MIDI в способе, которым они организуют записанные данные MIDI. Как упомянуто выше, a Sequence агрегация MidiEvents, организованный вовремя. Но есть больше структуры к a Sequence чем только линейная последовательность MidiEvents: a Sequence фактически содержит глобальную информацию о синхронизации плюс набор Tracks, и это Tracks непосредственно то хранение MidiEvent данные. Таким образом, данные, играемые секвенсером, состоят из трехуровневой иерархии объектов: Sequencer, Track, и MidiEvent.

В стандартном использовании этих объектов, Sequence представляет полный музыкальный состав или раздел состава, с каждым Track соответствие речи или проигрывателю в ансамбле. В этой модели, всех данных на детали Track был бы также поэтому закодирован в определенный канал MIDI, зарезервированный для той речи или проигрывателя.

Этот способ организовать данные удобен в целях отредактировать последовательности, но отметьте, что это - только стандартный способ использовать Tracks. Нет ничего в определении Track class, который препятствует этому содержать соединение MidiEvents на различных каналах MIDI. Например, весь многоканальный состав MIDI может быть смешан и записан на одного Track. Кроме того, стандартные файлы MIDI Типа 0 (в противоположность Типу 1 и Типу 2) содержат по определению только одну дорожку; так a Sequence это читается из такого файла, будет обязательно иметь сингл Track объект.

MidiEvents и Галочки

Как обсуждено в Кратком обзоре Пакета MIDI, API Звука Java включает MidiMessage объекты, которые соответствуют сырым данным два - или трехбайтовые последовательности, которые составляют большинство стандартных сообщений MIDI. A MidiEvent просто упаковка a MidiMessage наряду с сопроводительным значением синхронизации, которое определяет, когда событие имеет место. (Мы могли бы тогда сказать, что последовательность действительно состоит из четырех - или пятиуровневая иерархия данных, а не трехуровневый, потому что очевидный самый низкий уровень, MidiEvent, фактически содержит низшего уровня MidiMessage, и аналогично MidiMessage объект содержит массив байтов, который включает стандартное сообщение MIDI.)

В API Звука Java есть два различных пути в который MidiMessages может быть связан со значениями синхронизации. Каждый - путь, упомянутый выше под, "Когда Использовать Секвенсер." Этот метод был описан подробно при Отправке сообщения к Получателю без Использования Передатчика и Понимания Меток времени. Там, мы видели что send метод Receiver берет a MidiMessage параметр и параметр метки времени. В микросекундах может только быть выражена такая метка времени.

Другой путь тот, в который a MidiMessage могли определить его синхронизацию, будучи инкапсулировавшимся в a MidiEvent. В этом случае синхронизация выражается в немного более абстрактных модулях, названных галочками.

Какова продолжительность галочки? Это может измениться между последовательностями (но не в пределах последовательности), и ее значение сохранено в заголовке стандартного файла MIDI. Размер галочки дается в одном из двух типов модулей:

Если модуль является PPQ, размер галочки выражается как часть четвертной ноты, которая является родственником, не абсолютным, временная стоимость. Четвертная нота является музыкальным значением продолжительности, которое часто соответствует одному удару музыки (четверть меры в 4/4 время). Продолжительность четвертной ноты зависит от темпа, который может измениться в течение музыки, если последовательность содержит события изменения темпа. Так, если синхронизация последовательности постепенно увеличивается (отсчитывает), происходят, говорят 96 раз на четвертную ноту, меры по значению синхронизации каждого события что позиция события в музыкальных терминах, не как абсолютная временная стоимость.

С другой стороны, в случае SMPTE, модули измеряют абсолютное время, и понятие темпа является неподходящим. Есть фактически четыре различных доступные соглашения SMPTE, которые обращаются к числу кадров в секунду кинофильма. Число кадров в секунду может быть 24, 25, 29.97, или 30. С временным кодом SMPTE размер галочки выражается как часть фрейма.

В API Звука Java можно вызвать Sequence.getDivisionType учиться, какой тип unit⠀” а именно, PPQ или один из SMPTE units⠀” используется в определенной последовательности. Можно тогда вычислить размер галочки после вызова Sequence.getResolution. Последний метод возвращает число галочек на четвертную ноту, если тип подразделения является PPQ, или на фрейм SMPTE, если тип подразделения является одним из соглашений SMPTE. Можно получить размер галочки, используя эту формулу в случае PPQ:

ticksPerSecond =  
    resolution * (currentTempoInBeatsPerMinute / 60.0);
tickSize = 1.0 / ticksPerSecond;

и эта формула в случае SMPTE:

framesPerSecond = 
  (divisionType == Sequence.SMPTE_24 ? 24
    : (divisionType == Sequence.SMPTE_25 ? 25
      : (divisionType == Sequence.SMPTE_30 ? 30
        : (divisionType == Sequence.SMPTE_30DROP ?
29.97)))); ticksPerSecond = resolution * framesPerSecond; tickSize = 1.0 / ticksPerSecond;

Определение API Звука Java синхронизации в последовательности зеркально отражает определение Стандартной спецификации Файлов MIDI. Однако, есть одно важное различие. Значения галочки, содержавшиеся в MidiEvents измерьте совокупное время, а не время дельты. В стандартном файле MIDI информация о синхронизации каждого события измеряет количество времени, законченное начиная с начала предыдущего события в последовательности. Это вызывают временем дельты. Но в API Звука Java, галочки не являются значениями дельты; они - временная стоимость предыдущего события плюс значение дельты. Другими словами в API Звука Java значение синхронизации для каждого события всегда больше чем то из предыдущего события в последовательности (или равно, если события, как предполагается, одновременны). Значение синхронизации каждого события измеряет время, законченное с начала последовательности.

Чтобы подвести итог, API Звука Java выражает информацию о синхронизации или в галочках MIDI или в микросекунды. MidiEvents храните информацию синхронизации с точки зрения галочек MIDI. Продолжительность галочки может быть вычислена от Sequence's глобальная информация о синхронизации и, если последовательность использует основанную на темпе синхронизацию, текущий музыкальный темп. Метка времени связалась с a MidiMessage отправленный a Receiver, с другой стороны, всегда выражается в микросекундах.

Одна цель этого проекта состоит в том, чтобы избежать конфликтных понятий времени. Это - задание a Sequencer интерпретировать единицы измерения времени в MidiEvents, который мог бы иметь модули PPQ, и преобразовать их в абсолютное время в микросекундах, принимая текущий темп во внимание. Секвенсер должен также выразить микросекунды относительно времени, когда устройство, получающее сообщение, было открыто. Отметьте, что у секвенсера могут быть многократные передатчики, каждый передающий сообщения к различному получателю, который мог бы быть связан с абсолютно различным устройством. Можно видеть, тогда, что секвенсер должен быть в состоянии выполнить многократные преобразования одновременно, удостоверяясь, что каждое устройство получает метки времени, подходящие для его понятия времени.

Чтобы сделать вопросы, более сложные, различные устройства могли бы обновить свои понятия времени, основанного на различных источниках (таких как часы операционной системы, или часы, сохраняемые звуковой картой). Это означает, что их синхронизации могут дрейфовать относительно секвенсера. Чтобы сохранить в синхронизации с секвенсером, некоторые устройства разрешают себе быть "ведомыми устройствами" понятия секвенсера времени. Установка ведущих устройств и ведомых устройств обсуждается позже под MidiEvent.


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Передача и Получение сообщений MIDI
Следующая страница: Используя Методы Секвенсера