Spec-Zone .ru
спецификации, руководства, описания, API
|
В мире MIDI секвенсер является любыми аппаратными средствами или устройством программного обеспечения, которое может точно играть или записать последовательность сообщений MIDI с меткой времени. Точно так же в API Звука Java, Sequencer
абстрактный интерфейс определяет свойства объекта, который может играть и записать последовательности MidiEvent
Sequencer
обычно загрузки они MidiEvent
последовательности от стандартного файла MIDI или сохраняют их к такому файлу. Последовательности могут также быть отредактированы. Следующие страницы объясняют, как использовать Sequencer
объекты, наряду со связанными классами и интерфейсами, чтобы выполнить такие задачи.
Разработать интуитивное понимание какой a Sequencer
думайте об этом по аналогии с магнитофоном, который секвенсер напоминает во многих отношениях. Принимая во внимание, что магнитофон играет аудио, секвенсер играет данные 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
объект.
Как обсуждено в Кратком обзоре Пакета 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;
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
.