DEADSOFTWARE

sound: do not crash if FMOD cant be initialized
[d2df-editor.git] / src / editor / f_addresource_sound.pas
1 unit f_addresource_sound;
3 {$INCLUDE ../shared/a_modes.inc}
5 interface
7 uses
8 LCLIntf, LCLType, LMessages, SysUtils, Variants, Classes,
9 Graphics, Controls, Forms, Dialogs, f_addresource,
10 ExtCtrls, StdCtrls, spectrum, Buttons, ComCtrls, utils;
12 type
13 TAddSoundForm = class (TAddResourceForm)
14 pSpectrum: TPanel;
15 bbPlay: TBitBtn;
16 bbStop: TBitBtn;
17 Timer: TTimer;
18 bEmpty: TButton;
20 procedure FormCreate(Sender: TObject);
21 procedure bbPlayClick(Sender: TObject);
22 procedure TimerTimer(Sender: TObject);
23 procedure FormDestroy(Sender: TObject);
24 procedure FormClose(Sender: TObject; var Action: TCloseAction);
25 procedure bbStopClick(Sender: TObject);
26 procedure FormActivate(Sender: TObject);
27 procedure bOKClick(Sender: TObject);
28 procedure bEmptyClick(Sender: TObject);
30 private
31 FSpectrum: TMiniSpectrum;
32 FSetResource: String;
33 FSoundEnabled: Boolean;
35 procedure ShowSpectrum();
36 function CreateSoundWAD(Resource: String): Boolean;
38 public
39 property SetResource: String read FSetResource write FSetResource;
40 end;
42 var
43 AddSoundForm: TAddSoundForm;
45 implementation
47 uses
48 BinEditor, WADEDITOR, e_log, f_main, g_language, g_resources
49 {$IFNDEF NOSOUND}, fmod, fmodtypes, fmoderrors;{$ELSE};{$ENDIF}
51 {$R *.lfm}
53 {$IFDEF NOSOUND}
54 // fuck my life
55 const
56 FMOD_OK = 0;
58 type
59 FMOD_SYSTEM = Pointer;
60 FMOD_CHANNEL = Pointer;
61 FMOD_SOUND = Pointer;
62 FMOD_CREATESOUNDEXINFO = Pointer;
63 FMOD_RESULT = Integer;
64 {$ENDIF}
66 var
67 F_System: FMOD_SYSTEM;
68 SoundData: Pointer = nil;
69 Sound: FMOD_SOUND = nil;
70 Channel: FMOD_CHANNEL = nil;
71 Playing: Boolean = False;
73 procedure TAddSoundForm.FormCreate(Sender: TObject);
74 var
75 res: FMOD_RESULT;
76 ver: Cardinal;
78 begin
79 Inherited;
81 res := FMOD_OK;
82 FSoundEnabled := False;
84 {$IFNDEF NOSOUND}
85 try
86 res := FMOD_System_Create(F_System);
87 if res <> FMOD_OK then
88 raise Exception.Create('FMOD_System_Create failed!');
90 res := FMOD_System_GetVersion(F_System, ver);
91 if res <> FMOD_OK then
92 raise Exception.Create('FMOD_System_GetVersion failed!');
94 if ver < FMOD_VERSION then
95 raise Exception.Create('FMOD version is too old! Need '+IntToStr(FMOD_VERSION));
97 res := FMOD_System_SetOutput(F_System, FMOD_OUTPUTTYPE_WINMM);
98 if res <> FMOD_OK then
99 raise Exception.Create('FMOD_System_SetOutput failed!');
101 res := FMOD_System_SetSoftwareFormat(F_System, 48000,
102 FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
103 if res <> FMOD_OK then
104 raise Exception.Create('FMOD_System_SetSoftwareFormat failed!');
106 res := FMOD_System_Init(F_System, 64, FMOD_INIT_NORMAL, nil);
107 if res <> FMOD_OK then
108 raise Exception.Create('FMOD_System_Init failed!');
110 FSoundEnabled := True;
111 except
112 Application.MessageBox('Sound was disabled. Reason: ' + FMOD_ErrorString(res), 'FMOD Error', MB_OK or MB_ICONWARNING);
113 end;
114 {$ENDIF}
116 FSpectrum := TMiniSpectrum.Create(pSpectrum);
117 FSpectrum.Align := alClient;
118 FSpectrum.Enabled := True;
119 FSpectrum.Style := ssBlock;
120 end;
122 function TAddSoundForm.CreateSoundWAD(Resource: String): Boolean;
123 var
124 FileName, SectionName, ResourceName: String;
125 ResLength: Integer;
126 sz: LongWord;
127 soundExInfo: FMOD_CREATESOUNDEXINFO;
128 res: FMOD_RESULT;
130 begin
131 Result := False;
132 SoundData := nil;
133 Sound := nil;
134 Channel := nil;
136 if FSoundEnabled = False then
137 Exit;
139 {$IFNDEF NOSOUND}
140 g_ProcessResourceStr(Resource, FileName, SectionName, ResourceName);
141 g_ReadResource(FileName, SectionName, ResourceName, SoundData, ResLength);
143 if SoundData <> nil then
144 begin
145 sz := SizeOf(FMOD_CREATESOUNDEXINFO);
146 FillMemory(@soundExInfo, sz, 0);
147 soundExInfo.cbsize := sz;
148 soundExInfo.length := LongWord(ResLength);
150 res := FMOD_System_CreateStream(F_System, SoundData,
151 FMOD_LOOP_OFF or FMOD_2D or FMOD_OPENMEMORY,
152 @soundExInfo, Sound);
154 if res <> FMOD_OK then
155 begin
156 e_WriteLog(Format('Error creating sound %s', [Resource]), MSG_WARNING);
157 e_WriteLog(FMOD_ErrorString(res), MSG_WARNING);
158 Exit;
159 end;
160 end
161 else
162 begin
163 e_WriteLog(Format('Error loading sound %s', [Resource]), MSG_WARNING);
164 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
165 Exit;
166 end;
168 Result := True;
169 {$ENDIF}
170 end;
172 procedure TAddSoundForm.bbPlayClick(Sender: TObject);
173 var
174 res: FMOD_RESULT;
176 begin
177 Inherited;
179 if FResourceSelected then
180 begin
181 if Playing then
182 bbStop.Click();
184 if FSoundEnabled = False then
185 Exit;
187 if not CreateSoundWAD(FFullResourceName) then
188 Exit;
190 {$IFNDEF NOSOUND}
191 res := FMOD_System_PlaySound(F_System, FMOD_CHANNEL_FREE,
192 Sound, False, Channel);
193 if res <> FMOD_OK then
194 begin
195 Application.MessageBox(FMOD_ErrorString(res),
196 PChar(MsgMsgSoundError),
197 MB_OK or MB_ICONHAND);
198 Exit;
199 end;
201 Playing := True;
203 FMOD_Channel_SetVolume(Channel, 1.0);
205 FSpectrum.SetChannel(Channel);
206 {$ENDIF}
207 end;
208 end;
210 procedure TAddSoundForm.ShowSpectrum;
211 begin
212 if FSpectrum.Enabled then
213 FSpectrum.Draw();
214 end;
216 procedure TAddSoundForm.TimerTimer(Sender: TObject);
217 var
218 res: FMOD_RESULT;
219 b: LongBool;
221 begin
222 Inherited;
224 if FSoundEnabled = False then
225 Exit;
227 {$IFNDEF NOSOUND}
228 FMOD_System_Update(F_System);
230 ShowSpectrum();
232 res := FMOD_Channel_IsPlaying(Channel, b);
233 if (res <> FMOD_OK) or (not b) then
234 bbStop.Click();
235 {$ENDIF}
236 end;
238 procedure TAddSoundForm.FormDestroy(Sender: TObject);
239 var
240 res: FMOD_RESULT;
242 begin
243 Inherited;
245 FSpectrum.Free;
247 if FSoundEnabled = False then
248 Exit;
250 {$IFNDEF NOSOUND}
251 res := FMOD_System_Close(F_System);
252 if res <> FMOD_OK then
253 begin
254 e_WriteLog('Error closing FMOD system!', MSG_FATALERROR);
255 e_WriteLog(FMOD_ErrorString(res), MSG_FATALERROR);
256 Exit;
257 end;
259 res := FMOD_System_Release(F_System);
260 if res <> FMOD_OK then
261 begin
262 e_WriteLog('Error releasing FMOD system!', MSG_FATALERROR);
263 e_WriteLog(FMOD_ErrorString(res), MSG_FATALERROR);
264 end;
265 {$ENDIF}
266 end;
268 procedure Sound_StopRelease();
269 begin
270 Playing := False;
271 {$IFNDEF NOSOUND}
272 if Channel <> nil then
273 FMOD_Channel_Stop(Channel);
275 if Sound <> nil then
276 FMOD_Sound_Release(Sound);
277 {$ENDIF}
278 if SoundData <> nil then
279 FreeMem(SoundData);
281 SoundData := nil;
282 Sound := nil;
283 Channel := nil;
284 end;
286 procedure TAddSoundForm.FormClose(Sender: TObject;
287 var Action: TCloseAction);
288 begin
289 Inherited;
291 Timer.Enabled := False;
293 FSpectrum.SetChannel(nil);
294 Sound_StopRelease();
295 end;
297 procedure TAddSoundForm.bbStopClick(Sender: TObject);
298 begin
299 Inherited;
301 FSpectrum.SetChannel(nil);
302 Sound_StopRelease();
303 end;
305 procedure TAddSoundForm.FormActivate(Sender: TObject);
306 var
307 FileName, SectionName, ResourceName: String;
308 a: Integer;
310 begin
311 Inherited;
313 Timer.Enabled := True;
315 // Уже есть выбранный ресурс:
316 if FSetResource <> '' then
317 begin
318 g_ProcessResourceStr(FSetResource, FileName, SectionName, ResourceName);
320 if FileName = '' then
321 FileName := MsgWadSpecialMap;
323 if SectionName = '' then
324 SectionName := '..';
326 // WAD файл:
327 a := cbWADList.Items.IndexOf(FileName);
328 if a <> -1 then
329 begin
330 cbWADList.ItemIndex := a;
331 cbWADList.OnChange(nil);
332 end;
334 // Секция:
335 a := cbSectionsList.Items.IndexOf(SectionName);
336 if a <> -1 then
337 begin
338 cbSectionsList.ItemIndex := a;
339 cbSectionsList.OnChange(nil);
340 end;
342 // Ресурс:
343 a := lbResourcesList.Items.IndexOf(ResourceName);
344 if a <> -1 then
345 begin
346 lbResourcesList.ItemIndex := a;
347 lbResourcesList.OnClick(nil);
348 end;
349 end;
350 end;
352 procedure TAddSoundForm.bOKClick(Sender: TObject);
353 begin
354 inherited;
356 ModalResult := mrOk;
357 end;
359 procedure TAddSoundForm.bEmptyClick(Sender: TObject);
360 begin
361 FResourceName := '';
362 ModalResult := mrOk;
363 end;
365 end.