Metropoli BBS
VIEWER: device.pas MODE: TEXT (CP437)
{sb device}
const blocksize=512;
      bsdiv2=blocksize div 2;
      bsdiv4=blocksize div 4;
      playspeed:word=22222; {5000-45454, voi vaihtaa ennen inittiƤ}

      base:word=$220;
      irq:byte=5;
      dma:byte=1;

type channelinforec=
             record
              playing:boolean;
              position:longint;
              fixed:word;
              faddl:word;
              faddh:word;
              sample:byte;
              freq:longint;
              volume:integer; {0-64!!!!!!!!!!}
             end;

const charecsize=sizeof(channelinforec);
      samrecsize=sizeof(samrec);

var interrupts:longint;
    airq,pic,pageport:byte;
    istam,istom,dstam,dstom:byte;
    koee:byte;

    dsp_reset:word;
    dsp_read_data:word;
    dsp_write_data:word;
    dsp_write_status:word;
    dsp_data_avail:word;

    tmp:array[0..bsdiv2] of integer;
    mix:array[0..blocksize*2] of byte;
    mixalku:word;
    imultable:array[0..64] of array[-128..127] of shortint;

    vuoro:word;

    oldclk:pointer;

    channel:array[1..32] of channelinforec;

    rekisterit:array[0..24] of byte;

{$i sndblst.pas}

{$S-}
procedure saver; assembler;
asm
 db $66; mov [rekisterit].word[0],ax
 db $66; mov [rekisterit].word[4],bx
 db $66; mov [rekisterit].word[8],cx
 db $66; mov [rekisterit].word[12],dx
 db $66; mov [rekisterit].word[16],si
 db $66; mov [rekisterit].word[20],di
end;

{$S-}
procedure restr; assembler;
asm
 db $66; mov ax,[rekisterit].word[0]
 db $66; mov bx,[rekisterit].word[4]
 db $66; mov cx,[rekisterit].word[8]
 db $66; mov dx,[rekisterit].word[12]
 db $66; mov si,[rekisterit].word[16]
 db $66; mov di,[rekisterit].word[20]
end;

{$S-}
procedure clip; near; assembler;
 asm
  mov di,[vuoro];
  add di,offset mix;
  add di,[mixalku];
  mov si,offset tmp;
  mov cx,bsdiv2
  mov dx,$FF00;

 @looppi:;
  mov ax,[si];

  cmp ax,127;
  jg @liikaa;

  add ax,128;
  jl @liianvahan;

  mov [di],al;
  add si,2;
  inc di
  dec cx;
  jnz @looppi;

  jmp @loppu;

 @liikaa:
  mov [di],dh;
  add si,2;
  inc di
  dec cx;
  jnz @looppi;

  jmp @loppu;

 @liianvahan:
  mov [di],dl;
  add si,2;
  inc di
  dec cx;
  jnz @looppi;

@loppu:
 end;

{$S-}
procedure tyhjennatmp; near; assembler;
asm
 db $66; push ax;
 mov dx,seg tmp;
 db $66; xor ax,ax;
 mov es,dx;
 mov cx,bsdiv4;
 mov di,offset tmp;
 cld;
 db $66; rep stosw;
 db $66; pop ax;
end;

{mixerille}
var mi,ma:word;
    sam:byte;
    oerror:byte;
    offs,page:word;
    offseti:longint;
    bytes:longint;
    bytez:longint;
    vol:integer;
    alku:word;

{$S-}
procedure map_page2(handle:word; phys_page:byte; log_page:word); near;
assembler; asm
 mov ah,$44;
 mov al,[phys_page];
 mov bx,[log_page];
 mov dx,[handle];
 cli;
 int $67;
 mov [error],ah
end;

{$F+}
{$S-}
procedure mixer; interrupt;
begin
 asm
  cli; cli;
 end;
 saver;
 koee:=port[base+$E];

 tyhjennatmp;

 oerror:=omaems.error;
 omaems.save_ems(ems.handle);
 if omaems.error>0 then mwrite('ERROR 1',0,0,15);

 ems.page:=65535;

 for mi:=1 to 32 do if channel[mi].playing then with channel[mi] do begin
  ma:=0;
  sam:=sample;
{  vol:=byte(word(word(volume)*word(master)) div 64);}

  repeat
   offseti:=samples[sam].data+position;
   page:=word(longint(offseti) shr 14);
   offs:=word(offseti) and $3FFF;
   if page<>ems.page then begin
    ems.page:=page;
    map_page2(ems.handle,0,ems.page);
   end;

   bytes:=16384-offs;
   bytez:=samples[sam].length-position;
   if (bytez<bytes) then bytes:=bytez;
   bytez:=samples[sam].loop.endi-position;
   if (samples[sam].loop.endi>0) and (bytez<bytes) then bytes:=bytez;
   inc(bytes,offs);
   alku:=offs;
   asm
    mov ax,[ems+emsrec.addr];
    mov es,ax;

    mov cx,[mi];
    mov ax,charecsize;
    mul cx;
    mov di,ax;
    sub di,charecsize;

    push bp;

    mov si,[ma];
    mov dx,[bytes].word;
    mov bp,[offs];
    mov cx,[channel+channelinforec.faddl+di];
    mov bh,[channel+channelinforec.volume+di].byte;
    mov al,[master];
    mul bh;
    shr ax,6;
    mov bh,al;
   @looppi:
    mov bl,es:[bp];
    mov al,[imultable+bx].byte;
    cbw;

    add [tmp+si].word,ax;

    add [channel+channelinforec.fixed+di],cx;
    adc bp,[channel+channelinforec.faddh+di];

    add si,2;
    cmp bp,dx
    jae @loppu;

    cmp si,bsdiv2*2;
    jb @looppi;
   @loppu:
    mov bx,bp;
    pop bp;

    mov [ma],si;
    mov [offs],bx;

    db $66; xor ax,ax;
    mov ax,[offs];
    sub ax,[alku];
    db $66; mov cx,[channel+channelinforec.position+di].word[0];
    db $66; add cx,ax;
    db $66; mov [channel+channelinforec.position+di].word[0],cx;
   end;
   if position>=samples[sam].loop.endi then
    dec(position,samples[sam].loop.length);
   if position>=samples[sam].length then playing:=false;
 until (ma>=blocksize) or (playing=false);
 end;
 clip;
 omaems.rest_ems(ems.handle);
 if error>0 then mwrite('ERROR 2',0,1,15);
 omaems.error:=oerror;

 if vuoro=0 then vuoro:=bsdiv2 else vuoro:=0;
 inc(interrupts,1);

 port[$20]:=$20;
 if irq>7 then port[$A0]:=$20;

 restr;
