2 * File: $RCSfile: OBuffer_Wave.pas,v $
3 * Revision: $Revision: 1.1.1.1 $
4 * Version : $Id: OBuffer_Wave.pas,v 1.1.1.1 2002/04/21 12:57:22 fobmagog Exp $
5 * Author: $Author: fobmagog $
6 * Homepage: http://delphimpeg.sourceforge.net/
7 * Kol translation by Thaddy de Koning
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 Windows
, MMSystem
, kol
, KolShared
, kolplayer
, kolobuffer
, err
;
32 POBuffer_wave
= ^TOBuffer_wave
;
33 TOBuffer_Wave
= object(TObuffer
)
35 FBufferP
: array[0..MAX_CHANNELS
- 1] of cardinal;
42 mmioinfoOut
: MMIOINFO
;
47 // constructor Create(NumberOfChannels: Cardinal; Player: PObj; Filename: String);
48 destructor Destroy
; virtual;
50 procedure Append(Channel
: cardinal; Value
: smallint
); virtual;
51 procedure WriteBuffer
; virtual;
54 procedure ClearBuffer
; virtual;
55 procedure SetStopFlag
; virtual;
58 function NewObuffer_wave(NumberOfChannels
: cardinal; Player
: PPlayer
;
59 Filename
: string): POBuffer_wave
;
60 function CreateWaveFileOBffer(Player
: PPlayer
; Filename
: string): POBuffer_wave
;
67 function CreateWaveFileOBffer(Player
: PPlayer
; Filename
: string): POBuffer_wave
;
70 WhichChannels
: TChannels
;
73 WhichChannels
:= Player
.Channels
;
75 if ((Mode
= SingleChannel
) or (WhichChannels
<> both
)) then
76 Result
:= NewObuffer_wave(1, Player
, Filename
) // mono
78 Result
:= NewObuffer_wave(2, Player
, Filename
); // stereo
87 // Need to break up the 32-bit integer into 2 8-bit bytes.
88 // (ignore the first two bytes - either 0x0000 or 0xffff)
89 // Note that Intel byte order is backwards!!!
90 procedure TOBuffer_Wave
.Append(Channel
: cardinal; Value
: smallint
);
92 FTemp
[FBufferP
[Channel
]] := (Value
and $ff);
93 FTemp
[FBufferP
[Channel
] + 1] := (Value
shr 8);
95 inc(FBufferP
[Channel
], FChannels
shl 1);
98 procedure TOBuffer_Wave
.ClearBuffer
;
100 // Since we write each frame, and seeks and stops occur between
101 // frames, nothing is needed here.
104 //constructor TOBuffer_Wave.Create
105 function newobuffer_wave(NumberOfChannels
: cardinal; Player
: PPlayer
;
106 Filename
: string): PObuffer_wave
;
114 FChannels
:= NumberOfChannels
;
116 FDataSize
:= FChannels
* OBUFFERSIZE
;
118 if (Player
.Version
= MPEG2_LSF
) then
119 FDataSize
:= FDataSize
shr 1;
121 if (Player
.Layer
= 1) then
122 FDataSize
:= FDataSize
div 3;
124 FTemp
:= AllocMem(FDataSize
);
126 hmmioOut
:= mmioOpen(PChar(FileName
), nil, MMIO_ALLOCBUF
or MMIO_WRITE
or MMIO_CREATE
);
127 if (hmmioOut
= 0) then
128 raise Exception
.Create(e_Custom
, 'Output device failure');
130 // Create the output file RIFF chunk of form type WAVE.
131 ckOutRIFF
.fccType
:= Ord('W') or (Ord('A') shl 8) or (Ord('V') shl 16) or
133 ckOutRIFF
.cksize
:= 0;
134 if (mmioCreateChunk(hmmioOut
, @ckOutRIFF
, MMIO_CREATERIFF
) <> MMSYSERR_NOERROR
) then
135 raise Exception
.Create(e_Custom
, 'Output device failure');
137 // Initialize the WAVEFORMATEX structure
139 pwf
.wBitsPerSample
:= 16; // No 8-bit support yet
140 pwf
.wFormatTag
:= WAVE_FORMAT_PCM
;
141 pwf
.nChannels
:= FChannels
;
142 pwf
.nSamplesPerSec
:= Player
.Frequency
;
143 pwf
.nAvgBytesPerSec
:= (FChannels
* Player
.Frequency
shl 1);
144 pwf
.nBlockAlign
:= (FChannels
shl 1);
147 // Create the fmt chunk
148 ckOut
.ckid
:= Ord('f') or (Ord('m') shl 8) or (Ord('t') shl 16) or (Ord(' ') shl 24);
149 ckOut
.cksize
:= sizeof(pwf
);
151 if (mmioCreateChunk(hmmioOut
, @ckOut
, 0) <> MMSYSERR_NOERROR
) then
152 raise Exception
.Create(e_Custom
, 'Output device failure');
154 // Write the WAVEFORMATEX structure to the fmt chunk.
156 if (mmioWrite(hmmioOut
, @pwf
, sizeof(pwf
)) <> sizeof(pwf
)) then
157 raise Exception
.Create(e_Custom
, 'Output device failure');
159 // Ascend out of the fmt chunk, back into the RIFF chunk.
160 if (mmioAscend(hmmioOut
, @ckOut
, 0) <> MMSYSERR_NOERROR
) then
161 raise Exception
.Create(e_Custom
, 'Output device failure');
163 // Create the data chunk that holds the waveform samples.
164 ckOut
.ckid
:= Ord('d') or (Ord('a') shl 8) or (Ord('t') shl 16) or (Ord('a') shl 24);
166 if (mmioCreateChunk(hmmioOut
, @ckOut
, 0) <> MMSYSERR_NOERROR
) then
167 raise Exception
.Create(e_Custom
, 'Output device failure');
169 mmioGetInfo(hmmioOut
, @mmioinfoOut
, 0);
171 for i
:= 0 to FChannels
- 1 do
172 FBufferP
[i
] := i
* FChannels
;
176 destructor TOBuffer_Wave
.Destroy
;
178 // Mark the current chunk as dirty and flush it
179 mmioinfoOut
.dwFlags
:= mmioinfoOut
.dwFlags
or MMIO_DIRTY
;
180 if (mmioSetInfo(hmmioOut
, @mmioinfoOut
, 0) <> MMSYSERR_NOERROR
) then
181 raise Exception
.Create(e_Custom
, 'Output device failure');
183 // Ascend out of data chunk
184 if (mmioAscend(hmmioOut
, @ckOut
, 0) <> MMSYSERR_NOERROR
) then
185 raise Exception
.Create(e_Custom
, 'Output device failure');
187 // Ascend out of RIFF chunk
188 if (mmioAscend(hmmioOut
, @ckOutRIFF
, 0) <> MMSYSERR_NOERROR
) then
189 raise Exception
.Create(e_Custom
, 'Output device failure');
192 if (mmioClose(hmmioOut
, 0) <> MMSYSERR_NOERROR
) then
193 raise Exception
.Create(e_Custom
, 'Output device failure');
195 // Free the buffer memory
203 procedure TOBuffer_Wave
.SetStopFlag
;
207 function Min(A
, B
: cardinal): integer; overload
;
215 procedure TOBuffer_Wave
.WriteBuffer
;
219 Write
:= Min(FDataSize
, cardinal(mmioinfoOut
.pchEndWrite
) - cardinal(mmioinfoOut
.pchNext
));
221 Move(FTemp
^, mmioinfoOut
.pchNext
^, Write
);
222 inc(cardinal(mmioinfoOut
.pchNext
), Write
);
224 if (Write
< FDataSize
) then
226 mmioinfoOut
.dwFlags
:= mmioinfoOut
.dwFlags
or MMIO_DIRTY
;
228 if (mmioAdvance(hmmioOut
, @mmioinfoOut
, MMIO_WRITE
) <> MMSYSERR_NOERROR
) then
229 raise Exception
.Create(e_Custom
, 'Output device failure');
232 Move(FTemp
[Write
], mmioinfoOut
.pchNext
^, FDataSize
- Write
);
233 inc(cardinal(mmioinfoOut
.pchNext
), FDataSize
- Write
);
235 // Reset buffer pointers
236 for i
:= 0 to FChannels
- 1 do
237 FBufferP
[i
] := i
* FChannels
;