Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Stille aus Wave-Dateien entfernen? (https://www.delphipraxis.net/135781-stille-aus-wave-dateien-entfernen.html)

Marco Steinebach 17. Jun 2009 22:46


Stille aus Wave-Dateien entfernen?
 
Hallo Zusammen,
ich bräuchte mal ein paar Tips wie ich es anstellen kann, eine Wave-Datei zu trimmen, will heißen, stille, am Anfang und Ende einer Wave-Datei rauszuschneiden. Das muß nicht supergenau sein, mir geht es um folgendes: Mein Benutzer drückt den Startknopf, sabbelt was ins Mikrophon, rappelt noch ein wenig, und drückt dann stopp. Das ergebnis soll eine Wave mit möglichst nur seinem gesabbel werden.
Meine Fragen:
Wie kann ich den Anfang bzw. das Ende einer Wave abschneiden? (gern mit BASS)
Wie kriege ich raus, ab wo das "gesabbel" anfängt und wo es aufhört? Mit der Lautsträrke, klar, aber ich find die Funktion ums verrecken nicht. *grummel!
Für Tips wäre ich sehr dankbar!
Einen freundlichen Gru´ß
Marco

SirThornberry 17. Jun 2009 22:59

Re: Stille aus Wave-Dateien entfernen?
 
stille ist eigentlich nur ein geringer Ausschlag. Du müsstest also nur alles Samples vom Anfang an durchgehen und schauen ab wann ein Sample den von dir definierten Minimalausschlag überschreitet.
Ich würde dazu einfach die Datei mit einem TStream (TFileStream) öffnen und dann entsprechend dem Header bis zu den WaveDaten navigieren. Dort Sample für Sample lesen und schauen wie groß der Ausschlag ist.

Marco Steinebach 18. Jun 2009 06:00

Re: Stille aus Wave-Dateien entfernen?
 
Zitat:

Zitat von SirThornberry
Ich würde dazu einfach die Datei mit einem TStream (TFileStream) öffnen und dann entsprechend dem Header bis zu den WaveDaten navigieren. Dort Sample für Sample lesen und schauen wie groß der Ausschlag ist.

Ja genau, okay, hinter den Header komm ich, ;-), aber woran sieht man, bei dem zahlensalat der dann folgt, wie groß der Ausschlag eines samples ist? Mir ist überhaupt nicht klar, wie ich aus den Wave-Daten was auslesen kann.
Dazu bräuchte ich bitte nochmal einen tip!
Viele Grüße
Marco

Florian H 18. Jun 2009 08:11

Re: Stille aus Wave-Dateien entfernen?
 
Du könntest eine FFT machen (mit BASS, Beispiele dazu gibts ja hundertfach hier im Forum) und dann den Ausschlag in verschiedenen Frequenzen Sample für Sample messen, bis eben eine Grenze überschritten wird. Dabei kannst du ja verwenden, dass gesprochene Sprache meist andere Frequenzen nutzt, als Umgebungsgeräusche oder das "rumgerappeln". Kannst du ja dann testen und entsprechend gewichten :)

Wishmaster 19. Jun 2009 11:32

Re: Stille aus Wave-Dateien entfernen?
 
Hi


Delphi-Quellcode:
function Channel_Get_SilenceLength_16Bit(FileName : String; Pinpoint : Boolean; Threshold : QWORD; var StartPoint, EndPoint : DWORD) : Bool; stdcall;
var
  a, b: Integer;
  pos, count, chan: DWORD;
  buf16: array[0..50000] of Smallint; // 100% OK.
  flag : DWORD;
begin
   result:= false;
   count := 0;
   flag:= BASS_STREAM_DECODE;    //BASS_STREAM_DECODE or BASS_STREAM_AUTOFREE

     if Pinpoint then
       flag:= flag or BASS_STREAM_PRESCAN;

     Chan:= BASS_StreamCreateFile(FALSE, PChar(FileName), 0, 0, Flag);
  if Chan = 0 then
     Chan:= BASS_MusicLoad(False, PChar(FileName), 0, 0, Flag or BASS_MUSIC_NOSAMPLE, 0);
  if Chan = 0 then
   Exit;

  while Bass_ChannelIsActive(Chan) <> 0 do
   begin
    b := BASS_ChannelGetData(Chan, @buf16, 20000);
    b := b div 2;
    a := 0;
    while (a < b) and (Abs(buf16[a]) <= Threshold) do
      a := a + 1;
      count := count + (a * 2);
    if (a < b) then
     begin
      while (a <> 0) and (Abs(buf16[a]) > (Threshold div 4)) do
       begin
        a := a - 1;
        count := count - 2;
      end;
      Break;
    end;
  end;
   StartPoint := count; // Start-Point ready

   pos := BASS_ChannelGetLength(Chan);
  while (pos > count) do
   begin
    if pos < 100000 then
      pos := 0
    else
      pos := pos - 100000;
    BASS_ChannelSetPosition(chan, pos);
    b := BASS_ChannelGetData(chan, @buf16, 100000);
    b := b div 2;
    a := b;
   while (a > 0) and (Abs(buf16[a - 1]) <= (Threshold div 2)) do
       a := a - 1;
    if a > 0 then
     begin
      count := pos + (a * 4);
      Break;
     end;
    end;
 EndPoint := Count;  // End-Point ready
 BASS_MusicFree(Chan);
 BASS_StreamFree(Chan);
 Result:= true;
