Hallo DPler,
ich weiß, dass es mittlerweile einige Themen zu Bass gibt, aber mein Anliegen ist eigentlich viel zu simpel,
um jetzt den Code aus anderen Themen auseinanderzufrickeln. Nicht zuletzt auch deshalb, weil ich mich nicht
so gut den Basics wie Speicherfreigabe etc. auskenne. Aber vielleicht habt ihr ja trotzdem Lust mir zu helfen.
Die gesucht Prozedur soll über die Angabe eines Dateinamens und einer Abtastrate (bspw. 40ms = 25fps)
ein Array of Float (0 bis 1) ausgeben. Dabei ist im ersten Schritt nur die Lautstärke-Amplitude beider Kanäle
zum gefragten Zeitpunkt (0, 40, 80 ms ...) wichtig. Um das
RAM nicht vollzumüllen, langt es prinzipiell ja
die Sounddatei zu laden/analysieren/freizugeben. Da mir jedoch, wie oben beschrieben, die Basics zur
sauberen Programmierung fehlen, soll die Prozedur/Funktion ihre Aufgabe möglichst elegant und ohne viel
Schnickschnack verrichten.
Diese Prozedur brauche ich für mein Programm "Animus", dass verschiedene Parameterwerte animieren kann.
Wer Interesse hat kann sich hier einen
Screencast (30MB) dazu ansehen.
(Mein Programm ist eine
GUI für einen
Konsolen-Renderer)
Vielen Dank schonmal!
EDIT: okay, so ganz ohne Eigeninitiative solls natürlich
nicht sein
Delphi-Quellcode:
procedure Sound2FloatArray(filename:
String; MS: Byte;
var Left, Right:
array of Float);
var //Dateiname; Abtastrate; Ausgabe-Arrays
wavebufL, wavebufR:
Array of smallInt;
Laenge, i: Integer;
begin
//init BASS
if not BASS_Init(-1,44100,0,Application.Handle,
nil)
then
ErrorPop('
Can''
t initialize device');
//creating stream
chan := BASS_StreamCreateFile(FALSE,pchar(filename),0,0,0
{$IFDEF UNICODE} or BASS_UNICODE
{$ENDIF});
if chan = 0
then
begin
chan := BASS_MusicLoad(False, pchar(filename), 0, 0, BASS_MUSIC_RAMPS
or BASS_MUSIC_POSRESET
or BASS_MUSIC_PRESCAN
{$IFDEF UNICODE} or BASS_UNICODE
{$ENDIF}, 0);
if (chan = 0)
then
begin
ErrorPop('
Can''
t play file');
Exit;
end;
end;
//jetzt nochmal das ganze für den zweiten Kanal?
//getting peak levels in seperate thread, stream handle as parameter
chan2 := BASS_StreamCreateFile(FALSE,pchar(filename),0,0,BASS_STREAM_DECODE
{$IFDEF UNICODE} or BASS_UNICODE
{$ENDIF});
if (chan2 = 0)
then chan2 := BASS_MusicLoad(FALSE,pchar(filename),0,0,BASS_MUSIC_DECODE
{$IFDEF UNICODE} or BASS_UNICODE
{$ENDIF},0);
TScanThread.Create(chan2);
// start scanning peaks in a new thread
//Wieviel Einträge im Array brauche ich?
Laenge := ???;
//set array size
setlength(wavebufL,Laenge);
setlength(wavebufR,Laenge);
setlength(Left,Laenge);
setlength(Right,Laenge);
//Die smallints zu Float 0 bis 1 wandeln
for i := 0
to Laenge-1
do
begin
Left[i] := wavebufL[i]/High(smallInt);
Right[i] := wavebufR[i]/High(smallInt);
end;
//BASS-Speicher freigeben
BASS_Free();
end;
{Sound2FloatArray}
// aus dem Beispiel custloop
procedure TForm1.ScanPeaks2(decoder : HSTREAM);
var
cpos,level : DWord;
peak :
array[0..1]
of DWORD;
position : DWORD;
counter : integer;
begin
cpos := 0;
peak[0] := 0;
peak[1] := 0;
counter := 0;
while not killscan
do
begin
level := BASS_ChannelGetLevel(decoder);
// scan peaks
if (peak[0]<LOWORD(level))
then
peak[0]:=LOWORD(level);
// set left peak
if (peak[1]<HIWORD(level))
then
peak[1]:=HIWORD(level);
// set right peak
if BASS_ChannelIsActive(decoder) <> BASS_ACTIVE_PLAYING
then
begin
position := cardinal(-1);
// reached the end
end else
position := BASS_ChannelGetPosition(decoder,BASS_POS_BYTE)
div bpp;
if position > cpos
then
begin
inc(counter);
if counter <= length(wavebufL)-1
then
begin
wavebufL[counter] := peak[0];
wavebufR[counter] := peak[1];
end;
if (position >= dword(ClientWidth))
then
break;
cpos := position;
end;
peak[0] := 0;
peak[1] := 0;
end;
BASS_StreamFree(decoder);
// free the decoder
end;
Ich habe (chaotischerweise) versucht aus dem BASS-Beispiel custloop die relevanten Befehle zu extrahieren.
Ist das alles, was ich brauche? Was ist zu viel, was fehlt unter Umständen?
Warum wird der zweite Channel anders als der erste Channel geholt?
Wie gesagt, ich möchte nichts abspielen, sondern nur ein bis zwei Arrays vom Typ Float füllen.