Отправка большого количества данных с pyportmidi перестает работать, если я не добавлю задержку - PullRequest
3 голосов
/ 20 ноября 2011

Я пытаюсь поговорить с панелью запуска Novation с pyportmidi.Я заметил, что если я просто продолжу посылать ему инструкции, используя midiOut.WriteShort(), он обработает первые 100 или около того, а затем потеряет остальные.

Я предполагаю, что где-то есть буфер, который заполняется, и один разон полон, инструкции потеряны.Я могу обойти эту проблему, добавив time.sleep (.1) после каждого сообщения, но это, очевидно, делает вещи очень медленными.Есть ли способ проверить, заполнен ли буфер, и спать только, если мне нужно?Или как дождаться освобождения буфера, прежде чем я отправлю больше данных?

1 Ответ

4 голосов
/ 21 ноября 2011

Когда я взглянул на репозиторий SVN, я наткнулся на это в коде обертки, обратите внимание на то, почему здесь bufferSize 0?комментарий ..

def __init__(self, OutputDevice, latency=0):
...stuff...
    # Why is bufferSize 0 here?
    err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency)

В документации API показано, что Pm_OpenOutput имеет следующую подпись

PmError Pm_OpenOutput (
    PortMidiStream **stream, 
    PmDeviceID outputDevice, 
    void *outputDriverInfo, 
    long bufferSize, 
    PmTimeProcPtr time_proc, 
    void *time_info, 
    long latency
)

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

portmidi.c рассказывает немного другую историю:

if (bufferSize <= 0) bufferSize = 256; /* default buffer size */
     midi->queue = Pm_QueueCreate(bufferSize, sizeof(PmEvent));
     if (!midi->queue) {
         /* free portMidi data */
         *stream = NULL;
         pm_free(midi); 
         err = pmInsufficientMemory;
         goto error_return;
}

Итак, 256 по умолчанию.Что объясняет, почему у вас возникают проблемы около 100 или около того.

Однако следует иметь в виду, что MIDI очень медленный, 31250 бод (31250 бит в секунду), поскольку MIDI-сообщения (обычно)2 байта (16 бит), что означает максимум 1953 сообщения в секунду.(Я могу ошибаться, но я довольно близок, если я не прав)

Однако, есть надежда: простое исправление: вы можете спать до 2 мс в большинстве операционных систем без проблемup.

time.sleep(.002) # 2 millisecond sleep

Однако, поскольку вы используете write_short (), это даст вам только 500 сообщений в секунду.Таким образом, вы можете захотеть сделать что-то вроде очереди, которая опрашивается каждые 0,002 секунды для исходящих сообщений, выталкивает 16 из стека, записывает их и затем спит.Таким образом, если весь ваш стек MIDI поддерживает такие высокие скорости, вы можете получать 8000 сообщений в секунду.

Я заметил, что в следующем коде, если я опущу время ожидания ниже, чем 0,002, MIDI не будет отправлено ввсе до Я вышел из программы, затем все события излились на MIDI BUS.Так что может быть проблема с ограничением скорости portmidi или в OSX.

Еще одна вещь, которую следует иметь в виду, если вы действительно используете MIDI - скорее всего, значения смены элемента управления, если вы модифицируете что-то вроде фильтра высоких частот, значение «1» звучит очень многокак «2», так что если вы сделаете ваши сообщения менее детальными (с приращением или уменьшением на 2 или 4), вы можете сократить количество сообщений без заметной разницы в аудио.Это неоптимальное решение, и, по всей вероятности, ваш MIDI-стек, вероятно, поддерживает намного быстрее, чем 31250 бод.

Еще одна вещь, которую следует учитывать, - это то, что если вы подчиняете свое приложение portmidi к часам MIDI, вы можете получить надежный потоктиков от хоста MIDI, который вы могли бы использовать в качестве триггера для записи данных MIDI обратно (без снов).

Удачи!

-n

PPQN Clock MIDI 1.0

...