end;


function Channel_Get_SilenceLength_32Bit(FileName : String; Pinpoint : Boolean; Threshold : QWORD; var StartPoint, EndPoint : DWORD) : boolean; stdcall;
var
  a, b: Integer;
  pos, count, chan: DWORD;
  buf32: array[0..50000] of Float;    //Single
  flag : DWORD;
begin
   Result:= false;

   Flag:=  BASS_STREAM_DECODE or BASS_SAMPLE_FLOAT;

  if Pinpoint then
   Flag:= Flag or BASS_STREAM_PRESCAN;


     Chan:= (BASS_StreamCreateFile(FALSE, PChar(FileName), 0, 0, Flag));
  if Chan = 0 then
     Chan:= BASS_MusicLoad(False, PChar(FileName), 0, 0, Flag or BASS_MUSIC_NOSAMPLE, 0);
  if Chan = 0 then
    Exit;

    count := 0;
  while Bass_ChannelIsActive(chan) <> 0 do
   begin
    b := BASS_ChannelGetData(chan, @buf32, 20000);
    b := b div 4;
    a := 0;
    while (a < b) and (Abs(buf32[a]) <= (Threshold / 32768)) do
      a := a + 1;
      count := count + (a * 4);
    if (a < b) then
     begin
      while (a <> 0) and (Abs(buf32[a]) > (Trunc(Threshold / 32768) div 4)) do
       begin
        a := a - 1;
        count := count - 2;
       end;
      Break;
     end;
    end;
     StartPoint := count; // Start-Point ready

    pos := BASS_ChannelGetLength(chan);
  while (pos > count) do
   begin
    if pos < 100000 then
      pos := 0         
    else
      pos := pos - 100000;                              
      BASS_ChannelSetPosition(chan, pos);
      b := BASS_ChannelGetData(chan, @buf32, 100000);
      b := b div 4; // 16Bit = 2 | 32Bit = 4
      a := b;
    while (a > 0) and (Abs(buf32[a - 1]) <= (Threshold div 2) / 32768) do
      a := a -1;
    if a > 0 then
     begin
      count := pos + (a * 8); //8=2
      Break;
    end;
  end;
  EndPoint := Count;  // End-Point ready
  BASS_MusicFree(Chan);
  BASS_StreamFree(chan);
  Result:= true;
end;

Marco Steinebach 20. Jun 2009 00:16

Re: Stille aus Wave-Dateien entfernen?
 
Hi Wishmaster,
Ganz herzlichen Dank für den Quellcode.
Mein Ansatz war, die Werte mittels BASS_ChannelGetLevel rauszufinden. Allerdings bin ich nicht auf die Idee gekommen, das ganze, für das Ende, rückwärts anzugehen, ich hab einfach mehrere Levels verglichen, und wenn’s 20 mal unterm threshold war, dann war schluß. ;-) Da ist deines natürlich um Längen besser.

Ich habe noch ein paar Fragen zum Code:
1. Wofür ist die möglichkeit des PreScan hier sinnvoll?
2. Warum vergleichst du auf Threshold div 2 bzw. threshold div 4?

Die Fragen, weil ich gerne verstehen würde, wie du es gemacht hast.

So, und damit man das Resultat auch als Wave-Datei hat, ;-), hier der Rest des Programms.
Kann man das evtl. noch verbessern?

Delphi-Quellcode:
procedure TMainForm.BStartClick(Sender: TObject);
const
  Buffersize = 1024;
var
  sh: HSTREAM; // sound handle
  eh: HENCODE; // encoder handle
  buf: array of byte;
  Startposition, Endposition: dWord;
