by Grey » 26 Sep 2018, 03:09
я ешё раз все обдумал. Если действительно сможешь сделать что бы ДМА сам следил за циклом и за концом сэмпла, то тогда подход немного измениться и упростится, тогда не нужен доступ для чтения ячеек с адресами ДМА машины, где она остановилась. Пускай сама продолжает с того места где остановилась при запуске следующей порции. А где поменялись данные - туда записываем новые данные.
Но что тогда нужно .
Нужно что бы можно было указать ДМА , сколько байт сэмпла передать в буфер. Это обязательно для точного совпадения скорости в модулях. Если просто привязывается к размеру половины буфера - 128 байт, то во многих модулях скорость будет сильно отличаться от оригинала и оцифровки уплывут.
Тут три варианта.
ПЕРВЫЙ Если ДМА сможет сам следить, в какой буфер писать и ждать пока он проиграет - это самый оптимистичный вариант. Тогда логика работы такая.
в ДМА задается 2 байта - сколько отсчетов проиграть. потому как это может быть и 100 и 10000. в зависимости от заданного темпа. поэтому пусть будет от 1 до 65535. Но в стандартных условиях это 750 байт.
Буфер 2*512 байт - 2 канала по 256 16-битных слов.- половина буфера - 128 отсчетов.
Значит ДМА сам определяет какой буфер играется и заполняет 128 байт второй половины буфера, останавливается, ждет пока проиграет первая половина и продолжает заполнять вторую и так по кругу, пока не передаст всю заданную ему в начале длинну. После этого z80 быстро записывает в ДМА новые параметры сэмплов и запускает ДМА дальше указав опять, сколько байт передать в буфер (если темп не менялся то столько же как и в первый раз ) - но ДМА должен начать заполнение буфера с того места, где остановился а не с начала !!! (Или лучше будет возможность указать - с какого адреса буфера начать заполнение)
Так как ДМА складывает сам каналы, то он может даже ориентироваться не по половине буфера по проигранному байту. Т.е. заполняет до проигрываемого сейчас байта и останавливается и потом все время идет как бы следом за воспроизведением. А при следующем запуске начинает строго с того места где остановился (лучше возможность указать от куда начать заполнение) и опять догоняет буфер и опять за ним медленно ползет до следующей остановки. Этот вариант возможен если ДМА складывает все каналы параллельно. т.е. перебрал и сложил все каналы, перешел к следующей ячейке буфера.
ВТОРОЙ Если ДМА не будет сам следить за заполнением буфера. тогда это должен делать z80. Но все равно должна быть возможность запустить пересылку столько байт, сколько нужно, но не более размера буфера - т.е от 1 до 256 (или от 0 до 255). Тогда z80 говорит ДМА с какого адреса буфер начать заполнять и сколько байт. Синхронизируется при этом читая статус - какая ячейка буфера сейчас воспроизводится, надеясь что ДМА все успеет сделать.
Этот вариант менее удобный но тоже вполне работоспособен.
Ну и ТРЕТИЙ вариант - самый плачевный, если ДМА четко привязан к размеры буфера. т.е. передает только по 128 байт и по другому не умеет, потом в другую половину буфера 128 байт. При этом варианте точность плеера немного пострадает. 750/128 = 5,86 . Допустим сделаем 6 циклов ДМА и в какой то момент 5 - примерно как то попадем. Кому слон на ухо наступил - не заметит. Но жизнь это осложнит , и времени для расчетов заметно меньше будет.
Это было только описание взаимодействия ДМА с буфером воспроизведения.
Теперь о ДМА машине
Что должно быть обязательно.
ДМА при запись первого канала должен делать сложение не с буфером а с 32768.
карта ДМА машины будет такая.
2 байта - адрес сэмпла - предлагаю для экономии выравнивать начало сэмплов до 256 байт (или 64 - биты позволяют но смысла нет)
2 байта - длинна сэмпла - при достижении ДМА должен или остановится или начать с лупа
2 байта - смещение начала лупа - если равен длине или больше то ДМА останавливается, если меньше - то запуск с лупа, только с учетом остатка (дробной части адреса).
2 байта - счетчик адреса воспроизведения (прибавляется к стартовому адресу, проверяется на конец длинны)
2 байта - остаток или дробная часть счетчика адреса сэмпла (12 бит)
2 байта - (условно - период) коэффициент масштабирования сэмпла (4 бита целая 12 бит дробная часть) - то что в цикле прибавляется к адресу сэмпла и к остатку. Это период уже помноженный на частоту сэмпла и поделенный на частоту дискретизации.
1 байт громкость
Получается минимум 13 байт . и без управляющего байта, правда остаются свободные 2 бита в адресе сэмпла, 4 бита в дробной части адреса сэмпла и 2 бита в громкости.
Можно сэкономить 1 байт, если отвести по 12 байт на 40 каналов - 480 байт, а оставшиеся 32 байта = 6 бит*40 - использовать как громкости - Да - не удобно считать, но громкость не так критично. Еще в в свободных битах 2 бита отвести - правый/левый канал, или в оба сразу.
объединить 4 свободных бита в дробной части счетчике и 4 бита в старшей части периода. тогда будет всего 3 байта - период и остаток
(в предложенной тобой карте почти тоже самое , только про начало лупа забыл, только счетчик и длинна. И 1 байт -- сумматор периода - мало, минимум 12 бит , я как раз у себя это учитываю 4+12 целая+дробная . )
Круто, если луп будет двух видов, с начала или вперед назад. Если нет - то можно и программно сэмпл разворачивается в обратную сторону - но тогда длинна может не поместиться в 64к.
Для ровного счета - 40 каналов, только без четкой привязки к правому или к левому, пусть битом в громкости задается - в правый или в левый канал складывать, ( а если возможно то и в два сразу вот и почти панинг, а если возможно, то в один складывать а в другой вычитать - вот тебе и суроунд для ImpulsTracker-a. ).
и получится крутотень.
В сам буфер z80 писать ничего не будет. Будет писать в память ДМА машины через два порта. В старшем разряде адреса- номер ячейки памяти ДМА машины, так как их 512 то два разных младших адреса порта нужно.
Читать - какая ячейка буфера проигрывается - 0-255 , и какой байт или отсчет ДМА складывает, либо просто статус ДМА - закончил или нет. (при параллельной обработке каналов ДМА можно какой отсчет , если будет выбрана последовательная схема записи в буфер, то просто закончил или нет)
Last edited by
Grey on 26 Sep 2018, 11:20, edited 1 time in total.