initial commit
[rofl0r-KOL.git] / units / mp3 / KOLOBuffer_Wave.pas
blobb3fb9fca6b66d3c4323bae7689a10baef65c35cb
1 (*
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.
23 {$DEFINE SEEK_STOP}
24 unit KOLOBuffer_Wave;
26 interface
28 uses
29 Windows, MMSystem, kol, KolShared, kolplayer, kolobuffer, err;
31 type
32 POBuffer_wave = ^TOBuffer_wave;
33 TOBuffer_Wave = object(TObuffer)
34 private
35 FBufferP: array[0..MAX_CHANNELS - 1] of cardinal;
36 FChannels: cardinal;
37 FDataSize: cardinal;
39 FTemp: PByteArray;
41 hmmioOut: HMMIO;
42 mmioinfoOut: MMIOINFO;
43 ckOutRIFF: MMCKINFO;
44 ckOut: MMCKINFO;
46 public
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;
53 {$IFDEF SEEK_STOP}
54 procedure ClearBuffer; virtual;
55 procedure SetStopFlag; virtual;
56 {$ENDIF}
57 end;
58 function NewObuffer_wave(NumberOfChannels: cardinal; Player: PPlayer;
59 Filename: string): POBuffer_wave;
60 function CreateWaveFileOBffer(Player: PPlayer; Filename: string): POBuffer_wave;
62 implementation
64 uses
65 KolMath, KolHeader;
67 function CreateWaveFileOBffer(Player: PPlayer; Filename: string): POBuffer_wave;
68 var
69 Mode: TMode;
70 WhichChannels: TChannels;
71 begin
72 Mode := Player.Mode;
73 WhichChannels := Player.Channels;
74 try
75 if ((Mode = SingleChannel) or (WhichChannels <> both)) then
76 Result := NewObuffer_wave(1, Player, Filename) // mono
77 else
78 Result := NewObuffer_wave(2, Player, Filename); // stereo
79 except
80 on E: Exception do
81 Result := nil;
82 end;
83 end;
85 { TOBuffer_Wave }
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);
91 begin
92 FTemp[FBufferP[Channel]] := (Value and $ff);
93 FTemp[FBufferP[Channel] + 1] := (Value shr 8);
95 inc(FBufferP[Channel], FChannels shl 1);
96 end;
98 procedure TOBuffer_Wave.ClearBuffer;
99 begin
100 // Since we write each frame, and seeks and stops occur between
101 // frames, nothing is needed here.
102 end;
104 //constructor TOBuffer_Wave.Create
105 function newobuffer_wave(NumberOfChannels: cardinal; Player: PPlayer;
106 Filename: string): PObuffer_wave;
107 var
108 pwf: TWAVEFORMATEX;
109 i: cardinal;
110 begin
111 New(Result, Create);
112 with Result^ do
113 begin
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
132 (Ord('E') shl 24);
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);
145 pwf.cbSize := 0;
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);
165 ckOut.cksize := 0;
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;
173 end;
174 end;
176 destructor TOBuffer_Wave.Destroy;
177 begin
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');
191 // Close the file
192 if (mmioClose(hmmioOut, 0) <> MMSYSERR_NOERROR) then
193 raise Exception.Create(e_Custom, 'Output device failure');
195 // Free the buffer memory
197 FreeMem(FTemp);
198 except
199 on E: Exception do;
200 end;
201 end;
203 procedure TOBuffer_Wave.SetStopFlag;
204 begin
205 end;
207 function Min(A, B: cardinal): integer; overload;
208 begin
209 if A < B then
210 Result := A
211 else
212 Result := B;
213 end;
215 procedure TOBuffer_Wave.WriteBuffer;
216 var
217 Write, i: cardinal;
218 begin
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
225 begin
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');
230 end;
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;
238 end;
240 end.