Тема: Фонографъ
Привет!
В порядке развлечения и для некоторого удобства разбора коллекций ковырнул формат "Фонографъ".
Формат вполне простой, но заковыкой:
парсится по байтам, нулевое значение байта - тишина длительностью примерно 2834 тактов (2.8 мс), любое другое значение даёт переключение положения мембраны + задержку длительностью (n-1) * 11 + 4 + 16 тактов.
Напомню: такт - это примерно 1 / (14.28/14 * 1000000) мкс.
Исходник плейера с комментариями (таблицы t1 и t3 могут настраиваться фонографом):
sBuf equ $FC Номер фрагмента (фрагмент - 8 Кб)
pBufL equ $FD Указатель на семпл внутри фрагмента
pBufH equ $FE
pName equ $428 Имя файла
; Ищем конец имени файла...
enter:
LDY #1C
l1:
LDA pName, Y
CMP #A0
BNE l0
DEY
BNE l1
; ... и дописываем к нему '.0'
l0:
LDA #'.
STA pName+1, Y
LDA #'0
STA pName+2, Y
STY pBufL
LDA #0E
STA 48 ; =функция "load ???"
LDA #20 ; Куда читать
STA 69
LDA #00
STA 68
STA sBuf
; Читаем файлы с музончиком в ОЗУ
; Все файлики сразу !!!
load_files:
LDA #00
STA 55 ; ?
STA 72 ; нормальный файл (не удалённый)
STA 04B0
STA 3F ; ?
STA 0425 ; обращение к драйверу ФС
STA 77 ; начиная с файла 0
LDY sBuf
LDA t1, Y
BEQ start_play
LDA #05
SEC
set_mem1:
LDX t1, Y
BEQ set_mem2
STA C200, X
STA C100, X
INY
SBC #01
BNE set_mem1
set_mem2:
STY sBuf
LDX pBufL
INC 042A, X
JSR 02A1 ; Исполнение команды "load"
BCC load_files
restore_mem_and_exit:
LDY #04
set_mem0:
LDX t2, Y
STA C200, X
STA C100, X
DEY
BPL set_mem0
RTS
t2: ; Таблица первоначальной настройки памяти (до запуска проги)
DFB $11,$22,$33,$44,$55
; Собсно, отсюда играем
start_play:
LDY #00
STY sBuf
STY pBufL
LDX t3
STA C210, X
STA C110, X
LDA #20
STA pBufH
JMP loop_ptrH
wait6tick:
BIT pBufL ; 3
JMP ret_to_loop ; 3
loop_ptrH:
SEC
; Такт: 14.28/14 МГц или 0.98 мкс
; 0 - даёт задержку без щелчка 2834 тактов (2.8 мс)
; n - даёт задержку около (n-1) * 11 + 4 + 16 тактов и щелчок
loop_ptrL:
LDA (pBufL), Y ; 5
BEQ silence3ms ; 2 (скорее всего нет перехода)
ret_to_loop: ; (a-1) * 11 + 4
SBC #01 ; 2
BNE wait6tick ; 3 +6
STA C030 ; 4
goto_next_byte:
INY ; 2
BNE loop_ptrL ; 3 (скорее всего есть переход)
INC pBufH
LDA pBufH
CMP #40
BCC loop_ptrH
LDA #20
STA pBufH
INC sBuf
LDX sBuf
LDY t3, X
CLC
BEQ restore_mem_and_exit
STA C210, Y
STA C110, Y
LDY #00
BEQ loop_ptrH -JMP
; При a = 0, примерно 2822 тактов -> ~2.7 ms
silence3ms: ; 1(beq) + 2(nop) + a * 11 + 3(beq)
NOP
silence3ms_0: ; a * 11
NOP ; 2
NOP
NOP
SBC #01 ; 2
BNE silence3ms_0 ; 3
BEQ goto_next_byte -JMP
t1: ; Таблица сегментов памяти, в которые можно читать файл
DFB $11,$22,$33,$44,$55, $18,$29,$3a,$4b,$5c, $1d,0
t3: ; Таблица сегментов памяти, в которых расположены фрагменты мелодии
DFB $1,$2,$3,$4,$5,$8,$9,$A,$B,$C,$D
Синтезатор RAW-PCM-файла по заданным FIL-файлам "Фонографа"
(RAW-PCM можно открыть в каком нибудь аудио-редакторе на PC и прослушать):
const
sample : ShortInt = -63;
samplerate = 48000;
var
sf, df : File;
fono_buf: Array[0..500000] of Byte;
wav_buf : Array[0..$FFFFFF] of ShortInt;
fono_num: Cardinal;
fono_cnt: Cardinal;
wav_num : Cardinal;
// Заполняет интервал размером x тиков Агата
procedure add_wav_block(x: Cardinal);
var nsampl: Cardinal; ms2tick, ms2int, ms2sample: Double;
begin
ms2tick := 1 / (14280000 / 14); // Длительность одного тика в ms
ms2int := ms2tick * x; // Длительность интервала в ms
ms2sample := 1 / samplerate; // Длительность одного семпла
nsampl := Round(ms2int / ms2sample); // Число семплов в интервале
while nsampl > 0 do begin
wav_buf[wav_num] := sample;
inc(wav_num);
dec(nsampl);
end;
end;
var x, y: Cardinal;
begin
fono_num := 0;
for x := 1 to ParamCount do begin
assign(sf, ParamStr(x)); reset(sf, 1);
seek(sf, $28);
blockread(sf, fono_buf[fono_num], 5000000, y);
inc(fono_num, y);
close(sf);
end;
wav_num := 0;
for fono_cnt := 0 to fono_num - 1 do
if fono_buf[fono_cnt] = 0 then begin
add_wav_block(2834);
end else begin
add_wav_block((fono_buf[fono_cnt]-1) * 11 + 4 + 16);
sample := -sample;
end;
assign(df, 'wave.wav-raw'); rewrite(df, 1);
blockwrite(df, wav_buf, wav_num);
close(df);
end.