Einzelnen Beitrag anzeigen

aphexx

Registriert seit: 23. Apr 2010
19 Beiträge
 
#1

Prozedur: Sound zu Array of Float mittels BASS

  Alt 30. Mai 2010, 13:24
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.
  Mit Zitat antworten Zitat