Autor Beitrag
F34r0fTh3D4rk
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 29

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Mo 21.01.08 20:07 
Hi,

Ich suche eine Möglichkeit, zwei Wave Dateien direkt hintereinander zu schneiden und als eine Wave abzuspeichern,
wie stelle ich das am besten an ? ("Mit Bass.dll" oder "Mit FMOD" reicht mir als Antwort leider nicht ;) )

mfg
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1340
Erhaltene Danke: 120

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mo 21.01.08 21:49 
Mit Mono Dateien habe ich das schonmal bei meinem DOS Synthesizer gemacht. Ich habe mir auch eine Procedure geschrieben die an den fügestellen das Knacken entfernt was entstehen kann wenn die Amplitude des Endsamples und des neuen Startsamples zuweit auseinander liegt.
Für Stereo müsste man das ja eigentlich genauso hinbekommen.
Die Frage ist nur ob es heutzutage nicht fertige Tools gibt die das besser hinbekommen.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 29

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 22.01.08 15:17 
Ja ich benötige das allerdings in einem anderen Kontext. Welche Möglichkeiten habe ich ? Ich muss die beiden nur direkt hintereinander schneiden, nicht bearbeiten oder so.

mfg
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 23.01.08 13:04 
Lese WAV-Spec, sehe, dass das n Container-Format ist, überprüfe, dass die Format-Spec identisch ist (Sollte herfür eines der PCM-Formate sein).

Öffne nun die erste Datei, addiere zu Offset 4 die Größe des Datecontainers des zweiten Files. Passe die Container-Größe des ersten Files um diese Größe an, hänge den Inhalt des Datencontainers aus der zweiten File ans Ende der ersten Datei an ...

Mit Hilfe der OVFS-Stream IIRC ne Sache von 40 Zeilen ... (in Zwanzi Zeilen bekommt man do mit voller Fehlerprüfung das Auslesen der Spielzeit hin ...)

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 29

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Mi 23.01.08 19:49 
Ich habs jetzt mal "per Hand" versucht. Allerdings habe ich das Problem, dass ich den Inhalt des Data Chunks nicht auslesen kann. Ich habe alles Mögliche versucht, allerdings sind meine Daten immer leer.

Hier mal mein Code:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
const
  // Header
  cRIFF = 'RIFF';
  cWAVE = 'WAVE';
  cfmt  = 'fmt ';
  cdata = 'data';

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
type
  TRIFFHeader = record
    filesize: cardinal;
  end;
  TfmtHeader = record
    samplerate,
    bytessecond: cardinal;
    formattag,
    channels,
    blockalign,
    bitssample: smallint;
  end;
  TdataHeader = record
    datasize: cardinal;
    wdata: array of byte;
  end;

Dieser Code hier stammt aus dem Easy Delphi Helper:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
function GotoChunk(pStream: TFilestream; ID: string): Integer;
var
  chunkID: array[0..3] of char;
  chunkSize: Integer;
begin
  Result := -1;
  with pStream do
  begin
    // index of first chunk
    Position := 12;
    repeat
      // read next chunk
      Read(chunkID, 4);
      Read(chunkSize, 4);
      if chunkID <> ID then
          Position := Position + chunkSize;
    until (chunkID = ID) or (Position >= Size);
    if chunkID = ID then
      Result := chunkSize;
  end
end;

Dieser hier nicht mehr:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
function ReadWave(filename: string; var riff: TRIFFheader; var fmt: Tfmtheader; var data: Tdataheader): boolean;
var
  Stream: TFileStream;
  hRIFF,
  hWAVE:  array[0..3] of char;
begin
  result := false;
  Stream := TFilestream.Create(filename, fmOpenRead or fmShareDenyWrite);
  with Stream do
  try
    // RIFF header
    // "RIFF"
    Read(hriff, 4);
    // Filesize
    Read(riff.filesize, 4);
    // "WAVE"
    Read(hWAVE, 4);
    if (hRIFF = cRIFF) and (hWAVE = cWAVE) then
    begin
      // fmt header
      if (GotoChunk(Stream, cfmt) <> -1) then
      begin
        // format tag
        Read(fmt.formattag, 2);
        // channels
        Read(fmt.channels, 2);
        // sample rate
        Read(fmt.samplerate, 4);
        Read(fmt.bytessecond, 4);
        Read(fmt.blockalign, 2);
        Read(fmt.bitssample, 2);
        // data header
        data.datasize := GotoChunk(Stream, cdata);
        if data.datasize > 0 then
        begin
          setlength(data.wdata, data.datasize);
          read(data.wdata, data.datasize);
          result := true;
        end;
      end;
    end;
  finally
    Free;
  end;
