Author: Tomas Rutkauskas
How to generate a wave file and play it backwards
Answer:
Here's some code that plays a *.wav file backwards. It shows how *.wav files are
generated.
1 procedure Interchange(hpchPos1, hpchPos2: PChar; wLength: word);
2 var
3 wPlace: word;
4 bTemp: char;
5 begin
6 for wPlace := 0 to wLength - 1 do
7 begin
8 bTemp := hpchPos1[wPlace];
9 hpchPos1[wPlace] := hpchPos2[wPlace];
10 hpchPos2[wPlace] := bTemp
11 end
12 end;
13
14 procedure ReversePlay(const szFileName: string);
15 var
16 mmioHandle: HMMIO;
17 mmckInfoParent: MMCKInfo;
18 mmckInfoSubChunk: MMCKInfo;
19 dwFmtSize, dwDataSize: DWORD;
20 pFormat: PWAVEFORMATEX;
21 wBlockSize: word;
22 hpch1, hpch2: PChar;
23 waveOutHAndle: Integer;
24 data: PChar;
25 waveHdr: PWAVEHDR;
26 begin
27 data := nil;
28 mmioHandle := mmioOpen(PChar(szFileName), nil, MMIO_READ or MMIO_ALLOCBUF);
29 if mmioHandle = 0 then
30 raise Exception.Create('Unable to open file ' + szFileName);
31 try
32 mmckInfoParent.fccType := mmioStringToFOURCC('WAVE', 0);
33 if mmioDescend(mmioHandle, @mmckinfoParent, nil,
34 MMIO_FINDRIFF) <> MMSYSERR_NOERROR then
35 raise Exception.Create(szFileName + ' is not a valid wave file');
36 mmckinfoSubchunk.ckid := mmioStringToFourCC('fmt ', 0);
37 if mmioDescend(mmioHandle, @mmckinfoSubchunk, @mmckinfoParent,
38 MMIO_FINDCHUNK) <> MMSYSERR_NOERROR then
39 raise Exception.Create(szFileName + ' is not a valid wave file');
40 dwFmtSize := mmckinfoSubchunk.cksize;
41 GetMem(pFormat, dwFmtSize);
42 try
43 if DWORD(mmioRead(mmioHandle, PChar(pFormat), dwFmtSize)) <> dwFmtSize then
44 raise Exception.Create('Error reading wave data');
45 if pFormat^.wFormatTag <> WAVE_FORMAT_PCM then
46 raise Exception.Create('Invalid wave file format');
47 if waveOutOpen(@waveOutHandle, WAVE_MAPPER, pFormat, 0, 0,
48 WAVE_FORMAT_QUERY) <> MMSYSERR_NOERROR then
49 raise Exception.Create('Can''t play format');
50 mmioAscend(mmioHandle, @mmckinfoSubchunk, 0);
51 mmckinfoSubchunk.ckid := mmioStringToFourCC('data', 0);
52 if mmioDescend(mmioHandle, @mmckinfoSubchunk, @mmckinfoParent,
53 MMIO_FINDCHUNK) <> MMSYSERR_NOERROR then
54 raise Exception.Create('No data chunk');
55 dwDataSize := mmckinfoSubchunk.cksize;
56 if dwDataSize = 0 then
57 raise Exception.Create('Chunk has no data');
58 if waveOutOpen(@waveOutHandle, WAVE_MAPPER, pFormat, 0, 0,
59 CALLBACK_NULL) <> MMSYSERR_NOERROR then
60 begin
61 waveOutHandle := 0;
62 raise Exception.Create('Failed to open output device');
63 end;
64 wBlockSize := pFormat^.nBlockAlign;
65 ReallocMem(pFormat, 0);
66 ReallocMem(data, dwDataSize);
67 if DWORD(mmioRead(mmioHandle, data, dwDataSize)) <> dwDataSize then
68 raise Exception.Create('Unable to read data chunk');
69 hpch1 := data;
70 hpch2 := data + dwDataSize - 1;
71 while hpch1 < hpch2 do
72 begin
73 Interchange(hpch1, hpch2, wBlockSize);
74 Inc(hpch1, wBlockSize);
75 Dec(hpch2, wBlockSize)
76 end;
77 GetMem(waveHdr, sizeof(WAVEHDR));
78 waveHdr^.lpData := data;
79 waveHdr^.dwBufferLength := dwDataSize;
80 waveHdr^.dwFlags := 0;
81 waveHdr^.dwLoops := 0;
82 waveHdr^.dwUser := 0;
83 if waveOutPrepareHeader(WaveOutHandle, WaveHdr,
84 sizeof(WAVEHDR)) <> MMSYSERR_NOERROR then
85 raise Exception.Create('Unable to prepare header');
86 if waveOutWrite(WaveOutHandle, WaveHdr, sizeof(WAVEHDR)) <> MMSYSERR_NOERROR
87 then
88 raise Exception.Create('Failed to write to device');
89 finally
90 ReallocMem(pFormat, 0)
91 end;
92 finally
93 mmioClose(mmioHandle, 0)
94 end;
95 end;
|