1 Отредактировано Voldemar0 (20-08-2017 20:59)

Тема: Фонографъ

Привет!

В порядке развлечения и для некоторого удобства разбора коллекций ковырнул формат "Фонографъ".

Формат вполне простой, но заковыкой:
парсится по байтам, нулевое значение байта - тишина длительностью примерно 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.