home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip: Special Sound & MIDI
/
Chip-Special_Sound-und-Midi-auf-dem-PC.bin
/
dosprog
/
voc.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-11-21
|
29KB
|
774 lines
(***C*H*I*P***S*P*E*C*I*A*L**************************************************)
(* *)
(* Unit VOC: Sound-Wiedergabe über den digitalen Audiokanal per DMA *)
(* *)
(* (c) 1993 Rainer Reusch & Vogel Verlag München *)
(* *)
(* Turbo Pascal 7.0 *)
(* *)
(***V0.1*********************************************************************)
{
Die Unit bietet die Möglichkeit der Wiedergabe von Samples per DMA.
Während der Wiedergabe wird das Programm also nicht angehalten.
Die Unit erwartet die Environmentvariable "BLASTER" (zu setzen mit dem SET-
Befehl), damit eine Sound-Karte erkannt wird. Beispiel:
SET BLASTER=A220 I7 D1 T1
Aus dieser Variablen ermittelt die Unit die Basisportadresse, den Hardware-
Interrupt und den DMA-Kanal.
Die einzelnen Schritte für die Anwendung der Unit:
- SoundBoardInstalled (optional: Abfrage, ob Sound-Karte vorhanden)
- SetVolume (optional an jeder Programmstelle: Lautstärkeeinst.)
- LoadVOCFile (ein oder mehrere VOC-Sound-Dateien laden)
- GetMemVOCHandle (Alternative. Daten müssen manuell geladen werden.)
- PlaySound (Sound-Wiedergabe, beliebig oft)
- PauseSound (optional: Wiedergabe anhalten)
- RestartSound (optional: angehaltene Wiedergabe fortsetzen)
- StopSound (optional: Wiedergabe abbrechen)
- SoundPlaying (optional: Abfrage, ob Wiedergabe gerade läuft
- UnloadVOCFile (geladene Samples aus dem Speicher entfernen)
Jedem geladenen Sound ist ein Handle zugeordnet, den man über LoadVOCFile
oder GetMemVOCHandle erhält. Er wird bei PlaySound und UnloadVOCFile benötigt.
Die einzelnen Routinen dürfen auch aufgerufen werden, wenn keine Sound-Karte
installiert ist. Sie haben in diesem Fall keine Wirkung.
Hinweise:
- Beim Beenden des Programms muß der Programmierer dafür sorgen, daß eine
eventuell noch laufende Wiedergabe abgebrochen wird.
- Bei älteren Sound Blastern und dazu kompatiblen Karten funktioniert die
Lautstärkeeinstellung nicht (dort fehlt noch der Mixer).
- Für die Sample-Daten benötigt die Unit eine eigene Memory Page (wegen des
DMA-Transfer). Bei einem ausgiebig genutzten und stark fragmentierten Heap
kann es schon vorkommen, daß kein Speicher allokiert werden kann, obwohl
MaxAvail genügend anbietet. Wenn diese Gefahr besteht, sollte man sich
gleich am Anfang mit GetMemVOCHandle den nötigen Platz reservieren.
Besonderheiten der Unit:
- jeder 8-Bit-DMA-Kanal wird unterstützt (Kanäle 0..3)
- jeder Hardware-Interrupt wird unterstützt (IRQ 0..15)
- jede Abtastrate wird unterstützt
Die vorliegende Programmversion hat aber auch noch ein paar Einschränkungen:
- maximale Sample-Datengröße 65528 Byte
- nur umkomprimierte 8-bit-Samples in mono werden unterstützt
- die 16-Bit-DMA-Kanäle 4..7 dürfen nicht verwendet werden (wird nicht geprüft!);
- die Samples werden im knappen konventionellen Speicher gehalten
}
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+} { bei Vers. <7.0 überflüssige entfernen }
unit VOC;
interface
uses
Dos;
type
tHandle = record { Handle für Sample-Daten }
Buffer : pointer; { Zeiger auf Datenpuffer }
BufSize : word; { Größe des Puffers }
SR : byte; { SB-spezifischer Wert für Abtastrate }
end { record };
{ -------------------------------------------------------------------------- }
function SoundBoardInstalled : boolean;
{ -------------------------------------------------------------------------- }
{ Liefert true, wenn eine Sound-Karte gefunden wurde }
{ -------------------------------------------------------------------------- }
function LoadVOCFile(FileName : string; var Sample : tHandle) : boolean;
{ -------------------------------------------------------------------------- }
{ Laden von Voice-Daten aus einer VOC-Datei
Bedeutung der Parameter:
FileName: Dateiname, ggf. mit Pfad
Sample : Enthält Angaben zu den Voice-Daten
Funktionsergebnis:
true, wenn Ladeaktion erfolgreich
Die Routine hat in der vorliegenden Version folgende Einschränkungen:
- Es wird nur ein Datenblock und nur der Typ 1 ausgewertet.
- Es werden maximal 65528 Byte geladen.
- Nur 8-Bit-Samples in mono werden unterstützt. }
{ -------------------------------------------------------------------------- }
function GetMemVOCHandle(BufSize, SampleRate : word; var Sample : tHandle) : boolean;
{ -------------------------------------------------------------------------- }
{ Die Routine reserviert nur Speicher im Heap der gewünschten Größe BufSize
(max. 65528 Byte) und präpariert den Handle. Die Freigabe erfolgt ganz
normal mit UnloadVOCFile.
Das Funktionsergebnis ist true, wenn alle Parameter gültig und Aktion
erfolgreich. }
{ -------------------------------------------------------------------------- }
procedure SetVolume(Value : byte);
{ -------------------------------------------------------------------------- }
{ Lautstärke des Voice-Kanals einstellen
Value = 0..255, wird auf 4 Bit reduziert
Wert wird für linken und rechten Kanal gesetzt.
Funktioniert leider nicht auf jeder kompatiblen Karte. }
{ -------------------------------------------------------------------------- }
function PlaySound(var Sample : tHandle) : boolean;
{ -------------------------------------------------------------------------- }
{ Sound-Wiedergabe starten
Funktionsergebnis true, wenn Aktion erfolgreich.
Nur ein Sound kann zu einem bestimmten Zeitpunkt wiedergegeben werden. }
{ -------------------------------------------------------------------------- }
function PauseSound : boolean;
{ -------------------------------------------------------------------------- }
{ Sound-Wiedergabe anhalten
Funktionsergebnis true, wenn laufende Wiedergabe erfolgreich angehalten. }
{ -------------------------------------------------------------------------- }
function RestartSound : boolean;
{ -------------------------------------------------------------------------- }
{ Angehaltene Sound-Wiedergabe fortsetzen
Funktionsergebnis true, wenn Aktion erfolgreich. }
{ -------------------------------------------------------------------------- }
function StopSound : boolean;
{ -------------------------------------------------------------------------- }
{ Laufende Sound-Wiedergabe abbrechen
Funktionsergebnis true, wenn laufende Wiedergabe erfolgreich gestoppt. }
{ -------------------------------------------------------------------------- }
function SoundPlaying : boolean;
{ -------------------------------------------------------------------------- }
{ Abfrage, ob im Moment eine Sound-Wiedergabe läuft.
Funktionergebnis true, wenn ja (auch wenn pausierend). }
{ -------------------------------------------------------------------------- }
procedure UnloadVOCFile(var Sample : tHandle);
{ -------------------------------------------------------------------------- }
{ Speicher, welcher durch Sample-Daten belegt wurde, freigeben.
Der Handle darf für eine Wiedergabe nicht mehr verwendet werden. }
implementation
const
SoundBoardAvailable : boolean = false; { true, wenn Soundkarte installiert }
IsPlaying : boolean = false; { true, wenn Wiedergabe läuft }
IsPaused : boolean = false; { true, wenn Wiedergabe angehalten }
{ Indizes für Sound-Blaster-Register }
SB_MixReg = $04; { Mixer Registerselektion (0/W) }
SB_MixData= $05; { Mixer Registerzugriff (R/W) }
SB_Reset = $06; { DSP-Initialisierung (0/W) }
SB_Data = $0A; { DSP-Datenregister (R/0) }
SB_Write = $0C; { DSP-Befehlsregister (R/W) }
SB_Status = $0E; { DSP-Statusregister (R/0) }
Ready : boolean = false;
type
{ Sound-Kartenparameter
(Reihenfolge nicht ändern, nichts einfügen, neue Parameter nur anhängen!) }
tBoardParams = record
PortAdr, { Portadresse }
IRQ, { Hardware-Interrupt }
DMA, { DMA-Kanal }
BoardType : word; { Kartentyp }
end { record };
var
Board : tBoardParams; { Sound-Karten-Parameter }
OrgInt : pointer; { für internen Gebrauch }
{ -------------------------------------------------------------------------- }
function SoundBoardInstalled : boolean;
{ -------------------------------------------------------------------------- }
{ Liefert true, wenn eine Sound-Karte gefunden wurde }
begin
SoundBoardInstalled:=SoundBoardAvailable;
end { SoundBoardInstalled };
{ -------------------------------------------------------------------------- }
function GetBoardParams(var BoardParams : tBoardParams) : boolean;
{ -------------------------------------------------------------------------- }
{ Diese Funktion sucht nach der Environmentvariablen "BLASTER" und ermittelt
daraus die Sound-Kartenkonfiguration. Das Funktionsergebnis ist true, wenn
die Variable gefunden wurde und alle vier Parameter (siehe Typvereinbarung
tBoardParams) angegeben sind. }
function GetParamValue(var ParamLine : string; ParamCode : char;
var Value : word; IsHex : boolean) : boolean;
{ Ermittelt den Parameter aus einem String. Ergebnis true, wenn gefunden.
Value bleibt unverändert, wenn nicht gefunden. IsHex=true: Parameter ist
als Hexzahl aufzufassen. }
var
p : byte;
ss : string[5];
v : word;
e : integer;
begin
p:=Pos(ParamCode,ParamLine);
if p>0 then
begin { gewünschter Parameter gefunden }
GetParamValue:=true;
ss:=copy(ParamLine,p+1,5); { Ziffernstring extrahieren }
p:=Pos(#$20,ss);
if p>0 then ss[0]:=chr(p-1);
if IsHex then
begin { Parameter ist als Hexzahl aufzufassen }
if length(ss)>0 then
begin
v:=0;
e:=0;
for p:=1 to length(ss) do
begin
v:=v shl 4;
if (ss[p]>='0') and (ss[p]<='9') then v:=v+ord(ss[p])-48
else
if (ss[p]>='A') and (ss[p]<='F') then v:=v+ord(ss[p])-55
else inc(e);
end;
end
else GetParamValue:=false;
end
else val(ss,v,e); { Parameter ist als Dezimalzahl aufzufassen }
if e=0 then Value:=v
else GetParamValue:=false;
end
else GetParamValue:=false;
end { GetParamValue };
const
VarName = 'BLASTER'; { Name der zu suchenden Environmentvariablen }
var
Params : string[62];
Result : boolean;
begin
Params:=GetEnv(VarName);
Result:=GetParamValue(Params,'A',BoardParams.PortAdr,true); { Basisadresse }
Result:=Result and GetParamValue(Params,'I',BoardParams.IRQ,false); { Interrupt }
Result:=Result and GetParamValue(Params,'D',BoardParams.DMA,false); { DMA-Kanal }
Result:=Result and GetParamValue(Params,'T',BoardParams.BoardType,false); { Kartentyp }
GetBoardParams:=Result;
end { GetBoardParams };
{ -------------------------------------------------------------------------- }
function GetMemBuffer(MemSize : word) : pointer;
{ -------------------------------------------------------------------------- }
{ Speicher der Größe MemSize (max. 65528 Byte) an einer Segmentgrenze
(z.B. 6000h:0000h) für DMA-Transfer allokieren. Schlägt der Versuch fehl,
ist das Funktionsergebnis nil.
Die Freigabe des Speichers erfolgt ganz normal mit FreeMem. }
type
tPtr = record
case integer of
0 : (p : pointer);
1 : (Ofs_, Seg_ : word);
end { record };
var
Dummy, Result : tPtr;
a, d : longint;
begin
Result.p:=nil;
GetMem(Dummy.p,MemSize);
if (Dummy.Ofs_<>0) or ((Dummy.Seg_ and $0FFF)<>0) then
begin { Zeiger liegt nicht auf Segmentgrenze }
Result.Seg_:=(Dummy.Seg_ and $8000)+$1000; { benötigter Zeigerwert }
Result.Ofs_:=0;
a:=16*longint(Dummy.Seg_)+Dummy.Ofs_; { lineare phys. Adresse }
d:=16*longint(Result.Seg_)-a; { erforderliche Größe der Hilfsvariablen }
FreeMem(Dummy.p,MemSize);
GetMem(Dummy.p,word(d)); { Füller }
GetMem(Result.p,MemSize); { Speicher an Segmentgrenze allokieren }
FreeMem(Dummy.p,word(d)); { den Füller wieder freigeben }
end
else Result.p:=Dummy.p; { Zeiger liegt zufällig schon auf Segmentgrenze }
{ zur Sicherheit wird alles nochmal geprüft }
if ((Result.Seg_ and $0FFF)<>0) or (Result.Ofs_<>0) then Result.p:=nil;
GetMemBuffer:=Result.p;
end { GetMemBuffer };
{ -------------------------------------------------------------------------- }
function LoadVOCFile(FileName : string; var Sample : tHandle) : boolean;
{ -------------------------------------------------------------------------- }
{ Laden von Voice-Daten aus einer VOC-Datei
Bedeutung der Parameter:
FileName: Dateiname, ggf. mit Pfad
Sample : Enthält Angaben zu den Voice-Daten
Funktionsergebnis:
true, wenn Ladeaktion erfolgreich
Die Routine hat in der vorliegenden Version folgende Einschränkungen:
- Es wird nur ein Datenblock und nur der Typ 1 ausgewertet.
- Es werden maximal 65528 Byte geladen.
- Nur 8-Bit-Samples in mono werden unterstützt. }
type
tHeader = record { Header einer VOC-Datei }
case integer of
0 : (IDText : array[0..19] of char; { Identifikationstext }
Data : word; { Index, wo die Daten beginnen }
Version : word; { Version }
cVers : word); { Version komplementär }
1 : (b : array[0..25] of byte);
end { record };
var
f : file of byte;
g : file;
i : longint;
m, n : byte;
w : word;
h : tHeader;
FilePtr : longint;
BlockType : byte;
BlockSize : longint;
Ready,
Closed,
Result : boolean;
function GetBlockSize : longint;
var
nn : byte;
rr : longint;
begin
read(f,nn); rr:=nn;
read(f,nn); rr:=rr+256*longint(nn);
read(f,nn); GetBlockSize:=rr+65536*longint(nn);
end { GetBlockSize };
begin
{ Voreinstellungen }
with Sample do
begin
Buffer:=nil;
BufSize:=0;
SR:=0;
end;
Result:=false;
{ Analyse }
if (length(FileName)>0) and SoundBoardAvailable then
begin
assign(f,FileName);
reset(f);
if IOResult=0 then
begin
Closed:=false;
{ Header einlesen }
seek(f,0);
for n:=0 to SizeOf(tHeader)-1 do read(f,h.b[n]);
for n:=0 to 19 do if h.IDText[n]=#$1A then h.IDText[n]:=#$00;
if h.IDText='Creative Voice File'+#0 then
begin { ID-Text deutet auf VOC-Datei hin }
FilePtr:=h.Data;
Ready:=false;
repeat
seek(f,FilePtr); { Dateizeiger auf Datenblock setzen }
read(f,BlockType);
case BlockType of
0 : Ready:=true; { Terminator }
1 : begin { Voice Data }
BlockSize:=GetBlockSize-2; { Blockgröße }
read(f,n); { Abtastrate }
read(f,m); { Format der Komprimierung }
if (BlockSize>0) and (n>0) and (m=0) then
begin
if BlockSize>65528 then Sample.BufSize:=65528
else Sample.BufSize:=BlockSize;
Sample.SR:=n;
Sample.Buffer:=GetMemBuffer(Sample.BufSize);
if Sample.Buffer<>nil then
begin { Speicher ist vorhanden }
close(f); Closed:=true;
assign(g,FileName);
reset(g,1);
seek(g,FilePtr+6);
BlockRead(g,Sample.Buffer^,Sample.BufSize,w);
if w=Sample.BufSize then Result:=true;
close(g);
end;
end;
Ready:=true;
end;
2 : FilePtr:=FilePtr+GetBlockSize+4;
3 : FilePtr:=FilePtr+7;
4 : FilePtr:=FilePtr+6;
5 : FilePtr:=FilePtr+GetBlockSize+4;
6 : FilePtr:=FilePtr+6;
7 : FilePtr:=FilePtr+6;
8 : Ready:=true;
9 : Ready:=true;
else Ready:=true;
end { case };
writeln;
until Ready or (IOResult<>0);
end;
if not Closed then close(f);
end;
end;
LoadVocFile:=Result;
end { LoadVOCFile };
{ -------------------------------------------------------------------------- }
function GetMemVOCHandle(BufSize, SampleRate : word; var Sample : tHandle) : boolean;
{ -------------------------------------------------------------------------- }
{ Die Routine reserviert nur Speicher im Heap der gewünschten Größe BufSize
(max. 65528 Byte) und präpariert den Handle. Die Freigabe erfolgt ganz
normal mit UnloadVOCFile.
Das Funktionsergebnis ist true, wenn alle Parameter gültig und Aktion
erfolgreich. }
begin
GetMemVOCHandle:=false;
if (BufSize>0) and (BufSize<65529) and (SampleRate>0) and SoundBoardAvailable then
begin
Sample.Buffer:=GetMemBuffer(BufSize);
if Sample.Buffer<>nil then
begin
Sample.BufSize:=BufSize;
Sample.SR:=256 - 1000000 div SampleRate;
GetMemVOCHandle:=true;
end;
end;
end;
{ -------------------------------------------------------------------------- }
function SBInit(var BoardParams : tBoardParams) : boolean; assembler;
{ -------------------------------------------------------------------------- }
{ DSP der Sound Blaster initialisieren
Funktionsergebnis true, wenn Aktion erfolgreich. }
asm
push es
les bx,BoardParams { Adresse der Kartenparameter in ES:BX }
mov cx,es:[bx] { 1. Record-Variable (hier PortAdr) in CX }
mov dx,cx { und CX }
add dx,SB_Reset { Index für Reset-Register dazuaddieren }
mov al,1 { eine "1" auf Reset-Register ausgeben }
out dx,al
xor al,al { ein bißchen warten (mind. 3µs) }
@1:
nop
dec al
jnz @1
out dx,al { eine "0" auf Reset-Register ausgeben }
mov ax,2000h { nochmal ein bißchen warten }
@2:
nop
dec ax
jnz @2
mov dx,cx { Status ermitteln }
add dx,SB_Status
in al,dx
test al,80h { Bit 7 gesetzt? }
jz @NotOk { Sprung, wenn nein }
mov dx,cx { zusätzliche Prüfung }
add dx,SB_Data { aus dem DSP-Datenregister muß AAh gelesen werden }
in al,dx
cmp al,0AAh
jne @NotOk
mov ax,1 { Funktionsergebnis true }
jmp @Ready
@NotOk:
xor ax,ax { Funktionsergebnis false }
@Ready:
pop es
end { SBInit };
{ -------------------------------------------------------------------------- }
procedure SBWrite(PortAdr : word; Data : byte); assembler;
{ -------------------------------------------------------------------------- }
{ Übergabe eines Kommando- oder Datenbytes an DSP }
asm
mov dx,PortAdr { Basisadresse der Sound-Karte }
add dx,SB_Write { Index für Ausgaberegister hinzuaddieren }
@1:
in al,dx { Prüfen, ob der DSP zur Datenaufnahme bereits ist }
and al,80h
jnz @1
mov al,[Data] { Kommando bzw. Datenbyte ausgeben }
out dx,al
end { SBWrite };
{ -------------------------------------------------------------------------- }
procedure SetIntProc(var BoardParams : tBoardParams; IntProc : pointer);
{ -------------------------------------------------------------------------- }
{ Interruptroutine anhand des eingestellten IRQ's festlegen
Der Originalvektor wird in der globalen Variablen OrgInt festgehalten. }
begin
with BoardParams do
begin
if IRQ<8 then
begin { IRQ 0..7 --> Int 8..15 }
GetIntVec(IRQ+$08,OrgInt);
SetIntVec(IRQ+$08,IntProc);
Port[$21]:=Port[$21] and not(1 shl IRQ); { IRQ aktivieren (Master PIC) }
end
else
begin { IRQ 8..15 --> Int 112..119 (AT) }
GetIntVec(IRQ+$68,OrgInt);
SetIntVec(IRQ+$68,IntProc);
Port[$A1]:=Port[$A1] and not(1 shl (IRQ-8)); { IRQ aktivieren (Slave PIC) }
end;
end;
end { SetIntProc };
{ -------------------------------------------------------------------------- }
procedure RestoreIntProc(var BoardParams : tBoardParams);
{ -------------------------------------------------------------------------- }
{ Originalen Interruptvektor wieder setzen
Inhalt von OrgInt wird verwendet. SetIntProc muß daher vorher aufgerufen
worden sein! }
begin
with BoardParams do
begin
if IRQ<8 then
begin
SetIntVec(IRQ+$08,OrgInt); { IRQ 0..7 --> Int 8..15 }
Port[$21]:=Port[$21] or (1 shl IRQ); { IRQ sperren }
end
else
begin
SetIntVec(IRQ+$68,OrgInt); { IRQ 8..15 --> Int 112..119 (AT) }
Port[$A1]:=Port[$A1] or (1 shl (IRQ-8)); { IRQ sperren }
end;
end;
end { RestoreIntProc };
{$F+}
{ -------------------------------------------------------------------------- }
procedure SndIntProc; interrupt;
{ -------------------------------------------------------------------------- }
{ Interruptroutine
Wird automatisch aufgerufen, wenn Sound-Wiedergabe beendet ist. }
var
Status : byte;
begin
Status:=Port[Board.PortAdr+SB_Status]; { Int-Bestätigung für DSP }
Port[$20]:=$20; { EOI an Master-PIC }
Port[$A0]:=$20; { EOI an Slave-PIC }
SBWrite(Board.PortAdr,$D3); { Lautsprecher ausschalten }
RestoreIntProc(Board); { Interruptvektor restaurieren }
IsPlaying:=false; { Mitteilung nach Außen, daß DMA-Transfer abgeschlossen ist }
end { SndIntProc };
{$F-}
{ -------------------------------------------------------------------------- }
procedure InitDMA(var BoardParams : tBoardParams;
Buffer : pointer; BufSize : word);
{ -------------------------------------------------------------------------- }
{ DMA für Sound-Wiedergabe vorbereiten
Buffer MUSS auf den Anfang einer Memory Page (z.B. $7000:$0000) zeigen. }
type
tPtr = record
case integer of
0 : (p : pointer);
1 : (Ofs_, Seg_ : word);
end { record };
var
b : tPtr;
x : byte;
begin
with BoardParams do
begin
Port[$0A]:=$04+DMA; { DMA-Kanal (0..3) deaktivieren }
Port[$0C]:=$00; { Flip-Flop f. 16-Reg. zurücksetzen }
Port[$0B]:=$48+DMA; { Modus für entsprechenden Kanal }
Port[DMA shl 1]:=$00; { LoByte Adreßregister (Offset) }
Port[DMA shl 1]:=$00; { HiByte Adreßregister (Offset) }
dec(BufSize);
Port[(DMA shl 1)+1]:=Lo(BufSize); { LoByte Datenpuffergröße }
Port[(DMA shl 1)+1]:=Hi(BufSize); { HiByte Datenpuffergröße }
b.p:=Buffer; { physikalische Speicherseite }
case DMA of
0 : x:=$87; { Page-Register-Portadresse für Kanal 0 }
1 : x:=$83; { Page-Register-Portadresse für Kanal 1 }
2 : x:=$81; { Page-Register-Portadresse für Kanal 2 }
3 : x:=$82; { Page-Register-Portadresse für Kanal 3 }
end { case };
Port[x]:=b.Seg_ shr 12;
Port[$0A]:=DMA; { DMA-Kanal (0..3) aktivieren }
Port[$08]:=$10; { DMA-Controller aktivieren (zur Sicherheit) }
end;
end { InitDMA };
{ -------------------------------------------------------------------------- }
procedure SetVolume(Value : byte);
{ -------------------------------------------------------------------------- }
{ Lautstärke des Voice-Kanals einstellen
Value = 0..255, wird auf 4 Bit reduziert
Wert wird für linken und rechten Kanal gesetzt.
Funktioniert leider nicht auf jeder kompatiblen Karte. }
begin
with Board do
begin
Value:=Value shr 4; { nur 16 Laustärkestufen möglich }
Value:=(Value shl 4)+Value; { für beide Kanäle das Gleiche }
Port[PortAdr+SB_MixReg]:=$04; { gewünschtes Mixer-Register (hier: Voice Volume) }
Port[PortAdr+SB_MixData]:=Value;{ gewünschte Lautstärke setzen }
end;
end { SetVolume };
{ -------------------------------------------------------------------------- }
function PlaySound(var Sample : tHandle) : boolean;
{ -------------------------------------------------------------------------- }
{ Sound-Wiedergabe starten
Funktionsergebnis true, wenn Aktion erfolgreich }
var
w : word;
begin
PlaySound:=false;
if SoundBoardAvailable and (Sample.Buffer<>nil) and (Sample.BufSize>0)
and (not IsPlaying) then
begin { Voraussetzungen für Wiedergabe erfüllt }
if SBInit(Board) then
begin { Initialisierung des DSP ok }
SetIntProc(Board,@SndIntProc); { Int-Routine setzen }
SBWrite(Board.PortAdr,$D1); { Lautsprecher einschalten }
SBWrite(Board.PortAdr,$40); { Abtastrate einstellen }
SBWrite(Board.PortAdr,Sample.SR);
InitDMA(Board,Sample.Buffer,Sample.BufSize); { DMA vorbereiten }
w:=Sample.BufSize-1;
SBWrite(Board.PortAdr,$14); { normaler 8-Bit-DMA }
SBWrite(Board.PortAdr,Lo(w)); { LoByte Datengröße }
SBWrite(Board.PortAdr,Hi(w)); { HiByte Datengröße }
IsPlaying:=true;
PlaySound:=true;
end;
end;
end { PlaySound };
{ -------------------------------------------------------------------------- }
function PauseSound : boolean;
{ -------------------------------------------------------------------------- }
{ Sound-Wiedergabe anhalten
Funktionsergebnis true, wenn laufende Wiedergabe erfolgreich angehalten. }
begin
PauseSound:=false;
if IsPlaying and (not IsPaused) then
begin
SBWrite(Board.PortAdr,$D0); { DMA-Transfer anhalten }
IsPaused:=true;
PauseSound:=true;
end;
end { PauseSound };
{ -------------------------------------------------------------------------- }
function RestartSound : boolean;
{ -------------------------------------------------------------------------- }
{ Angehaltene Sound-Wiedergabe fortsetzen
Funktionsergebnis true, wenn Aktion erfolgreich. }
begin
RestartSound:=false;
if IsPlaying and IsPaused then
begin
SBWrite(Board.PortAdr,$D4); { DMA-Transfer fortsetzen }
IsPaused:=false;
RestartSound:=true;
end;
end { RestartSound };
{ -------------------------------------------------------------------------- }
function StopSound : boolean;
{ -------------------------------------------------------------------------- }
{ Laufende Sound-Wiedergabe abbrechen
Funktionsergebnis true, wenn laufende Wiedergabe erfolgreich gestoppt. }
begin
StopSound:=false;
if IsPlaying then
begin
SBWrite(Board.PortAdr,$D0); { DMA-Transfer anhalten }
SBWrite(Board.PortAdr,$D3); { Lautsprecher ausschalten }
RestoreIntProc(Board); { Interruptvektor restaurieren }
SBInit(Board); { DSP initialisieren }
IsPlaying:=false;
IsPaused:=false;
StopSound:=true;
end;
end { StopSound };
{ -------------------------------------------------------------------------- }
function SoundPlaying : boolean;
{ -------------------------------------------------------------------------- }
{ Abfrage, ob im Moment eine Sound-Wiedergabe läuft.
Funktionergebnis true, wenn ja (auch wenn pausierend). }
begin
SoundPlaying:=IsPlaying;
end { SoundPlaying };
{ -------------------------------------------------------------------------- }
procedure UnloadVOCFile(var Sample : tHandle);
{ -------------------------------------------------------------------------- }
{ Speicher, welcher durch Sample-Daten belegt wurde, freigeben }
begin
if SoundBoardAvailable then
with Sample do
if (Buffer<>nil) and (BufSize>0) then
begin
FreeMem(Buffer,BufSize);
Buffer:=nil;
BufSize:=0;
SR:=0;
end;
end { UnloadVOCFile };
begin { Hauptprogramm }
SoundBoardAvailable:=GetBoardParams(Board); { Prüfung, ob Soundkarte installiert }
end { Unit VOC }.