begin
  SetLength (buf, BufferSize);
  BASS_init (-1, 44100, 0, application.handle, nil);
  if not Channel_Get_SilenceLength_16Bit ('Test.wav', true, 5000, Startposition, Endposition) then
  begin
    ErrorMsg ('Calculation of silence failed!');
    exit
  end;

  sh := BASS_StreamCreateFile (false, pChar('test.wav'), 0, 0, BASS_Stream_Decode);
  if sh = 0 then
  begin
    ErrorMsg ('Could not open input file.');
    exit
  end;

  BASS_ChannelSetPosition (sh, Startposition, BASS_POS_Byte);
  eh := BASS_Encode_Start (sh, pChar('test_silent.wav'), BASS_Encode_PCM + BASS_Encode_AutoFree, nil, nil);
  if eh = 0 then
  begin
    ErrorMsg ('Encoder not started.');
    BASS_StreamFree (sh);
    exit
  end;
  While BASS_ChannelIsActive (sh) <> BASS_ACTIVE_Stopped do
  begin
    BASS_ChannelGetData (sh, buf, Buffersize);
    if BASS_ChannelGetPosition (sh, BASS_Pos_Byte) >= EndPosition then
      BASS_ChannelStop (sh);
  end;
  BASS_StreamFree (sh);
  Infobox ('Ready!');
end;
Ich hab’s auch schon mittels eine BASS_SYNC_Pos probiert, aber der Sync wird niemals erreicht.

Freundliche Grüße
Marco

Wishmaster 20. Jun 2009 10:46

Re: Stille aus Wave-Dateien entfernen?
 
Hi

ich freue mich das dir der code weiter geholfen hat.

PreScan ist mehr für MP3s gedacht. Benutze es nur wen du das unbedingt brauchst, es dauert en Stück länger um eine mp3 Datei zu Laden.

Aus der bass Hilfe
Zitat:

Enable pin-point accurate seeking (to the exact byte) on the MP3/MP2/MP1 stream. This also increases the time taken to create the stream, due to the entire file being pre-scanned for the seek points.
Tipp
1, wen möglich verwende immer 32 Bit (bessere qualität)
2, ich würde an deiner stelle die bassmix.dll benutzen

in deinem Code würde ich den buffer vergrößern besonders wen du nach wma encodieren willst

Delphi-Quellcode:
var Buff32 : Array [0..20000] of FLOAT;    // 32 Bit
  BASS_ChannelGetData(Channel, @Buff32, SizeOf(Buff32));

var Buff16 : Array [0..20000] of LongInt;  // 16 Bit
  Result:=BASS_ChannelGetData(Channel, @Buff16, SizeOf(Buff16));

Marco Steinebach 1. Jul 2009 18:23

Re: Stille aus Wave-Dateien entfernen?
 
Hallo Wishmaster,
Zitat:

Zitat von Wishmaster
ich freue mich das dir der code weiter geholfen hat.

Nochmal vielen Dank, hat er wirklich!

Zitat:

Zitat von Wishmaster
2, ich würde an deiner stelle die bassmix.dll benutzen

wie jetzt, um dann die neue Wave zu speichern? Ähm, wie denn? Ich hab nicht mal 'ne Idee. ;-)

Zitat:

Zitat von Wishmaster
in deinem Code würde ich den buffer vergrößern besonders wen du nach wma encodieren willst

Ich hatte ihn so klein gehalten, da ich möglichst na an die errechnete Endposition heranwollte - und der Trick mit dem eingesetzten SyncPos nicht geklappt hat.

Viele Grüße
Marco

Wishmaster 2. Jul 2009 09:51

Re: Stille aus Wave-Dateien entfernen?
 
Hi

Zitat:

wie jetzt, um dann die neue Wave zu speichern? Ähm, wie denn? Ich hab nicht mal 'ne Idee.
Nein! Mit der bassmix.dll kannst mehrere Dateien zusammen mixen, Samplerate und Channels ändern.
du kannst auch die Lautstärke und Balance ändern

Zitat:

When mixing a channel, the mixer makes use of the channel's freq/volume/pan attributes, as set with BASS_ChannelSetAttribute. The BASS_CONFIG_CURVE_VOL and BASS_CONFIG_CURVE_PAN config option settings are also used.

Zitat:

Ich hatte ihn so klein gehalten, da ich möglichst na an die errechnete Endposition heranwollte - und der Trick mit dem eingesetzten SyncPos nicht geklappt hat.
Das kannst du auch mit der bassmix.dll erreichen!

