Wave-Datei schreiben

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
es_91
Beiträge: 383
Registriert: 25.01.2011 04:48

Wave-Datei schreiben

Beitrag von es_91 »

Hi.

Also, ich möchte eine mit 44.1 KHz abgetastete .wav-Datei in eine mit 22.05 KHz abgetastete umwandeln. Ich weiß, sowas kann heutzutage jedes kleinere Audio-tool, aber ich brauche es in meiner .exe.

Also habe ich folgenden code geschrieben:

Code: Alles auswählen

;- Enumeration

Enumeration
  #source
  #target
EndEnumeration

;- Getting file names

NewList Lword.w()
NewList Rword.w()

source.s = ProgramParameter()

target.s = ProgramParameter()

;- Initiating files

If source
  If ReadFile(#source, source)
  Else
    End
  EndIf
Else
  End
EndIf

los = Lof(#source)

;- Initiating memory

smemory = AllocateMemory(los)
tmemory = AllocateMemory(los * 2)

;- Reading header from source

ReadData(#source, smemory, los)

Repeat
  
  If Not offset < 44
    AddElement(Lword())
    Lword() = PeekW(smemory + offset)
    AddElement(Rword())
    Rword() = PeekW(smemory + offset + 2)
  EndIf
  
  offset + 4
  
Until offset + 4 > los

Repeat
  
  AddElement(Lword())
  Lword() = PeekW(smemory + offsettwo)
  
  offsettwo + 2
  
  AddElement(Rword())
  Rword() = PeekW(smemory + offsettwo)
  
  offsettwo + 2
  
Until Not offsettwo < offset

For headeroffset = 0 To 44 Step 4
  If headeroffset = 44
    Break
  EndIf
  
  If headeroffset < 24 Or Not headeroffset < 28
    PokeL(tmemory + headeroffset, PeekL(smemory + headeroffset))
  EndIf
  If headeroffset = 24
    PokeL(tmemory + headeroffset, 22050)
  EndIf
Next

;- Working through the body of the file

ForEach Lword()
  PokeW(tmemory + headeroffset + ListIndex(Lword()) * 2, Lword())
  SelectElement(Rword(), ListIndex(Lword()))
  PokeW(tmemory + headeroffset + ListIndex(Lword()) * 2 + 2, Rword())
  NextElement(LWord())
Next

;- Writing target file

If target
  If CreateFile(#target, target)
  Else
    End
  EndIf
Else
  target = source + ".22khz.wav"
  If CreateFile(#target, target)
  Else
    End
  EndIf
EndIf

WriteData(#target, tmemory, (ListSize(Lword()) - 1) + headeroffset)
Was der code macht:

- er liest die Quelldatei, deren Dateiname als Programmparameter übergeben wird, komplett in den Speicher ein.
- er erstellt eine Zieldatei, deren Dateiname per Standard (d.h. wenn nicht anders als Programmparameter übergeben) eine Abwandlung dessen der Quelldatei ist.
- er schreibt die Zieldatei nach Bearbeitung der in den Speicher geladenen Daten
- Im Speicher kopiert es den, lt. wikipedia, 44 Bytes großen Header in den "Ziel"-Speicher und ersetzt nur den Wert für die Abtastrate (von 44100 zu 22050)
- Im Speicherbereich des Dateikörpers wird jedes zweite Sample* fallen gelassen, wodurch die Abtastrate um die Hälfte sinkt.

*Sample = Datensatz, der die Elongation angibt. (In einer .wav-Datei folgen, wenn die Datei Stereo ist und mit 16 Bit abgetastet wird, immer zwei 16-Bit große Wörter aufeinander, eines für die linke, eines für die rechte Ausgabekanalseite. So geht das nach dem Header bis ans Ende der Datei.)

Nun mein Problem: Während winamp & co. (ich hab's außerdem noch mit der Wiedergabefunktion von NCHsoft Switch probiert) die neue Datei problemlos abspielen weigert sich der Windows Media Player und bringt die Nachricht, er würde das Format nicht verstehen.

Was mache ich denn falsch, für die Bill Gates-Liga?

Nachtrag: Wann immer ich von einem Wave-"Header" spreche, meine ich lt. wikipedia, den RIFF-Header, den fmt-Abschnitt und den Daten-Abschnitt (zusammen).
Derren
Beiträge: 557
Registriert: 23.07.2011 02:08

Re: Wave-Datei schreiben

Beitrag von Derren »

Hab mir den Code noch nicht angeschaut aber der Header beinhalter außerdem noch die Länge der Datei und der "Datasection". Wenn du jedes 2te Byte fallen lässt halbiert sich die Länge der Datasection. Die Dateigröße ist damit ((alt-44) / 2) + 44

Das Offset der Dateigröße ist *buffer+4 und die Größte der Datasection: *buffer+40
An diesen Stellen musst die jeweilige Größe als long poken
Signatur und so
es_91
Beiträge: 383
Registriert: 25.01.2011 04:48

Re: Wave-Datei schreiben

Beitrag von es_91 »

Zeile 72 bis 80 habe ich jetzt so verändert:

Code: Alles auswählen

  If headeroffset = 4
    PokeL(tmemory + headeroffset, 36 + ListSize(Lword()))
  ElseIf headeroffset = 24
    PokeL(tmemory + headeroffset, 22050)
  ElseIf headeroffset = 40
    PokeL(tmemory + headeroffset, ListSize(Lword()))
  Else
    PokeL(tmemory + headeroffset, PeekL(smemory + headeroffset))
  EndIf
... sodass der code jetzt so aussieht:

Code: Alles auswählen

;- Enumeration

Enumeration
  #source
  #target
EndEnumeration

;- Getting file names

NewList Lword.w()
NewList Rword.w()

source.s = ProgramParameter()

target.s = ProgramParameter()

;- Initiating files

If source
  If ReadFile(#source, source)
  Else
    End
  EndIf
Else
  End
EndIf

los = Lof(#source)

;- Initiating memory

smemory = AllocateMemory(los)
tmemory = AllocateMemory(los * 2)

;- Reading header from source

ReadData(#source, smemory, los)

Repeat
  
  If Not offset < 44
    AddElement(Lword())
    Lword() = PeekW(smemory + offset)
    AddElement(Rword())
    Rword() = PeekW(smemory + offset + 2)
  EndIf
  
  offset + 4
  
Until offset + 4 > los

Repeat
  
  AddElement(Lword())
  Lword() = PeekW(smemory + offsettwo)
  
  offsettwo + 2
  
  AddElement(Rword())
  Rword() = PeekW(smemory + offsettwo)
  
  offsettwo + 2
  
Until Not offsettwo < offset

For headeroffset = 0 To 44 Step 4
  If headeroffset = 44
    Break
  EndIf
  
  If headeroffset = 4
    PokeL(tmemory + headeroffset, 36 + ListSize(Lword()))
  ElseIf headeroffset = 24
    PokeL(tmemory + headeroffset, 22050)
  ElseIf headeroffset = 40
    PokeL(tmemory + headeroffset, ListSize(Lword()))
  Else
    PokeL(tmemory + headeroffset, PeekL(smemory + headeroffset))
  EndIf
Next

;- Working through the body of the file

ForEach Lword()
  PokeW(tmemory + headeroffset + ListIndex(Lword()) * 2, Lword())
  SelectElement(Rword(), ListIndex(Lword()))
  PokeW(tmemory + headeroffset + ListIndex(Lword()) * 2 + 2, Rword())
  NextElement(LWord())
Next

;- Writing target file

If target
  If CreateFile(#target, target)
  Else
    End
  EndIf
Else
  target = source + ".22khz.wav"
  If CreateFile(#target, target)
  Else
    End
  EndIf
EndIf

WriteData(#target, tmemory, (ListSize(Lword())) + headeroffset)
Trotzdem spielt der Windows Media Player die Datei nicht ab.
Auch andere Player können jetzt die Zieldatei nicht mehr lesen.
Derren hat geschrieben:Wenn du jedes 2te Byte fallen lässt halbiert sich die Länge der Datasection.
Kleine Korrektur: Jedes zweite Wort.

Trotzdem erstmal vielen Dank, das hatte ich natürlich nicht bedacht. Vielen Dank. :allright:
Derren
Beiträge: 557
Registriert: 23.07.2011 02:08

Re: Wave-Datei schreiben

Beitrag von Derren »

Hast du block align auch angepasst? Finde den Offset 32 nicht in deinem Code.
Signatur und so
es_91
Beiträge: 383
Registriert: 25.01.2011 04:48

Re: Wave-Datei schreiben

Beitrag von es_91 »

Derren hat geschrieben:Hast du block align auch angepasst? Finde den Offset 32 nicht in deinem Code.
Nein, habe ich nicht. Nach der Rechnung auf wikipedia kommt da eine 4 rein. Was soll dieser Blödsinn denn?
wikipedia hat geschrieben:32 (0x20) 2 <block align> Frame-Größe = <Anzahl der Kanäle> · ((<Bits/Sample (eines Kanals)> + 7) / 8) (Division ohne Rest)
Also: <Anzahl der Kanäle> ist 2, <Bits/Sample (eines Kanals)> ist 16, demnach: 2*((16+7)/8) = 4

Probieren wir das mal aus...

Code: Alles auswählen

; wieder Zeile 72 - 80 ersetzen:
  If headeroffset = 4
    PokeL(tmemory + headeroffset, 36 + ListSize(Lword()))
  ElseIf headeroffset = 24
    PokeL(tmemory + headeroffset, 22050)
  ElseIf headeroffset = 32
    PokeW(tmemory + headeroffset, 4)
    PokeW(tmemory + headeroffset + 2, PeekW(smemory + headeroffset + 2))
  ElseIf headeroffset = 40
    PokeL(tmemory + headeroffset, ListSize(Lword()))
  Else
    PokeL(tmemory + headeroffset, PeekL(smemory + headeroffset))
  EndIf
... und siehe da ....... ....... ....... es geht nicht. NHCsoft Switch spielt nach einer Weile ein verknackstes leeres File ab und Winamp spielt die Datei gar nicht ab.
Derren
Beiträge: 557
Registriert: 23.07.2011 02:08

Re: Wave-Datei schreiben

Beitrag von Derren »

Hi, bei mir stocks grade auch ein bißchen.

Hab mal nen ordentlicheren Testcode erstellt. Beim 1:1 kopieren funktioniert der, aber irgendwo stimmt noch ein Wert nicht, denn fast die komplette hintere Hälfte meiner output.wav besteht aus null bytes.

Ich guck morgen nochmal danach.

Code: Alles auswählen

EnableExplicit 
Define sourcefile.s = "test_01.wav"
Define outputfile.s = "zOUTPUT.wav"
Define offset.i, datalength.i
Define *header, *data


ReadFile(0, sourcefile)

*header = AllocateMemory(44)
;- Read Header from Sourcefile into our Buffer
PokeL(*header, 		ReadLong(0)) ;"RIFF"
PokeL(*header+4, 	ReadLong(0)) ;filesize - 8
PokeL(*header+8, 	ReadLong(0)) ;"WAVE"
PokeL(*header+12, 	ReadLong(0)) ;"fmt "
PokeL(*header+16, 	ReadLong(0)) ;fmt-length (always 16)
PokeW(*header+20, 	ReadWord(0)) ;format tag
PokeW(*header+22, 	ReadWord(0)) ;channels
PokeL(*header+24, 	ReadLong(0)) ;sample rate
PokeL(*header+28, 	ReadLong(0)) ;bytes/sec
PokeW(*header+32, 	ReadWord(0)) ;block-align
PokeW(*header+34, 	ReadWord(0)) ;bits/sample
PokeL(*header+36, 	ReadLong(0)) ;"data"
PokeL(*header+40, 	ReadLong(0)) ;datalength

datalength = PeekL(*header+40)
datalength = datalength / 2 ;new datalength = old/2, since we drop half of the data
*data = AllocateMemory(datalength) ;Create a new buffer for our NEW wave data
If *data
	offset=0
	While offset<=(datalength)
		PokeW(*data + offset, ReadWord(0)) ;read two words (left and right)
		PokeW(*data + offset+2, ReadWord(0)) ;and poke them into our new data buffer
		;PokeW(*data + offset+4, ReadWord(0)) ;and poke them into our new data buffer
		;PokeW(*data + offset+6, ReadWord(0)) ;and poke them into our new data buffer
		ReadWord(0) ;ignore the next two words
		ReadWord(0)	
		offset + 2 
	Wend 
EndIf 

CloseFile(0)

;-Edit header
PokeL(*header+4, datalength + 36) ;new file size =(datasize + headersize - 8)
PokeL(*header+24, 22050) ;new sample rate
PokeW(*header+32, 4) ;block align
PokeL(*header+40, datalength) ;new data size

CreateFile(1, outputfile)
WriteData(1, *header, 44)
WriteData(1, *data, datalength)
CloseFile(1)


Signatur und so
Benutzeravatar
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

Re: Wave-Datei schreiben

Beitrag von Regenduft »

Habe da gerade einen Code in der Schmiede... ist nicht gerade schön (um nicht pott hässlich zu sagen...) und enthält evtl. noch böse Bugs, aber vielleicht findest Du's ja trotzdem nützlich. :)

Code: Alles auswählen

DeclareModule pbex_Sound
  
  #PBEX_Sound_Format_PCM   = 1
  #PBEX_Sound_Format_FLOAT = 3
  
  #PBEX_Sound_Channels_MultiTrack      = $00000
  #PBEX_Sound_Channels_Mono            = $00004
  #PBEX_Sound_Channels_Stereo          = $00003
  #PBEX_Sound_Channels_Quadro          = $00033
  #PBEX_Sound_Channels_Surround        = $00107
  #PBEX_Sound_Channels_5point1         = $0003F
  #PBEX_Sound_Channels_7point1         = $000FF
  
  #PBEX_Sound_Speaker_FrontLeft        = $00001
  #PBEX_Sound_Speaker_FrontRight       = $00002
  #PBEX_Sound_Speaker_FrontCenter      = $00004
  #PBEX_Sound_Speaker_SubWoofer        = $00008 ; Normal=20Hz...20kHz, Subwoofer=20...120Hz
  #PBEX_Sound_Speaker_BackLeft         = $00010
  #PBEX_Sound_Speaker_BackRight        = $00020
  #PBEX_Sound_Speaker_FrontCenterLeft  = $00040
  #PBEX_Sound_Speaker_FrontCenterRight = $00080
  #PBEX_Sound_Speaker_BackCenter       = $00100
  #PBEX_Sound_Speaker_SideLeft         = $00200
  #PBEX_Sound_Speaker_SideRight        = $00400
  #PBEX_Sound_Speaker_TopCenter        = $00800
  #PBEX_Sound_Speaker_TopFrontLeft     = $01000
  #PBEX_Sound_Speaker_TopFrontCenter   = $02000
  #PBEX_Sound_Speaker_TopFrontRight    = $04000
  #PBEX_Sound_Speaker_TopBackLeft      = $08000
  #PBEX_Sound_Speaker_TopBackCenter    = $10000
  #PBEX_Sound_Speaker_TopBackRight     = $20000
  
  #PBEX_Sound_LegacyMode_BITMASK   = $0003
  #PBEX_Sound_LegacyMode_Off       = $0000
  #PBEX_Sound_LegacyMode_Prefer    = $0001
  #PBEX_Sound_LegacyMode_Force     = $0002
  #PBEX_Sound_CatchMode_BITMASK    = $0030
  #PBEX_Sound_CatchMode_AutoDetect = $0000
  #PBEX_Sound_CatchMode_Normal     = $0010
  #PBEX_Sound_CatchMode_MoveData   = $0020
  #PBEX_Sound_CatchMode_PokeHeader = $0030
  
  Declare.i AllocateRawWaveMemory( Size , Flags = #PBEX_Sound_CatchMode_PokeHeader ) ; #PB_Memory_NoClear als Flag möglich
  Declare.i CatchRawSound( Sound , *Data , DataBytes , Bits , SamplingRate , Channels = 1 , ChannelFormat = 0 , SoundFormat = #PBEX_Sound_Format_PCM , Flags = #PBEX_Sound_LegacyMode_Off | #PBEX_Sound_CatchMode_AutoDetect )
  Declare.i DolbyDigitalChannels( Value1 , Value2 , Value3 = 0 )
  Declare.i FreeRawWaveMemory( *RawWaveMemory )
  Declare.i PokeWaveHeader( *Memory , WaveBytes , Bits , SamplingRate , Channels , ChannelFormat , SoundFormat , Flags = #PBEX_Sound_LegacyMode_Off )
  Declare.i RawWaveMemorySize( *RawWaveMemory , FullSize = #False )
  Declare.i ReAllocateRawWaveMemory( *RawWaveMemory , Size , Flags = #PBEX_Sound_CatchMode_AutoDetect ) ; #PB_Memory_NoClear als Flag möglich
  
EndDeclareModule

Module pbex_Sound
  
  CompilerIf #PB_Any = #PB_Ignore : CompilerError "#PB_Any = #PB_Ignore" : CompilerEndIf
  CompilerIf #PB_Ignore >= 0 : CompilerError "#PB_Ignore >= 0" : CompilerEndIf
  CompilerIf #PB_Memory_NoClear & #PBEX_Sound_CatchMode_BITMASK : CompilerError "#PB_Memory_NoClear & #PBEX_Sound_CatchMode_BITMASK <> #False" : CompilerEndIf
  
  EnableExplicit

  Structure WAVE_EXTENSIBLE
    zzz_Align1      .l
    AddWaveBytes    .l        ; FileSize-8 ODER 72+WaveBytes=SizeOf(WAVE_EXTENSIBLE)-8+WaveBytes
    zzz_Align2      .u[7]
    Channels        .u        ; Channels
    SampleRate      .l        ; SampleRate (8000, 11025, 22050, 44100, 48000, 96000, ...)
    ByteRate        .l        ; SampleRate * BlockSize
    BlockSize       .u        ; (Bits+7)>>3 * Channels
    Bits            .u        ; Bits (8, 16, 24, 32, 64)
    zzz_Align3      .u
    BitsValid       .u        ; = Bits (theoretisch auch z.B. ValidBits=12 und Bits=16)
    ChannelMask     .l        ; 0 (Mono/Mehrkanal) oder #SPEAKER_~ (Stereo/Surround)
    Format          .u        ; #WAVE_FORMAT_~
    zzz_Align4      .u[11]
    SamplesTotal    .l        ; Channels * SamplesPerChannel
    zzz_Align5      .l
    WaveBytes       .l        ; BlockSize * Samples; (WaveBytes+1)&~1 (damit gerade!)
  EndStructure
  
  Structure WAVE_FLOAT_LEGACY
    zzz_Align1      .l
    AddWaveBytes    .l        ; FileSize-8 ODER 50+WaveBytes=SizeOf(WAVE_FLOAT_LEGACY)-8+WaveBytes
    zzz_Align2      .u[7]
    Channels        .u        ; Channels
    SampleRate      .l        ; SampleRate (8000, 11025, 22050, 44100, 48000, 96000, ...)
    ByteRate        .l        ; SampleRate * BlockSize
    BlockSize       .u        ; (Bits+7)>>3 * Channels
    Bits            .u        ; Bits (8, 16, 24, 32, 64)
    zzz_Align3      .u[5]
    SamplesTotal    .l        ; Channels * SamplesPerChannel
    zzz_Align5      .l
    WaveBytes       .l        ; BlockSize * Samples; (WaveBytes+1)&~1 (damit gerade!)
  EndStructure
  
  Structure WAVE_PCM_LEGACY
    zzz_Align1      .l
    AddWaveBytes    .l        ; FileSize-8 ODER 36+WaveBytes=SizeOf(WAVE_PCM_LEGACY)-8+WaveBytes
    zzz_Align2      .u[7]
    Channels        .u        ; Channels
    SampleRate      .l        ; SampleRate (8000, 11025, 22050, 44100, 48000, 96000, ...)
    ByteRate        .l        ; SampleRate * BlockSize
    BlockSize       .u        ; (Bits+7)>>3 * Channels
    Bits            .u        ; Bits <= 16
    zzz_Align3      .l
    WaveBytes       .l        ; BlockSize * Samples; (WaveBytes+1)&~1 (damit gerade!)
  EndStructure
  
  Structure WAVE_UNION
    StructureUnion
      Extensible.WAVE_EXTENSIBLE
      FloatLegacy.WAVE_FLOAT_LEGACY
      PcmLegacy.WAVE_PCM_LEGACY
   EndStructureUnion
  EndStructure
  
;{  Structure WAVE_EXTENSIBLE_FULL
;     a_txt_RIFF      .a[4]   ; "RIFF"
;     b_FileSizeMinus8.l        ; FileSize-8 ODER 72+WaveBytes=SizeOf(WAVE_EXTENSIBLE)-8+WaveBytes
;     c_txt_WAVE      .a[4]   ; "WAVE"
;     d_txt_fmt       .a[4]   ; "fmt "
;     e_Size40        .l      ; (40)
;     f_Format        .u      ; $FFFE (#WAVE_FORMAT_EXTENSIBLE)
;     g_Channels      .u        ; Channels
;     h_SampleRate    .l        ; SampleRate (8000, 11025, 22050, 44100, 48000, 96000, ...)
;     i_ByteRate      .l        ; SampleRate * BlockSize
;     j_BlockSize     .u        ; (Bits+7)>>3 * Channels
;     k_Bits          .u        ; Bits (8, 16, 24, 32, 64)
;     l_Size22        .u      ; (22)
;     m_ValidBits     .u        ; = Bits (theoretisch auch z.B. ValidBits=12 und Bits=16)
;     n_ChannelMask   .l        ; 0 (Mono/Mehrkanal) oder #SPEAKER_~ (Stereo/Surround)
;     o_SubFormat     .u        ; #WAVE_FORMAT_~
;     p_FixedSubFormat.a[14]  ; fester SubFormat-Wert (siehe gleichnamiges Label)
;     q_txt_fact      .a[4]   ; "fact"
;     r_Size4         .l      ; (4)
;     s_SamplesTotal  .l        ; Channels * SamplesPerChannel
;     t_txt_data      .a[4]   ; "data"
;     u_WaveBytes     .l        ; BlockSize * Samples; (WaveBytes+1)&~1 (damit gerade!)
;}  EndStructure
  
;{  Structure WAVE_FLOAT_LEGACY_FULL
;     a_txt_RIFF      .a[4]   ; "RIFF"
;     b_FileSizeMinus8.l        ; FileSize-8 ODER 50+WaveBytes=SizeOf(WAVE_FLOAT_LEGACY)-8+WaveBytes
;     c_txt_WAVE      .a[4]   ; "WAVE"
;     d_txt_fmt       .a[4]   ; "fmt "
;     e_Size18        .l      ; (18)
;     f_Format        .u      ; 3 (#WAVE_FORMAT_IEEE_FLOAT)
;     g_Channels      .u        ; Channels
;     h_SampleRate    .l        ; SampleRate (8000, 11025, 22050, 44100, 48000, 96000, ...)
;     i_ByteRate      .l        ; SampleRate * BlockSize
;     j_BlockSize     .u        ; (Bits+7)>>3 * Channels
;     k_Bits          .u        ; Bits (8, 16, 24, 32, 64)
;     l_Size0         .u      ; (0)
;     m_txt_fact      .a[4]   ; "fact"
;     n_Size4         .l      ; (4)
;     o_SamplesTotal  .l        ; Channels * SamplesPerChannel
;     p_txt_data      .a[4]   ; "data"
;     q_WaveBytes     .l        ; BlockSize * Samples; (WaveBytes+1)&~1 (damit gerade!)
;}  EndStructure
  
;{  Structure WAVE_PCM_LEGACY_FULL
;     a_txt_RIFF      .a[4]   ; "RIFF"
;     b_FileSizeMinus8.l        ; FileSize-8 ODER 36+WaveBytes=SizeOf(WAVE_PCM_LEGACY)-8+WaveBytes
;     c_txt_WAVE      .a[4]   ; "WAVE"
;     d_txt_fmt       .a[4]   ; "fmt "
;     e_Size16        .l      ; (16)
;     f_Format        .u      ; 1 (#WAVE_FORMAT_PCM)
;     g_Channels      .u        ; Channels
;     h_SampleRate    .l        ; SampleRate (8000, 11025, 22050, 44100, 48000, 96000, ...)
;     i_ByteRate      .l        ; SampleRate * BlockSize
;     j_BlockSize     .u        ; (Bits+7)>>3 * Channels
;     k_Bits          .u        ; Bits <= 16
;     l_txt_data      .a[4]   ; "data"
;     m_WaveBytes     .l        ; BlockSize * Samples; (WaveBytes+1)&~1 (damit gerade!)
;}  EndStructure
  
;{  Structure WAVE_UNION_FULL
;     StructureUnion
;       Extensible.WAVE_EXTENSIBLE_FULL
;       FloatLegacy.WAVE_FLOAT_LEGACY_FULL
;       PcmLegacy.WAVE_PCM_LEGACY_FULL
;     EndStructureUnion
;}  EndStructure
  
  
  Structure RawWaveMemory
    real.i
    wave.i
    mode.i
  EndStructure
  NewList RawWaveMemory.RawWaveMemory()
  
  Procedure.i AllocateRawWaveMemory( Size , Flags = #PBEX_Sound_CatchMode_PokeHeader ) ; #PB_Memory_NoClear als Flag möglich
    Shared RawWaveMemory()
    Define Ergebnis , *Memory , Offset , CatchMode
    
    If Size
      
      CatchMode = Flags & #PBEX_Sound_CatchMode_BITMASK
      
      Select CatchMode
      
      Case #PBEX_Sound_CatchMode_PokeHeader
        Size = SizeOf( WAVE_EXTENSIBLE ) + ( Size + 1 ) & ~1
        Offset = SizeOf( WAVE_EXTENSIBLE )
        
      Case #PBEX_Sound_CatchMode_MoveData
        Size = SizeOf( WAVE_EXTENSIBLE ) + ( Size + 1 ) & ~1
        ;Offset = 0
        
      Case #PBEX_Sound_CatchMode_Normal
        Size = ( Size + 1 ) & ~1
        ;Offset = 0
        
      Default ; #PBEX_Sound_CatchMode_AutoDetect
        ProcedureReturn #False
        
      EndSelect
      
      
      *Memory = AllocateMemory( Size , Flags & #PB_Memory_NoClear )
      If *Memory
        
        If AddElement( RawWaveMemory() )
          RawWaveMemory()\real = *Memory
          RawWaveMemory()\wave = *Memory + Offset
          RawWaveMemory()\mode = CatchMode
          Ergebnis = RawWaveMemory()\wave
          
        Else
          FreeMemory( *Memory )
          
        EndIf
        
      EndIf
      
    EndIf
    
    ProcedureReturn Ergebnis
  EndProcedure
  
  Procedure.i ReAllocateRawWaveMemory( *RawWaveMemory , Size , Flags = #PBEX_Sound_CatchMode_AutoDetect ) ; #PB_Memory_NoClear als Flag möglich
    Shared RawWaveMemory()
    Define Ergebnis , *NewMemory , Offset , MemMoved
    Define CatchMode      = Flags & #PBEX_Sound_CatchMode_BITMASK
    Define Memory_NoClear = Flags & #PB_Memory_NoClear
    
    If Size
      
      If *RawWaveMemory
        
        ForEach RawWaveMemory()
          
          If RawWaveMemory()\wave = *RawWaveMemory
            
            Size = ( Size + 1 ) & ~1
            Offset = RawWaveMemory()\wave - RawWaveMemory()\real
            
            If CatchMode = #PBEX_Sound_CatchMode_AutoDetect
              CatchMode = RawWaveMemory()\mode
            EndIf
            
            If RawWaveMemory()\mode <> CatchMode And RawWaveMemory()\wave <> RawWaveMemory()\real
              MoveMemory( RawWaveMemory()\wave , RawWaveMemory()\real , MemorySize( RawWaveMemory()\real ) - Offset )
              MemMoved = #True
            EndIf
            
            *NewMemory = ReAllocateMemory( RawWaveMemory()\real , Size + Offset , Memory_NoClear )
            If *NewMemory
              
              RawWaveMemory()\real = *NewMemory
              RawWaveMemory()\wave = *NewMemory + Offset
              RawWaveMemory()\mode = CatchMode
              
              If MemMoved And RawWaveMemory()\real <> RawWaveMemory()\wave
                MoveMemory( RawWaveMemory()\real , RawWaveMemory()\wave , Size )
              EndIf
              
              Ergebnis = RawWaveMemory()\wave
              
            ElseIf MemMoved And RawWaveMemory()\real <> RawWaveMemory()\wave
              
              MoveMemory( RawWaveMemory()\real , RawWaveMemory()\wave , MemorySize( RawWaveMemory()\real ) - Offset )
              
            EndIf
            
            Break
            
          EndIf
          
        Next
        
      Else
        Ergebnis = AllocateRawWaveMemory( Size , Flags )
        
      EndIf
      
    EndIf
    
    ProcedureReturn Ergebnis
  EndProcedure
  
  Procedure.i FreeRawWaveMemory( *RawWaveMemory )
    Shared RawWaveMemory()
    
    ForEach RawWaveMemory()
      If RawWaveMemory()\wave = *RawWaveMemory
        FreeMemory( RawWaveMemory()\real )
        DeleteElement( RawWaveMemory() )
        ProcedureReturn #True
      EndIf
    Next
    
    ProcedureReturn #False
  EndProcedure
  
  Procedure.i RawWaveMemorySize( *RawWaveMemory , ReturnFullSize = #False )
    Shared RawWaveMemory()
    
    ForEach RawWaveMemory()
      If RawWaveMemory()\wave = *RawWaveMemory
        If ReturnFullSize
          ProcedureReturn MemorySize( RawWaveMemory()\real )
        Else
          ProcedureReturn MemorySize( RawWaveMemory()\real ) - ( RawWaveMemory()\wave - RawWaveMemory()\real )
        EndIf
      EndIf
    Next
    
    ProcedureReturn #False
  EndProcedure
  
  
  Procedure.i PokeWaveHeader( *Memory.WAVE_UNION , WaveBytes , Bits , SamplingRate , Channels , ChannelFormat , SoundFormat , Flags = #PBEX_Sound_LegacyMode_Off )
    
    Define LegacyMode = Flags & #PBEX_Sound_LegacyMode_BITMASK
    Define WaveBytes = ( WaveBytes + 1 ) & ~1
    
    If LegacyMode = #PBEX_Sound_LegacyMode_Off
      If *Memory
        CopyMemory( ?Header_WAVE_EXTENSIBLE , *Memory , SizeOf( WAVE_EXTENSIBLE ) )
        With *Memory\Extensible
          \Format       = SoundFormat
          \SampleRate   = SamplingRate
          \Channels     = Channels
          \ChannelMask  = ChannelFormat
          \Bits         = ( Bits + 7 ) & ~7
          \BitsValid    = Bits
          \BlockSize    = \Bits>>3 * \Channels
          \ByteRate     = \SampleRate * \BlockSize
          \WaveBytes    = WaveBytes
          \SamplesTotal = \WaveBytes / \BlockSize
          \AddWaveBytes + \WaveBytes
        EndWith
      EndIf
      ProcedureReturn SizeOf( WAVE_EXTENSIBLE )
      
    ElseIf SoundFormat = #PBEX_Sound_Format_FLOAT
      If *Memory = 0 Or LegacyMode = #PBEX_Sound_LegacyMode_Force Or ( Channels <= 2 And Bits & ~7 = 0 And ChannelFormat = 0 )
        If *Memory
          CopyMemory( ?Header_WAVE_FLOAT_LEGACY , *Memory , SizeOf( WAVE_FLOAT_LEGACY ) )
          With *Memory\FloatLegacy
            \SampleRate   = SamplingRate
            \Channels     = Channels
            \Bits         = Bits
            \BlockSize    = \Bits>>3 * \Channels
            \ByteRate     = \SampleRate * \BlockSize
            \WaveBytes    = WaveBytes
            \SamplesTotal = \WaveBytes / \BlockSize
            \AddWaveBytes + \WaveBytes
          EndWith
        EndIf
        ProcedureReturn SizeOf( WAVE_FLOAT_LEGACY )
      EndIf
      
    ElseIf SoundFormat = #PBEX_Sound_Format_PCM
      If *Memory = 0 Or LegacyMode = #PBEX_Sound_LegacyMode_Force Or ( Bits <= 16 And Channels <= 2 And Bits & ~7 = 0 And ChannelFormat = 0 )
        If *Memory
          CopyMemory( ?Header_WAVE_PCM_LEGACY , *Memory , SizeOf( WAVE_PCM_LEGACY ) )
          With *Memory\PcmLegacy
            \SampleRate   = SamplingRate
            \Channels     = Channels
            \Bits         = Bits
            \BlockSize    = Bits>>3 * Channels
            \ByteRate     = \SampleRate * \BlockSize
            \WaveBytes    = WaveBytes
            \AddWaveBytes + \WaveBytes
          EndWith
        EndIf
        ProcedureReturn SizeOf( WAVE_PCM_LEGACY )
      EndIf
      
    EndIf
    
    If LegacyMode = #PBEX_Sound_LegacyMode_Prefer
      ProcedureReturn PokeWaveHeader( *Memory , WaveBytes , Bits , SamplingRate , Channels , ChannelFormat , SoundFormat , #PBEX_Sound_LegacyMode_Off )
    EndIf
    
    ProcedureReturn #False
    
  EndProcedure
  
  Procedure.i CatchRawSound( Sound , *RawData , DataBytes , Bits , SamplingRate , Channels = 1 , ChannelFormat = 0 , SoundFormat = #PBEX_Sound_Format_PCM , Flags = #PBEX_Sound_LegacyMode_Off | #PBEX_Sound_CatchMode_AutoDetect )
    Shared RawWaveMemory()
    Define Ergebnis
    
    Define LegacyMode = Flags & #PBEX_Sound_LegacyMode_BITMASK
    Define CatchMode  = Flags & #PBEX_Sound_CatchMode_BITMASK
    
    If CatchMode = #PBEX_Sound_CatchMode_AutoDetect
      ForEach RawWaveMemory()
        If RawWaveMemory()\wave = *RawData
          Break
        EndIf
      Next
      If ListSize( RawWaveMemory() ) And RawWaveMemory()\wave = *RawData
        CatchMode = RawWaveMemory()\mode
      Else
        CatchMode = #PBEX_Sound_CatchMode_Normal
      EndIf
    EndIf
    
    Define AlignedDataBytes = ( DataBytes + 1 ) & ~1
    Define *Wave.WAVE_EXTENSIBLE
    Define HeaderSize = PokeWaveHeader( 0 , DataBytes , Bits , SamplingRate , Channels , ChannelFormat , SoundFormat , Flags )
    
    If HeaderSize And *RawData
      
      Select CatchMode
      
      Case #PBEX_Sound_CatchMode_Normal
        *Wave.WAVE_EXTENSIBLE = AllocateMemory( SizeOf( WAVE_EXTENSIBLE ) + AlignedDataBytes , #PB_Memory_NoClear )
        
      Case #PBEX_Sound_CatchMode_MoveData
        *Wave.WAVE_EXTENSIBLE = *RawData
        
      Case #PBEX_Sound_CatchMode_PokeHeader
        *Wave.WAVE_EXTENSIBLE = *RawData - HeaderSize
        
      EndSelect
      
      If *Wave
        
        Define *WaveData = *Wave + HeaderSize
        
        If CatchMode = #PBEX_Sound_CatchMode_MoveData
          MoveMemory( *RawData , *WaveData , DataBytes )
        EndIf
        
        PokeWaveHeader( *Wave , DataBytes , Bits , SamplingRate , Channels , ChannelFormat , SoundFormat , Flags )
        
        If CatchMode = #PBEX_Sound_CatchMode_Normal
          CopyMemory( *RawData , *WaveData , DataBytes )
        EndIf
        
        If DataBytes < AlignedDataBytes
          PokeB( *WaveData + DataBytes , 0 )
        EndIf
        
        Ergebnis = CatchSound(Sound, *Wave)
        
      EndIf
      
    EndIf
    
    If *Wave And CatchMode = #PBEX_Sound_CatchMode_Normal
      FreeMemory(*Wave)
    EndIf
    
    ProcedureReturn Ergebnis
  EndProcedure
  
  Procedure.i DolbyDigitalChannels( Number1 , Number2 , Number3 = 0 )
    If Number1 & ~7 Or Number2 & ~3 Or Number3 & ~1 : ProcedureReturn #False : EndIf
    Define Ergebnis
    If Number1 & 1 : Ergebnis | #PBEX_Sound_Speaker_FrontCenter                                            : EndIf
    If Number1 & 2 : Ergebnis | #PBEX_Sound_Speaker_FrontLeft       | #PBEX_Sound_Speaker_FrontRight       : EndIf
    If Number1 & 4 : Ergebnis | #PBEX_Sound_Speaker_FrontCenterLeft | #PBEX_Sound_Speaker_FrontCenterRight : EndIf
    If Number2 & 1 : Ergebnis | #PBEX_Sound_Speaker_BackCenter                                             : EndIf
    If Number2 & 2 : Ergebnis | #PBEX_Sound_Speaker_BackLeft        | #PBEX_Sound_Speaker_BackRight        : EndIf
    If Number3 & 1 : Ergebnis | #PBEX_Sound_Speaker_SubWoofer                                              : EndIf
    ProcedureReturn Ergebnis
  EndProcedure
  
  
  DataSection
    
    Header_WAVE_EXTENSIBLE:   ;{
      Data.a 'R','I','F','F'    ; "RIFF"
      Data.l 72                   ; FileSize-8 ODER 72+WaveBytes=SizeOf(WAVE_EXTENSIBLE)-8+WaveBytes
      Data.a 'W','A','V','E'    ; "WAVE"
      Data.a 'f','m','t',' '    ; "fmt "
      Data.l 40                 ; 40
      Data.u $FFFE              ; $FFFE (#WAVE_FORMAT_EXTENSIBLE)
      Data.u 0                    ; 2 Byte: Channels
      Data.l 0                    ; 4 Byte: SampleRate
      Data.l 0                    ; 4 Byte: ByteRate
      Data.u 0                    ; 2 Byte: BlockSize
      Data.u 0                    ; 2 Byte: Bits
      Data.u 22                 ; 22
      Data.u 0                    ; 2 Byte: ValidBits
      Data.l 0                    ; 4 Byte: ChannelMask
      Data.q $0010000000000000    ; 2 Byte: SubFormat (#WAVE_FORMAT_~)
      Data.q $719B3800AA000080  ; ...
      Data.a 'f','a','c','t'    ; "fact"
      Data.l 4                  ; 4
      Data.l 0                    ; SamplesTotal (Channels * SamplesPerChannel)
      Data.a 'd','a','t','a'    ; "data"
      Data.l 0                    ; 4 Byte: WaveBytes
    EndHeader_WAVE_EXTENSIBLE: ;}
    
    Header_WAVE_FLOAT_LEGACY: ;{
      Data.a 'R','I','F','F'    ; "RIFF"
      Data.l 50                   ; FileSize-8 ODER 50+WaveBytes=SizeOf(WAVE_FLOAT_LEGACY)-8+WaveBytes
      Data.a 'W','A','V','E'    ; "WAVE"
      Data.a 'f','m','t',' '    ; "fmt "
      Data.l 18                 ; 18
      Data.u 3                  ; 3 (#WAVE_FORMAT_IEEE_FLOAT)
      Data.u 0                    ; 2 Byte: Channels
      Data.l 0                    ; 4 Byte: SampleRate
      Data.l 0                    ; 4 Byte: ByteRate
      Data.u 0                    ; 2 Byte: BlockSize
      Data.u 0                    ; 2 Byte: Bits
      Data.u 0                  ; 0 
      Data.a 'f','a','c','t'    ; "fact"
      Data.l 4                  ; 4
      Data.l 0                    ; SamplesTotal (Channels * SamplesPerChannel)
      Data.a 'd','a','t','a'    ; "data"
      Data.l 0                    ; 4 Byte: WaveBytes
    EndHeader_WAVE_FLOAT_LEGACY: ;}
    
    Header_WAVE_PCM_LEGACY:   ;{
      Data.a 'R','I','F','F'    ; "RIFF"
      Data.l 36                   ; FileSize-8 ODER 36+WaveBytes=SizeOf(WAVE_PCM_LEGACY)-8+WaveBytes
      Data.a 'W','A','V','E'    ; "WAVE"
      Data.a 'f','m','t',' '    ; "fmt "
      Data.l 16                 ; 16
      Data.u 1                  ; 1 (#WAVE_FORMAT_PCM)
      Data.u 0                    ; 2 Byte: Channels
      Data.l 0                    ; 4 Byte: SampleRate
      Data.l 0                    ; 4 Byte: ByteRate
      Data.u 0                    ; 2 Byte: BlockSize
      Data.u 0                    ; 2 Byte: Bits
      Data.a 'd','a','t','a'    ; "data"
      Data.l 0                    ; 4 Byte: WaveBytes
    EndHeader_WAVE_PCM_LEGACY: ;}
    
  EndDataSection
  
  
EndModule

;{ ==== TESTCODE ====
CompilerIf #True And #PB_Compiler_IsMainFile And #PB_Compiler_Debugger
  EnableExplicit
  
  ;XIncludeFile #PB_Compiler_FilePath + "pbex_Constants.pbi"
  ;XIncludeFile #PB_Compiler_FilePath + "pbex_Math.pbi"
  
  ;UseModule pbex_Constants
  ;UseModule pbex_Math
  
  InitSound()
  
  UseModule pbex_Sound
  
  CompilerSelect 3
  
  CompilerCase 1
    Define i, *mem = AllocateMemory(44100 * SizeOf(Word) + 1)
    Define *w.Word = *mem
    For i = 1 To 44100
      ;*w\w = #WordMax * RandomD(1.0, -1.0)
      ;*w\w = #WordMax * Sin(#PI2 * i*1000/44100)
      *w\w = $7FFF * Sin(#PI*2 * i*1000/44100)
      *w + SizeOf(Word)
    Next i
    Debug CatchRawSound(0, *mem, MemorySize(*mem), 16, 44100)
    Debug PlaySound(0)
    MessageRequester("","")
  
  CompilerCase 2
    Define i, *mem = AllocateMemory(44100 * SizeOf(Float))
    Define *f.Float = *mem
    For i = 1 To 44100
      ;*w\w = #WordMax * RandomD(1.0, -1.0)
      ;*f\f = Sin(#pi2 * i*1000/44100)
      *f\f = Sin(#PI*2 * i*1000/44100)
      *f + SizeOf(Float)
    Next i
    Debug CatchRawSound(0, *mem, MemorySize(*mem), 32, 44100, 1, 0, #PBEX_Sound_Format_FLOAT)
    Debug PlaySound(0)
    MessageRequester("","")
  
  CompilerCase 3
    Define i, *mem = AllocateMemory(44100 * SizeOf(Float))
    Define *f.Float = *mem
    For i = 1 To 44100
      ;*f\f = Sin( #pi2 * i * 220 / 44100 )
      *f\f = Sin( #PI*2 * i * 220 / 44100 )
      If *f\f >= 0.0
        *f\f = 1.0
      Else
        *f\f = -1.0
      EndIf
      *f + SizeOf(Float)
    Next i
    Debug CatchRawSound(0, *mem, MemorySize(*mem), 32, 44100, 1, 0, #PBEX_Sound_Format_FLOAT)
    Debug PlaySound(0)
    MessageRequester("","")
  
  CompilerEndSelect
  
CompilerEndIf
;} ==== TESTCODE ====
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
es_91
Beiträge: 383
Registriert: 25.01.2011 04:48

Re: Wave-Datei schreiben

Beitrag von es_91 »

Regenduft, vielen Dank für Deinen langen code, ich habe zwar noch keinen Nutzen daraus ziehen können, weil ich zu Träge bin, ihn zu analysieren, aber ich komme sicher irgendwann darauf zurück. Einstweilen wollte ich noch sagen, dass ich das Thema als abgeschlossen betrachte, weil ich meine files zwar nicht im Windows Media Player zum Laufen bringe, sie aber in der Software laufen, für die ich sie brauch(t)e.

Danke an Alle, die sich aktiv oder auch passiv beteiligt haben, besonderen Dank an Derren und Regenduft!

Bis bald!
Rebon
Beiträge: 263
Registriert: 20.05.2009 19:13

Re: Wave-Datei schreiben

Beitrag von Rebon »

Regenduft hat geschrieben:

Code: Alles auswählen

\Bits         = ( Bits + 7 ) & ~7
Ich hätte da mal eine Frage. :)
Gibt es einen speziellen Grund weshalb du extra per "Bitweises NOT" eine Dezimalzahl, wie in dem hier zitierten Fall die 7, invertierst und nicht direkt eine -8 verwendest?
Als Binärzahl könnte ich es noch nachvollziehen, wenn diese direkt ausgelesen werden kann, also nicht wie folgender Code.

Code: Alles auswählen

\Bits         = ( Bits + 7 ) & ~%00000111
Aber vielleicht sehe ich auch nur den Wald vor lauter Bäumen nicht, dann würde ich mich über eine Aufklärung freuen. :wink:
PB 4.00 | Windows XP Home SP3
Benutzeravatar
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

Re: Wave-Datei schreiben

Beitrag von Regenduft »

@Rebon: Das ist einfach ein Standardtrick, den ich mir angewöhnt habe um schnell zu Quantisieren. Soll heißen (in diesem Fall) auf ein durch 8 teilbares Ergebnis aufzurunden. Bei einer Zweierpotenz (1,2,4,8,...) ist ja immer nur ein einzelnes Bit gesetzt. Minus ein, dann ist es selbst nicht mehr, dafür aber alle Bits darunter gesetzt. Das ist also (sozusagen) eine Vereinfachung von:

Code: Alles auswählen

\Bits = ( Bits + (8-1) ) & ~(8-1)
bzw. verallgemeinert:

Code: Alles auswählen

QuantisierterWert = ( Wert + (ZweierPotenz-1) ) & ~(ZweierPotenz-1)
Das zweimal "7" (im Original) vorkommt, hat halt den Vorteil, dass ich einfach für sieben eine Variable einsetzen kann.

...habe ich's jetzt erklärt oder verkompliziert... :?:

Ein Code sagt mehr als tausend Worte: :wink:

Code: Alles auswählen

Quantisierung = 8 ; <- Spiel mit mir! Aber nur 2er-Potenzen... ;)

HilfsVariable = Quantisierung - 1

For i = 0 To $FF
  
  x = ( i + HilfsVariable ) & ~HilfsVariable
  
  Debug RSet( Str( i ) , 3, " " ) + " -> " +
        RSet( Str( x ) , 3, " " ) + " = $" +
        RSet( Hex( x ) , 2, "0" ) + " = %" +
        RSet( Bin( x ) , 8, "0" )
  
Next
@es_91: Sorry... war ein wenig blöd den Code einfach hinzuklatschen ohne irgendetwas zu sagen. Falls Dich doch noch die Muse packt: Wenn ich es richtig erkannt habe, dann ist Dein Header an und für sich fehlerfrei! Allerdings entspricht er wohl nicht ganz der Norm. Darum spielt ihn auch das eine Prog ab (findete ja alle benötigten Informationen im Header) und der Windows Media Player nicht, weil (wenn ich das einfach mal hineininterpretiere) Microsoft halt will, dass sich die "Sound-Ersteller" bitte genau an die von Ihnen definierte Norm halten. Ergibt auch Sinn, denn früher hatten viele einfach munter irgendwelche eigenen abartigen Wave-Formate erfunden und fröhlich die Headerfelder zweckentfremdet, was ein riesiges Chaos zur Folge hatte. Kann aber auch sein, dass das abspielende Programm einfach einige Felder nicht zur Berechnung nutzt, da in den beiden neueren Wave-Formaten (ich komme gleich drauf) es redundante Informationen gibt, d.h. manches ist eigentlich überflüssig und "doppelgemoppelt". Man kann zur Berechnung das eine oder das andere Feld benutzen.

Es gibt (sozusagen) drei Wave-Grundformate. (alle Infos evtl. nicht 100%ig exakt):
  1. Das uralte (und vermutlich immernoch am weitesten verbreitete) hat einen 44 Byte großen Header, kann nur 8 und 16 Bit, max. zwei Kanäle und hat (per Definition) noch andere Einschränkungen und Hirnrissigkeiten, wie z.B. dass 8 Bit unsigned sind (also ".a" statt ".b" in PB) und 16 Bit signed (also ".w" statt ".u" in PB). Hab' ich aber nicht alles im Kopf! :wink:
  2. Das etwas neuere hat einen 58 Byte großen Header und ist einfach einfach nur eine verpfriemelte Variante des alten Headers. Es unterstützt zusätzlich neben 8, 16, 32 und 64 Bit. Außerdem nicht nur Integer sondern auch Floats.
  3. Das aktuelle Wave-Formate (alias "Extensible") hat einen 80 Byte großen Header und ist ein noch weiter getriebene Verpfriemelung der beiden alten Formate. Dieses Format ist der absolute Overkill und kann z.B. auch MP3- oder OGG-Daten enthalten. Darum unterstützt so ziemlich kein Programm das komplett (außer natürlich Wave-Editoren u.ä.).
Halbwegs sicher kann man die Formate am Word (".w" in PB, genaugenommen eigentlich ".u") an Offset 36 unterscheiden:
  • Das neuste hat hier den Wert 22 stehen
  • Das "mittel-neue" hat hier den Wert Null stehen.
  • Das uralte hat hier den Wert 24932 stehen. (24932 = "data" in Ascii)
Also folgender Code, dann weißt Du welches Format es ist:

Code: Alles auswählen

Debug PeekU( *wave + 22 )
Wenn es das ganz neue ist, dann nimm meine "WAVE_EXTENSIBLE" Struktur.
Wenn es das "mittel-neue" ist, dann nimm meine "WAVE_WAVE_FLOAT_LEGACY" Struktur (lass Dich vom Float nicht irritieren, geht auch mit Integern).
Wenn es das uralte ist, dann nimm meine "WAVE_PCM_LEGACY" Struktur.
Ganz wichtig! Die Wavelänge muss immer Gerade sein! Wenn Sie ungerade ist, dann hänge einfach eine Null an!
Nun die Felder wie folgt bearbeiten (Pseudo-Code):

Code: Alles auswählen

SampleRate = 22050
ByteRate = SampleRate * BlockSize
WaveBytes / 2
If WaveBytes & 1 ; ungerade?
  WaveBytes + 1 ; gerade!
EndIf

AddWaveBytes = 72 + WaveBytes ; nur bei "WAVE_EXTENSIBLE"
AddWaveBytes = 50 + WaveBytes ; nur bei "WAVE_FLOAT_LEGACY"
AddWaveBytes = 36 + WaveBytes ; nur bei "WAVE_PCM_LEGACY"

SamplesTotal / 2 ; nur bei "WAVE_EXTENSIBLE" und "WAVE_FLOAT_LEGACY"
Falls Du mit Strukturen noch nicht umgehen kannst, dann frage einfach! Das wirkt kompliziert, ist aber ganz einfach eine bequeme Alternative zu dem ganzen Peek() und Poke() Kram.

Ich muss übrigens noch zugeben, dass ich die Strukturfelder manchmal ganz pragmatisch einfach nach dem benannt habe, was ich damit machen muss (z.B. "AddWaveBytes"), anstatt ordentliche Namen zu wählen... Darum sagte ich auch, es ist ein extrem hässlicher Code... :oops:

Die Formeln zur Berechnung der einzelnen Strukturfelder findest Du übrigens als Kommentar dahinter. Da kannst Du Dich mal "durchhangeln", wenn Du richtig verstehen willst, wie das eigentlich alles zusammenhängt. Alle meine Infos hatte ich von Wikipedia und vor allem von hier:
http://www-mmsp.ece.mcgill.ca/Documents ... /WAVE.html (auf der Wiki-Seite verlinkt :wink:)
Zuletzt geändert von Regenduft am 21.06.2014 04:44, insgesamt 1-mal geändert.
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
Antworten