end;

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
var
  Stream: TFileStream;
  nfilesize: cardinal;
  fmtsize: integer;
begin
  Stream := TFilestream.Create(filename, fmCreate);
  with Stream do
  try
    // RIFF header
    // "RIFF"
    Write(cRIFF, 4);
    // Filesize
    nfilesize := data.datasize + 36;
    Write(nfilesize, 4);
    // "WAVE"
    Write(cWAVE, 4);
    // fmt header
    Write(cfmt, 4);
    fmtsize := 16;
    Write(fmtsize, 4);
    Write(fmt.formattag, 2);
    Write(fmt.channels, 2);
    Write(fmt.samplerate, 4);
    Write(fmt.bytessecond, 4);
    Write(fmt.blockalign, 2);
    Write(fmt.bitssample, 2);
    // data header
    Write(cdata, 4);
    Write(data.datasize, 4);
    Write(data.wdata, data.datasize);
  finally
    Free;
  end;
end;

Es lässt sich alles wunderbar auslesen und schreiben und ist data.wdata leer, warum ?

mfg


Zuletzt bearbeitet von F34r0fTh3D4rk am Do 24.01.08 17:14, insgesamt 2-mal bearbeitet
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mi 23.01.08 20:41 
Wenn du das mit dem Header gelöst hast kommt noch eine weitere Schwierigkeit hinzu:
Die Datenpakete einfach zusammenstecken erzeugt mit hoher Wahrscheinlichkeit ein kurzes Klickgeräusch, da die Waveform beim Schnitt mit hoher Wahrscheinlichkeit nicht stetig ist. Du musst die Waveform in der Nähe des Schnitts so zusammenbiegen, dass sie stetig wird - oder beide in der Nähe des Schnitts zu 0 biegen, ansonsten erzeugst du eine Schockwelle ;)
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 29

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Mi 23.01.08 21:13 
Ich habe mir die Dateien gerade mal angeguckt, sie enden nicht komplett lautlos (aber schon nicht mehr wirklich hörbar), ist das schlimm ? (Mit audacity aneinanderhängen macht auf jeden Fall keine Probleme, aber das ist auch was anderes)
Für Lösungsvorschläge / Alternativen bin ich offen ;)
(vor allem zu dem Problem, dass ich die Wave Daten nicht ausgelesen bekomme :P)


mfg
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1340
Erhaltene Danke: 120

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Do 24.01.08 11:51 
Eine Webseite auf der sich was zum Lesen und Schreiben von Wavedateien finden lassen dürfte : www.wotsit.org/

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 29

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Do 24.01.08 15:21 
Ich hab die Doku doch schon, ich habe soweit auch alles auslesen können. Der Code müsste eigentlich schon funktionieren,
allerdings funktioniert das mit den wave daten nicht:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
        // data header
        data.datasize := GotoChunk(Stream, cdata);
        if data.datasize > 0 then
        begin
          setlength(data.wdata, data.datasize);
          read(data.wdata, data.datasize);
          result := true;
        end;

vielleicht liegt das problem bei meinem datentyp, aber ich habe schon alles mögliche probiert.

Wenn ich an diese stelle ein ReadBuffer setze, bekommt ich einen Stream Read Error.

mfg


Zuletzt bearbeitet von F34r0fTh3D4rk am Do 24.01.08 17:13, insgesamt 1-mal bearbeitet
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1340
Erhaltene Danke: 120

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Do 24.01.08 17:02 
user profile iconF34r0fTh3D4rk hat folgendes geschrieben:

vielleicht liegt das problem bei meinem datentyp, aber ich habe schon alles mögliche probiert.

Damit hast du recht, alle deine Records müssen aus jeden Fall packed sein.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
type
  TRIFFHeader = packed record
    filesize: cardinal;
  end;
  TfmtHeader = packed record
    samplerate,
    bytessecond: cardinal;
    formattag,
    channels,
    blockalign,
    bitssample: smallint;
  end;
  TdataHeader = packed record
    datasize: cardinal;
    wdata: array of byte;
  end;


Ansonsten hast du eine 4 oder 8-Byte Datenausrichtung und damit liest man eigentlich immer nur Müll.
Mit Vorsicht ist auch die datasize zu genießen, die wirkliche Größe der Daten ergibt sich aus der Anzahl der Samples, der Channels und der Bitbreite.
Zudem wird Normalerweise immer aus ganze Word (16-Bit) "aufgerundet" (wenn ich mich recht erinnere)

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 29

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Do 24.01.08 17:11 
An dem packed hats nicht gelegen (kann ich mir eigentlich auch nicht vorstellen). Und die Größe die ich bekomme, sollte eigentlich stimmen. Woher bekomme ich denn die Anzahl der Samples ? (Es funktioniert übrigens auch nicht z.B. 4 bytes zu lesen, das aber nur an der einen stelle)

mfg
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Do 24.01.08 17:59 
user profile iconF34r0fTh3D4rk hat folgendes geschrieben:
Ich hab die Doku doch schon, ich habe soweit auch alles auslesen können. Der Code müsste eigentlich schon funktionieren,
allerdings funktioniert das mit den wave daten nicht:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
        // data header
        data.datasize := GotoChunk(Stream, cdata);
        if data.datasize > 0 then
        begin
          setlength(data.wdata, data.datasize);
          read(data.wdata, data.datasize);
          result := true;
        end;

vielleicht liegt das problem bei meinem datentyp, aber ich habe schon alles mögliche probiert.

Wenn ich an diese stelle ein ReadBuffer setze, bekommt ich einen Stream Read Error.

mfg

data.wdata ist ein dynamisches Array, data.wdata ist also nur ein Pointer. Du musst wenn schon nach data.wdata[0] schreiben, oder wie in älteren Codes wdata als statisches à la array[0..0] oder [0..$FFFFFxxx] definieren, allenfalls die Range-Checks ausschalten und den notwendigen Speicher selbst mit GetMem allozieren und mit Pointern arbeiten. Ich empfehle ersteres.


Zuletzt bearbeitet von delfiphan am Do 24.01.08 18:06, insgesamt 2-mal bearbeitet
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 29

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Do 24.01.08 18:02 
sowas hab ich mir schon gedacht, danke jetzt gehts ;)

Das verketten zweier / mehrerer Wave funktioniert ebenfalls.

Hier der Code:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
function MergeMultipleWaves(inputs: TStringArray; output: string): boolean;
  function CompareFMT(fmt1, fmt2: Tfmtheader): boolean;
  begin
    result := (fmt1.samplerate = fmt2.samplerate) and
              (fmt1.bytessecond = fmt2.bytessecond) and
              (fmt1.channels = fmt2.channels) and
              (fmt1.formattag = fmt2.formattag) and
              (fmt1.blockalign = fmt2.blockalign) and
              (fmt1.bitssample = fmt2.bitssample);
  end;
var
  riff: TRiffheader;
  fmt: Tfmtheader;
  data: Tdataheader;
  ergriff: TRiffheader;
  ergfmt: Tfmtheader;
  ergdata: TDataheader;
  i, d, oldsize: integer;
begin
  result := false;
  for i := 0 to high(inputs) do
  begin
    if ReadWave(inputs[i], riff, fmt, data) then
      if (i = 0) then
      begin
        ergriff.filesize := riff.filesize;
        ergfmt := fmt;
        ergdata.datasize := 0;
      end else
        if CompareFMT(fmt, ergfmt) then
          ergriff.filesize := ergriff.filesize + data.datasize else
            exit;
      oldsize := ergdata.datasize;
      ergdata.datasize := ergdata.datasize + data.datasize;
      setlength(ergdata.wdata, ergdata.datasize);
      for d := 0 to data.datasize - 1 do
        ergdata.wdata[d + oldsize] := data.wdata[d];
  end;
  WriteWave(output, ergriff, ergfmt, ergdata);
  result := true;
end;


mfg