end;
{$F-}

{$S-}
procedure init; far;
var c:byte;
    l,i,t:integer;
    cha:char;
begin
 if ((longint(seg(mix))*16+longint(ofs(mix))) and $FFFF)+
    longint(blocksize) > $0000FFFF then mixalku:=blocksize else
    mixalku:=0;

 if ((longint(seg(mix))*16+longint(ofs(mix)+mixalku)) and $FFFF)+
    longint(blocksize) > $0000FFFF then begin
     writeln('error locating DMA-buffer. press any key.');
     cha:=readkey;
    end;

 for i:=0 to 64 do
  for l:=-128 to 127 do begin
   t:=i*l div 64;
   if t<-128 then t:=-128 else
   if t>127 then t:=127;
   imultable[i][byte(l)-128]:=shortint(t);
  end;

 for c:=1 to 32 do fillchar(channel[c],sizeof(channel[c]),0);

 if resetdsp((base-$200) div $10,10) then;
 if resetdsp((base-$200) div $10,10) then;

 if irq<=7 then airq:=irq+$08 else airq:=$70+irq-$08;
 if irq<=7 then pic:=$21 else pic:=$A1;
 istom:=1 shl (irq mod 8);
 istam:=not(istom);
 dstam:=dma;
 dstom:=dstam or $04;
 case dma of
  0:pageport:=$87;
  1:pageport:=$83;
  2:pageport:=$81;
  3:pageport:=$82;
 end;
 vuoro:=0;
 interrupts:=0;

 asm cli; cli; end;
 port[pic]:=port[pic] or istom;
 oldclk:=getintvek(airq);
 setintvek(airq,@mixer);

 koee:=port[base+$E];
 port[$20]:=$20;
 if irq>7 then port[$A0]:=$20;

 port[pic]:=port[pic] and istam;
 asm sti; sti; end;

 speakeroff;
 dmastop;

 speakeron;
 playspeed:=setfreq(playspeed);
 fillchar(mix,sizeof(mix),0);

 playback(ptr(seg(mix),ofs(mix)),blocksize,dstam,dstom,pageport);
end;

procedure deinit; far;
begin
 asm cli; cli; end;
 if resetdsp((base-$200) div $10,10) then;
 if resetdsp((base-$200) div $10,10) then;
 port[pic]:=port[pic] or istom;
 setintvek(airq,oldclk);
 koee:=port[base+$E];
 dmastop;
 speakeroff;
 port[$0A]:=dstom;
 asm sti; sti; end;
end;

{$S-}
procedure playvoice(samplenro:byte; offset:longint; channa:byte);
begin
 asm pushf; cli; end;
 channel[channa].playing:=false;
 channel[channa].sample:=samplenro;
 channel[channa].fixed:=0;
 channel[channa].position:=offset;
 channel[channa].playing:=true;
 asm popf; end;
end;

{$S-}
procedure setplayfreq(c:byte; freq:longint);
begin
 asm pushf; cli; end;
 channel[c].freq:=freq;
 channel[c].faddh:=freq div longint(playspeed);
 channel[c].faddl:=word(longint(longint(longint(freq) mod longint(playspeed)) shl 16) div longint(playspeed));
 asm popf; end;
end;

{$S-}
procedure setamigafreq(chan:byte; period:word);
begin
 if period>0 then
  setplayfreq(chan,longint(14317056) div longint(period));
end;

{$S-}
procedure stopvoice(channa:byte);
begin
 asm pushf; cli; end;
 channel[channa].playing:=false;
 asm popf; end;
end;

{$S-}
procedure setvolume(chan:byte; volume:byte);
begin
 asm pushf; cli; end;
 channel[chan].volume:=volume;
 asm popf; end;
end;
[ RETURN TO DIRECTORY ]