Delphi-Quellcode:
Procedure Encode(inFile, outFile : String; Samplerate, Bits, Channels : integer) // 44100, 16, 2
Var Channel, Mixer : DWORD;
       Flag, encFlag : DWORD;
       StopTime : INT64;
begin
     Channel:= BASS_StreamCreateFile(FALSE, PChar(inFile), 0, 0, Flag);

     Mixer := BASS_Mixer_StreamCreate(Samplerate, Channels, BASS_SAMPLE_FLOAT or BASS_STREAM_DECODE);

    (* 
        limiting the duration to X seconds
        StopTime = The maximum amount of data (in bytes) to mix... 0 = no limit.
    *)

     StopTime := BASS_ChannelSeconds2Bytes(Mixer, 2) ; // in Sec.

     Flag:= BASS_MIXER_LIMIT or BASS_MIXER_FILTER or BASS_MIXER_BUFFER;
     BASS_Mixer_StreamAddChannelEx(Mixer, Channel, Flag, 0, StopTime);

     BASS_ChannelSetPosition (..., Startposition, BASS_POS_Byte);

     encFlag:= 0;
    if Bits = 8 then  encFlag:= encFlag or BASS_ENCODE_FP_8BIT;
    if Bits = 16 then encFlag:= encFlag or BASS_ENCODE_FP_16BIT;
    if Bits = 24 then encFlag:= encFlag or BASS_ENCODE_FP_24BIT;
    if Bits = 32 then encFlag:= encFlag or BASS_ENCODE_FP_32BIT;
   // else 32 Bit (floating-point)

     BASS_Encode_Start(..., PChar(outFile), encFlag or BASS_Encode_AutoFree, nil, nil)

Marco Steinebach 13. Aug 2009 22:29

Re: Stille aus Wave-Dateien entfernen?
 
Hallo,
Ich hab mir den Code heute nochmal zu gemüte geführt und, denke?, er hat einen Fehler.
Delphi-Quellcode:
function Channel_Get_SilenceLength_16Bit(FileName : String; Pinpoint : Boolean; Threshold : QWORD; var StartPoint, EndPoint : DWORD) : Bool; stdcall;
var
  a, b: Integer;
  pos, count, chan: DWORD;
  buf16: array[0..50000] of Smallint; // 100% OK.
  flag : DWORD;
begin
   result:= false;
   count := 0;
   flag:= BASS_STREAM_DECODE;    //BASS_STREAM_DECODE or BASS_STREAM_AUTOFREE

     if Pinpoint then
       flag:= flag or BASS_STREAM_PRESCAN;

     Chan:= BASS_StreamCreateFile(FALSE, PChar(FileName), 0, 0, Flag);
  if Chan = 0 then
     Chan:= BASS_MusicLoad(False, PChar(FileName), 0, 0, Flag or BASS_MUSIC_NOSAMPLE, 0);
  if Chan = 0 then
   Exit;

  while Bass_ChannelIsActive(Chan) <> 0 do
   begin
    b := BASS_ChannelGetData(Chan, @buf16, 20000);
    b := b div 2;
    a := 0;
    while (a < b) and (Abs(buf16[a]) <= Threshold) do
      a := a + 1;
      count := count + (a * 2);
    if (a < b) then
     begin
      while (a <> 0) and (Abs(buf16[a]) > (Threshold div 4)) do
       begin
        a := a - 1;
        count := count - 2;
      end;
      Break;
    end;
  end;
   StartPoint := count; // Start-Point ready

   pos := BASS_ChannelGetLength(Chan);
  while (pos > count) do
   begin
    if pos < 100000 then
      pos := 0
    else
      pos := pos - 100000;
    BASS_ChannelSetPosition(chan, pos);
    b := BASS_ChannelGetData(chan, @buf16, 100000);
// ... so, hier geht's los:
    b := b div 2; // b ist also die Anzahl der samples
    a := b;
   while (a > 0) and (Abs(buf16[a - 1]) <= (Threshold div 2)) do
       a := a - 1;
    if a > 0 then
     begin
      count := pos + (a * 4); // warum 4, müßte doch bei smallint, also 2 byte, * 2 heißen, oder?      Break;
     end;
    end;
 EndPoint := Count;  // End-Point ready
 BASS_MusicFree(Chan);
 BASS_StreamFree(Chan);
 Result:= true;
end;
Das gleiche gilt, natürlich, auch für die 32-Bit-Variante.
Der Code produziert nämlich manchmal Ergebnisse, deren Endposition größer ist, als die tatsächliche Länge.
Hilf mir mal bitte!
Einen freundlichen Gruß
Marco


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:38 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz