habe hier leider 2 kleinere Probleme mit dem Soundblaster:
1. Ich bekomme den Autoinitmode nicht richtig zum laufen (die Beispiele die ich im Netz gefunden habe hatten auch nur den Singlemode genutzt und dann jedes mal die Karte neu Programmiert - für mich unpraktisch)
2. Wie codiere ich Creative's 8bit zu 4 Bit ADPCM? Dazu habe ich leider auch nichts im Netz gefunden und die gängigen ADPCM Codecs arbeiten mit 16 zu 4 Bit, was dem Sound auf der Soundblaster nicht gerade zu gute kommt.
____________________________________________________________________________
Hier erstmal die Unit:
Die kann nur 8Bit, 8khz Dateien abspielen - mehr soll sie auch nicht können (evtl. mal 11-16khz wenn ADPCM läuft)
Es gibt eine kleine Besonderheit: Der Int der Soundkarte wird auch als ~30 Ints/s Taktgeber genutzt - deshalb auch die funktion PlaySilence, damit es eben auch bei Stille noch einen Takt gibt.
Das Problem ist: aktuell läuft alles klaglos durch, aber die Interruptroutine wird nicht aufgerufen. (auch nicht wenn ich beim IRQ +8 hinschreibe wie in einigen Beispielen)
Code: Alles auswählen
Unit SB_Unit;
interface
var clock:boolean;
procedure SB_Set(Base_Addr:word;IRQ,DMA:byte);
function SB_PlayFile(F_Name:String;Continuos:boolean):boolean;
function SB_PlaySilence:boolean;
procedure SB_Stop;
implementation
uses Dos;
type S_Buffer=array[0..32767]of byte;
type S_Chunk=array[0..8191]of byte;
type S_BufferChunk=array[0..3]of S_Chunk;{Nutzung des Soundinterrupts als Tmer ~31ips}
type S_BufferPTR=^S_Buffer;
type S_BufferChunkPTR=^S_BufferChunk;
const SB_Base:word=$220;
const SB_IRQ: byte= 7;
const SB_DMA: byte= 1;
const SB_FileEnd: boolean=false;
const SB_FilePlaying: boolean=false;
const SB_ContinuosPlay:boolean=false;
const SB_Run: boolean=false;
var SB_File:file;
var SB_BufferPos:byte;
var SB_BufferClock:byte;
const SB_Buffer:S_BufferPTR=nil;
var SB_BufferChunk:S_BufferChunkPTR absolute SB_Buffer;
var SB_InitTest:byte;
var SB_OldInt:procedure;
procedure SB_ServiceIRQ; interrupt;
var Temp:Byte; Result:word;
begin
writeln('IRQ'); {debug}
Temp := Port [SB_Base+$E]; {Relieve DSP}
Port [$20] := $20; {Acknowledge hardware interrupt}
if SB_IRQ >7 then Port [$A0] := $20; {Überarbeiten IRQ 2}
inc(SB_BufferClock);
if SB_BufferClock>31 then
begin
FillChar(SB_BufferChunk^[SB_BufferPos],8192,128);
if SB_FilePlaying then
begin
BlockRead(SB_File,SB_BufferChunk^[SB_BufferPos],8192, Result);
if Result<8192 then if SB_ContinuosPlay then seek(SB_File,48) else SB_FileEnd:=true;
end;
SB_BufferClock:=0;
SB_BufferPos:=(SB_BufferPos+1)and 3;
end;
clock:=true;
end;
procedure SB_WriteDSP(Value : byte);
begin
{Wait for the DSP to be ready to accept data}
while Port[SB_Base+$0C] and $80 <> 0 do;
{Send byte}
Port[SB_Base+$0C] := value;
end;
procedure SB_InitTimer;interrupt;
begin;
inc(SB_InitTest);
SB_OldInt;
end;
function SB_Init:boolean;
begin
{Starte DSP Reset und Überprüfe auf gelingen}
SB_InitTest:=0;
GetIntVec($1C,@SB_OldInt);
SetIntVec($1C,@SB_InitTimer);
Port[SB_Base+$06]:=$01;
repeat;until SB_InitTest=2;
Port[SB_Base+$06]:=$00;
SB_InitTest:=0;
repeat;until SB_InitTest=2;
if (Port[SB_Base+$0E] and $80=$80)and(Port[SB_Base+$0A]=$AA) then
SB_Init:=true else SB_Init:=false;
SetIntVec($1C,@SB_OldInt);
end;
procedure SB_Set(Base_Addr:word;IRQ,DMA:byte);
begin;SB_Base:=Base_Addr;SB_IRQ:=IRQ;SB_DMA:=DMA;end;
procedure SB_CreateSoundbuffer;
var wastesize:word;var waste:Pointer;
begin
{Buffer an Seitengrenze ausrichten für DMA}
new(SB_Buffer);
wastesize:=(($0FFF and seg(SB_Buffer^))shl 4)+Ofs(SB_Buffer^);
if wastesize>$8000 then begin
wastesize:=$FFFF-wastesize;
inc(wastesize);
dispose(SB_Buffer);
getmem(waste,wastesize);
new(SB_Buffer);
freemem(waste,wastesize); {wastesize aufbewahren für weitere Speicherreservierungen?}
FillChar(SB_Buffer^,32768,128); {mit Stille Füllen}
end;
{/Buffer an Seitengrenze ausrichten}
end;
procedure SB_Start;
var dmapage:byte;Size,Offset:word;
begin
SB_WriteDSP($D3); {Disable Speaker}
SB_WriteDSP($D1); {Enable Speaker}
{Init DMA}
dmapage:=hi(seg(SB_Buffer^)shr 4);
Port[$0A]:= $04 or SB_DMA; {Mask Channel (Disable Channel)}
Port[$0C]:=0; {Clear byte pointer}
Port[$0B]:=$58 or +SB_DMA; {Set Mode}
{01XX XXXX 00 Demand Mode, 01 Single Mode, 10 Block Mode, 11 Cascade Mode
XX0X XXXX 0 address increment/1 Address decrement
XXX1 XXXX 1 Autoinit
XXXX 10XX 00 Verify, 01 Write, 10 Readmode
XXXX XXYY - YY=DMA Channel}
{Write Offset to DMA Controller}
Offset:=(seg(SB_Buffer^)shl 4)+Ofs(SB_buffer^);
Port[(SB_DMA shl 1)]:=Lo(Offset);
Port[(SB_DMA shl 1)]:=Hi(Offset);
{Write length of buffer}
size:=sizeof(SB_Buffer^)-1;
Port[(SB_DMA shl 1)+1]:=$FF; {Lo(Length-1)}
Port[(SB_DMA shl 1)+1]:=$7F; {Hi(Length-1)}
{Write the Page to the DMA Controller}
case SB_DMA of
0:port[$87]:=dmapage;
1:port[$83]:=dmapage;
2:port[$81]:=dmapage;
3:port[$82]:=dmapage;
end;
{unmask DMA}
Port[$0A]:=SB_DMA; {Enable DMA}
{/InitDMA}
{start}
SB_BufferClock:=0;
SB_BufferPos:=0;
SB_FilePlaying:=false;
SB_Run:=true;
FillChar(SB_Buffer^,32768,128);
GetIntVec(SB_IRQ,@SB_OldInt);
SetIntVec(SB_IRQ,@SB_ServiceIRQ);
Port[$21]:=Port[$21]and not (1 shl SB_IRQ);
SB_WriteDSP($40); {set time constant}
SB_WriteDSP(131); {256-1.000.000/Samplingrate}
SB_WriteDSP($48); {Set Block Length}
SB_WriteDSP($FF); {Set Block Length to 256 -> about 30 Int/s -> Timerinterrupt}
SB_WriteDSP($00);
SB_WriteDSP($1C); {Start Playback}
end;
function SB_PlaySilence:boolean;
begin
if SB_Run then
begin;
SB_FilePlaying:=false;
FillChar(SB_Buffer^,32768,128);
seek(SB_File,0);
if IoResult=0 then close(SB_File);
end else
if SB_Init then
begin;
SB_FileEnd:=false;
SB_ContinuosPlay:=false;
SB_FilePlaying:=false;
SB_PlaySilence:=true;
SB_CreateSoundBuffer;
SB_Start;
end else SB_PlaySilence:=False;
end;
function SB_PlayFile(F_Name:String;Continuos:boolean):boolean; var Result:word; {debug}
begin
If SB_PlaySilence then
begin
assign(SB_File,F_Name);
reset(SB_File,1); {RecSize=1Byte, wichtig für Blockread}
if IoResult=0 then
begin;
seek(SB_File,46);
if IoResult=0 then
begin;
BlockRead(SB_File,SB_Buffer^,32768, Result); {Debug}
writeln('Result: ', Result); {debug}
SB_ContinuosPlay:=Continuos;
SB_FilePlaying:=true;
SB_FileEnd:=false;
SB_PlayFile:=true;
end else SB_PlayFile:=False
end else SB_PlayFile:=False;
end else SB_Playfile:=False;
end;
procedure SB_Stop;
begin
SB_FileEnd:=false;
SB_ContinuosPlay:=false;
SB_FilePlaying:=false;
close(SB_File);
{Stop DMA}
SB_WriteDSP($D0);
SB_WriteDSP($DA);
SetIntVec(SB_IRQ,@SB_OldInt);
if SB_Buffer<>nil then dispose(SB_Buffer);
end;
end.
Es spielt ersteinmal Stille - bereits dabei sollte der Bildschirm mit der (Debug-) Meldung IRQ überflutet werden
Als nächstes spielt es eine Datei (Test.wav - 8khz, 8Bit) einmal ab-
Und zu guter letzt diese Datei nochmal in Dauerschleife.
stattdessen spielts nur den 32k Puffer in Dauerschleife ab.
Wenn bei euch die Soundkarte nicht auf 220,7,1 liegt, solltet ihr noch die
"procedure SB_Set(Base_Addr:word;IRQ,DMA:byte);" aufrufen.
Code: Alles auswählen
uses crt,sb_unit;
var w:char;
begin
w:=readkey;
writeln('Playing Silence');
writeln(SB_PlaySilence);
w:=readkey;
writeln('Playing Test.wav once');
writeln(SB_PlayFile('Test.wav',false));
w:=readkey;
writeln('Playing Test.wav continuos');
writeln(SB_PlayFile('Test.wav',true));
w:=readkey;
SB_Stop;
end.