initial commit
[rofl0r-KOL.git] / KOLMediaPlayer.pas
blob2a24b02b45334d6f9d1b791ed2947f9fe6507cde
1 unit KOLMediaPlayer;
3 interface
5 uses
6 Windows, MMSystem, KOL;
8 {#If not[OBJECTS]}
9 {#Replace[= object(][= class(]}
10 {#Replace[@Self][Self]}
11 {#Replace[@ Self][Self]}
12 {#End not[OBJECTS]}
14 { -- MultiMedia player object -- }
16 type
17 {#If not[OBJECTS]}
18 {++}(*TMediaPlayer = class;*){--}
19 PMediaPlayer = {-}^{+}TMediaPlayer;
21 TMPState = ( mpNotReady, mpStopped, mpPlaying, mpRecording, mpSeeking,
22 mpPaused, mpOpen );
23 {* Available states of TMediaPlayer. }
24 TMPDeviceType = ( mmAutoSelect, mmVCR, mmVideodisc, mmOverlay, mmCDAudio, mmDAT,
25 mmScanner, mmAVIVideo, mmDigitalVideo, mmOther, mmWaveAudio,
26 mmSequencer );
27 {* Available device types of TMediaPlayer. }
28 TMPTimeFormat = ( tfMilliseconds, tfHMS, tfMSF, tfFrames, tfSMPTE24, tfSMPTE25,
29 tfSMPTE30, tfSMPTE30Drop, tfBytes, tfSamples, tfTMSF );
30 {* Available time formats, used with properties Length and Position. }
31 TMPNotifyValue = (nvSuccessful, nvSuperseded, nvAborted, nvFailure);
32 {* Available notification flags, which can be passed to TMediaPlayer.OnNotify
33 event handler (if it is set). }
34 TMPOnNotify = procedure( Sender: PMediaPlayer; NotifyValue: TMPNotifyValue ) of object;
35 {* Event type for TMediaPlayer.OnNotify event. }
38 TSoundChannel = ( chLeft, chRight );
39 {* Available sound channels. }
40 TSoundChannels = set of TSoundChannel;
41 {* Set of available sound channels. }
43 { ----------------------------------------------------------------------
45 TMediaPlayer object
47 ----------------------------------------------------------------------- }
48 TMediaPlayer = object( TObj )
49 {* MediaPlayer incapsulation object. Can open and play any supported
50 by system multimedia file. (To play wave only, it is possible to
51 use functions PlaySound..., which can also play it from memory and
52 from resource).
53 |<br>
54 Please note, that while debugging, You can get application exception
55 therefore standalone application is working fine. (Such results took
56 place for huge video). )
58 private
59 FWait: Boolean;
60 FDeviceID: Integer;
61 FError: Integer;
62 FTrack: Integer;
63 FDisplay: HWnd;
64 FFileName: String;
65 FOnNotify: TMPOnNotify;
66 FDeviceType: TMPDeviceType;
67 FHeight: Integer;
68 FWidth: Integer;
69 FTimeFormat: TMPTimeFormat;
70 FBaseKeyCDAudio: HKey;
71 FoldKeyValCDData: DWORD;
72 FoldKeyValCDAudio: String;
73 FAutoRestore: procedure of object;
74 FAudioOff: array[ TSoundChannel ] of Boolean;
75 FVideoOff: Boolean;
76 FAlias: String;
77 function GetErrorMessage: String;
78 function GetState: TMPState;
79 procedure SetPause(const Value: Boolean);
80 procedure SetTrack(Value: Integer);
81 function GetCapability( const Index: Integer ): Boolean;
82 function GetICapability( const Index: Integer ): Integer;
83 procedure SetDisplay(const Value: HWND);
84 function GetDisplayRect: TRect;
85 function GetDeviceType: TMPDeviceType;
86 procedure SetFileName(const Value: String);
87 function GetBState( const Index: Integer ): Boolean;
88 function GetIState( const Index: Integer ): Integer;
89 function GetPosition: Integer;
90 procedure SetPosition(Value: Integer);
91 function GetTimeFormat: TMPTimeFormat;
92 procedure SetTimeFormat(const Value: TMPTimeFormat);
93 procedure SetDisplayRect(const Value: TRect);
94 function GetPause: Boolean;
95 function GetAudioOn(Chn: TSoundChannels): Boolean;
96 procedure SetAudioOn(Chn: TSoundChannels; const Value: Boolean);
97 function GetVideoOn: Boolean;
98 procedure SetVideoOn(const Value: Boolean);
99 function DGVGetSpeed: Integer;
100 procedure DGVSetSpeed(const Value: Integer);
101 protected
102 {++}(*public*){--}
103 destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
104 {* Please remember, that if CDAudio (e.g.) is playing, it is not stop
105 playing when TMediaPlayer object destroying unless performing command
106 ! Pause := True; }
107 {#End not[OBJECTS]}
108 public
109 property FileName: String read FFileName write SetFileName;
110 {* Name of file, containing multimedia, if any (some multimedia devices
111 do not require file, corresponding to device rather then file. Such as
112 mmCDAudio, mmScanner, etc. Use in that case DeviceType property to
113 assign to desired type of multimedia and then open it using Open method).
114 When new string is assigned to a FileName, previous media is closed
115 and another one is opened automatically. }
116 property DeviceType: TMPDeviceType read GetDeviceType write FDeviceType;
117 {* Type of multimedia. For opened media, real type is returned. If no
118 multimedia (device or file) opened, it is possible to set DeviceType to
119 desired type before opening multimedia. Use such way for opening
120 devices rather then for opening multimedia, stored in files. }
121 property DeviceID: Integer read FDeviceID;
122 {* Returns DeviceID, corresponded to opened multimedia (0 is returned
123 if no media opened. }
124 property TimeFormat: TMPTimeFormat read GetTimeFormat write SetTimeFormat;
125 {* Time format, used to set/retrieve information about Length or Position.
126 Please note, that not all formats are supported by all multimedia devices.
127 Only tfMilliseconds (is set by default) supported by all devices. Following
128 table shows what devices are supporting certain time formats:
129 |<table>
130 |&L=<tr><td>%0</td><td>
131 |&E=</td></tr>
132 <L tfMilliseconds> All multimedia device types. <E>
133 <L tfBytes> mmWaveAudio <E>
134 <L tfFrames> mmDigitalVideo <E>
135 <L tfHMS (hours, minutes, seconds)> mmVCR (video cassete recorder), mmVideodisc.
136 It is necessary to parse retrieved Length or Position or to prepare
137 value before assigning it to Position using typecast to THMS. <E>
138 <L tfMSF (minutes, seconds, frames)> mmCDAudio, mmVCR. It is necessary to
139 parse value retrieved from Length or Position properties or value to
140 assign to property Position using typecast to TMSF type. <E>
141 <L tfSamples> mmWaveAudio <E>
142 <L tfSMPTE24, tfSMPTE25, tfSMPTE30, tfSMPTE30DROP (Society of Motion Picture
143 and Television Engineers)> mmVCR, mmSequencer. <E>
144 <L tfTMSF (tracks, minutes, seconds, frames)> mmVCR <E>
145 |</table> }
146 property Position: Integer //index MCI_STATUS_POSITION read GetIState
147 read GetPosition write SetPosition;
148 {* Current position in milliseconds. Even if device contains several tracks,
149 this is the position from starting of first track. To determine position
150 in current Track, subtract TrackStartPosition. }
151 property Track: Integer read FTrack write SetTrack;
152 {* Current track (from 1 to TrackCount). Has no sence, if tracks are not
153 supported by opened multimedia device, or no tracks present. }
154 property TrackCount: Integer index MCI_STATUS_NUMBER_OF_TRACKS read GetIState;
155 {* Count of tracks for opened multimedia device. If device does not support
156 tracks, or tracks not present (e.g. there are no tracks found on CD),
157 value 1 is returned by system (but this not a rule to determine if
158 tracks are available). }
159 property Length: Integer index MCI_STATUS_LENGTH read GetIState;
160 {* Length of multimedia in milliseconds. Even if device has tracks,
161 this the length of entire multimedia. }
162 property Display: HWnd read FDisplay write SetDisplay;
163 {* Window to represent animation. It is recommended to create neutral
164 control (e.g. label, or paint box, and assign its TControl.Handle to
165 this property). Has no sense for multimedia, which HasVideo = False
166 (no animation presented). }
167 property DisplayRect: TRect read GetDisplayRect write SetDisplayRect;
168 {* Rectangle in Display window, where animation is shown while playing
169 animation. To restore default value, pass Bottom = Top = 0 and Right =
170 Left = 0. }
171 property Error: Integer read FError;
172 {* Error code. Is set after every operation. If 0, no errors detected. It
173 is also possible to retrieve description string for error using
174 property ErrorMessage. }
175 property ErrorMessage: String read GetErrorMessage;
176 {* Brief description of Error. }
177 property State: TMPState read GetState;
178 {* Current state of multimedia. }
179 property Pause: Boolean read GetPause write SetPause;
180 {* True, if multimedia currently not playing (or not open). Set this property
181 to True to pause playing, and to False to resume. }
182 property Wait: Boolean read FWait write FWait;
183 {* True, if operations will be performed synchronously (i.e. execution will
184 be continued only after completing operation). If Wait is False (default),
185 control is returned immediately to application, without waiting of completing
186 of operation. It is possible in that case to get notification about finishing
187 of previous operation in OnNotify event handler (if any has been set). }
189 property TrackStartPosition: Integer index $80000000 or MCI_STATUS_POSITION
190 read GetIState;
191 {* Returns given track starting position (in units, specisied by TimeFormat
192 property. E.g., if TimeFormat is set to (default) tfMilliseconds, in
193 milliseconds). }
194 property TrackLength: Integer index $80000000 or MCI_STATUS_LENGTH read GetIState;
195 {* Returns given track length (in units, specified by TimeFormat property). }
196 property OnNotify: TMPOnNotify read FOnNotify write FOnNotify;
197 {* Called when asynchronous operation completed. (By default property Wait is
198 set to False, so all operations are performed asynchronously, i.e. control
199 is returned to application ithout of waiting of completion operation).
200 Please note, that syatem can make several notifications while performing
201 operation. To determine if operation completed, check State property.
202 E.g., to find where playing is finished, check in OnNotify event handler
203 if State <> mpPlaying.
204 |<br>Though TMediaPlayer works fine with the most of multimedia formats
205 (at least it is tested for WAV, MID, RMI, AVI (video and sound), MP3 (soound),
206 MPG (video and sound) ),
207 there are some problems with getting notifications about finishing MP3
208 playing: when OnNotify is called, State returned is mpPlaying yet. For
209 that case I can advice to check also playing time and compare it with
210 Length of multimedia. }
211 property Width: Integer read FWidth;
212 {* Default width of video display (for multimedia, having video animation). }
213 property Height: Integer read FHeight;
214 {* Default height of video display (for multimedia, having video animation). }
216 function Open: Boolean;
217 {* Call this method to open device, which is not correspondent to file. For
218 multimedia, stored in file, Open is called automatically when FileName
219 property is changed.
220 |<br>
221 Multimedia is always trying to be open shareable first. If it is not
222 possible, second attempt is made to open multimedia without sharing. }
223 property Alias: String read FAlias write FAlias;
224 {* Alias for opened device. Must be set before opening (before changing
225 FileName). }
226 function Play( StartPos, PlayLength: Integer ): Boolean;
227 {* Call this method to play multimedia. StartPos is relative to
228 starting position of opened multimedia, even if it has tracks. If value
229 passed for StartPos is -1, current position is used to start from.
230 If -1 passed as PlayLength, multimedia is playing to the end of media.
231 Note, that after some operation (including Play) current position is
232 moved and it is necessary to pass 0 as StartPos to play multimedia
233 from its starting position again. To provide playing the same
234 multimedia several times, call:
235 ! with MyMediaPlayer do
236 ! Play( 0, -1 );
237 To Play single track, call:
238 ! with MyMediaPlayer do
239 ! begin
240 ! Track := N; // set track to desired number
241 ! Play( TrackStartPosition, TrackLength );
242 ! end; }
243 procedure Close;
244 {* Closes multimedia. Later it can be reopened using Open method. Please
245 remember, that if CDAudio (e.g.) is playing, it is not stop playing
246 when Close is called. To stop playing, first perform command
247 ! Pause := True; }
248 procedure Eject;
249 {* Ejects media from device. It is possible to check first, if this operation
250 is supported by the device - see CanEject. }
251 procedure DoorClose;
252 {* Backward operation to Eject - inserts media to device. This operation is
253 very easy and does not take in consideration if CD data / audio is playing
254 automatically when media is inserted. To prevent launching CD player or
255 application, defined in autostart.inf file in rootof CD, use Insert method
256 instead. }
257 procedure DisableAutoPlay;
258 {* Be careful when using this method - this affects user settings such as 'Autoplay
259 CD audio disk' and 'Autorun CD Data disk'. At least do not forget to restore
260 settings later, using RestoreAutoPlay method. When You use Insert method
261 to insert CD into device, DisableAutoPlay also is called, but in that case
262 restoring is made automatically at least when TMediaPlayer object is
263 destroying. }
264 procedure RestoreAutoPlay;
265 {* Restores settings CD autoplay settings, changed by calling DisableAutoPlay
266 method (which must be called earlier to save settings and change it to
267 disable CD autoplay feature). It is not necessary to call RestoreAutoPlay
268 only in case, when method Insert was used to insert CD into device (but
269 calling it restores settings therefore - so it is possible to restore
270 settings not only when object TMediaPlayer destroyed, but earlier. }
271 procedure Insert;
272 {* Does the same as DoorClose, but first disables auto play settings, preventing
273 system from running application defined in Autorun.inf (in CD root) or
274 launching CD player application. Such settings will be restored at least
275 when TMediaPlayer object is destroyed, but it is possible to call
276 RestoreAutoPlay earlier (but there is no sence to call it immediately
277 after performing Insert method - at least wait several seconds or start
278 playing track first). }
279 function Save( const aFileName: String ): Boolean;
280 {* Saves multimedia to a file. Check first, if this operation is supported
281 by device. }
282 property Ready: Boolean index MCI_STATUS_READY read GetBState;
283 {* True if Device is ready. }
284 function StartRecording( FromPos, ToPos: Integer ): Boolean;
285 {* Starts recording. If FromPos is passed -1, recording is starting from
286 current position. If ToPos is passed -1, recording is continuing up
287 to the end of media. }
288 function Stop: Boolean;
289 {* Stops playing back or recording. }
291 property IsCompoundDevice: Boolean index MCI_GETDEVCAPS_COMPOUND_DEVICE read GetCapability;
292 {* True, if device is compound. }
293 property HasVideo: Boolean index MCI_GETDEVCAPS_HAS_VIDEO read GetCapability;
294 {* True, if multimedia has videoanimation. }
295 property HasAudio: Boolean index MCI_GETDEVCAPS_HAS_AUDIO read GetCapability;
296 {* True, if multimedia contains audio. }
297 property CanEject: Boolean index MCI_GETDEVCAPS_CAN_EJECT read GetCapability;
298 {* True, if device supports "open door" and "close door" operations. }
299 property CanPlay: Boolean index MCI_GETDEVCAPS_CAN_PLAY read GetCapability;
300 {* True, if multimedia can be played (some of deviceces are only for recording,
301 not for playing). }
302 property CanRecord: Boolean index MCI_GETDEVCAPS_CAN_RECORD read GetCapability;
303 {* True, if multimedia can be used to record (video or/and audio). }
304 property CanSave: Boolean index MCI_GETDEVCAPS_CAN_SAVE read GetCapability;
305 {* True, if multimedia device supports saving to a file. }
306 property Present: Boolean index MCI_STATUS_MEDIA_PRESENT read GetBState;
307 {* True, if CD or videodisc inserted into device. }
309 property AudioOn[ Chn: TSoundChannels ]: Boolean read GetAudioOn write SetAudioOn;
310 {* Returns True, if given audio channels (both if [chLeft,chRight], any if [])
311 are "on". This property also allows to turn desired channels on and off. }
312 property VideoOn: Boolean read GetVideoOn write SetVideoOn;
313 {* Returns True, if video is "on". Allows to turn video signal on and off. }
315 //-- for "CDAudio" only:
316 property CDTrackNotAudio: Boolean index $80000000 or MCI_CDA_STATUS_TYPE_TRACK read GetBState;
317 {* True, if current Track is not audio. }
319 //-- for "digitalvideo":
320 property DGV_CanFreeze: Boolean index $4002 {MCI_DGV_GETDEVCAPS_CAN_FREEZE} read GetCapability;
321 {* True, if can freeze. }
322 property DGV_CanLock: Boolean index $4000 {MCI_DGV_GETDEVCAPS_CAN_LOCK} read GetCapability;
323 {* True, if can lock. }
324 property DGV_CanReverse: Boolean index $4004 {MCI_DGV_GETDEVCAPS_CAN_REVERSE} read GetCapability;
325 {* True, if can reverse playing. }
326 property DGV_CanStretchInput: Boolean index $4008 {MCI_DGV_GETDEVCAPS_CAN_STR_IN} read GetCapability;
327 {* True, if can stretch input. }
328 property DGV_CanStretch: Boolean index $4001 {MCI_DGV_GETDEVCAPS_CAN_STRETCH} read GetCapability;
329 {* True, if can stretch output. }
330 property DGV_CanTest: Boolean index $4009 {MCI_DGV_GETDEVCAPS_CAN_TEST} read GetCapability;
331 {* True, if supports Test. }
332 property DGV_HasStill: Boolean index $4005 {MCI_DGV_GETDEVCAPS_HAS_STILL} read GetCapability;
333 {* True, if has still images in video. }
334 property DGV_MaxWindows: Integer index $4003 {MCI_DGV_GETDEVCAPS_MAX_WINDOWS} read GetICapability;
335 {* Returns maximum windows supported. }
336 property DGV_MaxRate: Integer index $400A {MCI_DGV_GETDEVCAPS_MAXIMUM_RATE} read GetICapability;
337 {* Returns maximum possible rate (frames/sec). }
338 property DGV_MinRate: Integer index $400B {MCI_DGV_GETDEVCAPS_MINIMUM_RATE} read GetICapability;
339 {* Returns minimum possible rate (frames/sec). }
341 property DGV_Speed: Integer read DGVGetSpeed write DGVSetSpeed;
342 {* Returns speed of digital video as a ratio between the nominal frame
343 rate and the desired frame rate where the nominal frame rate is designated
344 as 1000. Half speed is 500 and double speed is 2000. The allowable speed
345 range is dependent on the device and possibly the file, too. }
347 //-- for AVI only (mmDigitalVideo, AVI-format):
348 property AVI_AudioBreaks: Integer index $8003 {MCI_AVI_STATUS_AUDIO_BREAKS} read GetIState;
349 {* Returns the number of times that the audio definitely broke up.
350 (We count one for every time we're about to write some audio data
351 to the driver, and we notice that it's already played all of the
352 data we have). }
353 property AVI_FramesSkipped: Integer index $8001 {MCI_AVI_STATUS_FRAMES_SKIPPED} read GetIState;
354 {* Returns number of frames not drawn during last play. If this number
355 is more than a small fraction of the number of frames that should have
356 been displayed, things aren't looking good. }
357 property AVI_LastPlaySpeed: Integer index $8002 {MCI_AVI_STATUS_LAST_PLAY_SPEED} read GetIState;
358 {* Returns a number representing how well the last AVI play worked.
359 A result of 1000 indicates that the AVI sequence took the amount
360 of time to play that it should have; a result of 2000, for instance,
361 would indicate that a 5-second AVI sequence took 10 seconds to play,
362 implying that the audio and video were badly broken up. }
365 //-- for "vcr" (video cassete recorder):
366 property VCR_ClockIncrementRate: Integer index $401C {MCI_VCR_GETDEVCAPS_CLOCK_INCREMENT_RATE} read GetICapability;
367 {* }
368 property VCR_CanDetectLength: Boolean index $4001 {MCI_VCR_GETDEVCAPS_CAN_DETECT_LENGTH} read GetCapability;
369 {* True, if can detect Length. }
370 property VCR_CanFreeze: Boolean index $401B {MCI_VCR_GETDEVCAPS_CAN_FREEZE} read GetCapability;
371 {* True, if supports command "freeze". }
372 property VCR_CanMonitorSources: Boolean index $4009 {MCI_VCR_GETDEVCAPS_CAN_MONITOR_SOURCES} read GetCapability;
373 {* True, if can monitor sources. }
374 property VCR_CanPreRoll: Boolean index $4007 {MCI_VCR_GETDEVCAPS_CAN_PREROLL} read GetCapability;
375 {* True, if can preroll. }
376 property VCR_CanPreview: Boolean index $4008 {MCI_VCR_GETDEVCAPS_CAN_PREVIEW} read GetCapability;
377 {* True, if can preview. }
378 property VCR_CanReverse: Boolean index $4004 {MCI_VCR_GETDEVCAPS_CAN_REVERSE} read GetCapability;
379 {* True, if can play in reverse direction. }
380 property VCR_CanTest: Boolean index $4006 {MCI_VCR_GETDEVCAPS_CAN_TEST} read GetCapability;
381 {* True, if can test. }
382 property VCR_HasClock: Boolean index $4003 {MCI_VCR_GETDEVCAPS_HAS_CLOCK} read GetCapability;
383 {* True, if has clock. }
384 property VCR_HasTimeCode: Boolean index $400A {MCI_VCR_GETDEVCAPS_HAS_TIMECODE} read GetCapability;
385 {* True, if has time code. }
386 property VCR_NumberOfMarks: Integer index $4005 {MCI_VCR_GETDEVCAPS_NUMBER_OF_MARKS} read GetICapability;
387 {* Returns number of marks. }
388 property VCR_SeekAccuracy: Integer index $4002 {MCI_VCR_GETDEVCAPS_SEEK_ACCURACY} read GetICapability;
389 {* Returns seek accuracy. }
391 //-- for mmWaveAudio:
392 property Wave_AvgBytesPerSecond: Integer index $4004 {MCI_WAVE_STATUS_AVGBYTESPERSEC} read GetIState;
393 {* Returns current bytes per second used for playing, recording, and saving. }
394 property Wave_BitsPerSample: Integer index $4006 {MCI_WAVE_STATUS_BITSPERSAMPLE} read GetIState;
395 {* Returns current bits per sample used for playing, recording, and saving PCM formatted data. }
396 property Wave_SamplesPerSecond: Integer index $4003 {MCI_WAVE_STATUS_SAMPLESPERSEC} read GetIState;
397 {* Returns current samples per second used for playing, recording, and saving. }
399 function SendCommand( Cmd, Flags: Integer; Buffer: Pointer ): Integer;
400 {* Low level access to a device. To get knoq how to use it, see sources. }
402 {$IFNDEF _FPC}
403 function asmSendCommand( Flags, Cmd: Integer {;var Buffer in stack} ): Integer;
404 {* Assembler version of SendCommand - only for advanced programmers. It
405 can be called from assembler only, and last parameter (but without
406 first member of the structure, dwCallback) must be placed
407 to stack just before calling asmSendCommand. Also, @Self must be
408 placed already in EBX, second parameter (Cmd) in EDX, and third (Flags)
409 in EAX. This method also retirns error code (0, if success), and
410 additionally ZF flag set if success. }
411 {$ENDIF}
413 {$IFDEF USE_CONSTRUCTORS}
414 constructor CreateMediaPlayer( const AFileName: String; AWindow: HWND );
415 {$ENDIF USE_CONSTRUCTORS}
416 end;
419 var MediaPlayers: PList;
421 function NewMediaPlayer( const FileName: String; Window: HWND ): PMediaPlayer;
422 {* Creates TMediaPlayer instance. If FileName is not empty string, file is opening
423 immediately. }
425 type
426 TPlayOption = ( poLoop, poWait, poNoStopAnotherSound, poNotImportant );
427 {* Options to play sound. poLoop, when sound is playing back repeatedly until
428 PlaySoundStop called. poWait, if sound is playing synchronously (i.e. control
429 returns to application after the sound event completed). poNoStopAnotherSound
430 means that another sound playing can not be stopped to free resources needed to
431 play requested sound. poNotImportant means that if driver busy, function
432 will return immediately returning False (with no sound playing). }
433 TPlayOptions = set of TPlayOption;
434 {* Options, available to play sound from memory or resource or to play standard
435 sound event using PlaySoundMemory, PlaySoundResourceID, PlaySoundResourceName,
436 PlaySoundEvent. }
438 function PlaySoundMemory( Memory: Pointer; Options: TPlayOptions ): Boolean;
439 {* Call it to play sound already stored in memory. (It is possible to preload
440 sound from resource (e.g., using Resurce2Stream function) or to load sound from
441 file. }
442 function PlaySoundResourceID( Inst, ResID: Integer; Options: TPlayOptions ): Boolean;
443 {* Call it to play sound, stored in resource. It is also possible to stop playing
444 certain sound, asynchronously playing from a resource, using PlaySoundStopResID.
445 |<br>&nbsp;&nbsp;&nbsp;
446 In this implementation, sound is played from memory and always with poWait
447 option turned on (i.e. synchronously). }
448 function PlaySoundResourceName( Inst: Integer; const ResName: String; Options: TPlayOptions ): Boolean;
449 {* Call it to play sound, stored in (named) resource. It is also possible to stop
450 playing certain sound, asynchronously playing from a resource, using
451 PlaySoundStopResName.
452 |<br>&nbsp;&nbsp;&nbsp;
453 In this implementation, sound is played from memory and always with poWait
454 option turned on (i.e. synchronously). }
455 function PlaySoundEvent( const EventName: String; Options: TPlayOptions ): Boolean;
456 {* Call it to play standard event sound. E.g., 'SystemAsterisk', 'SystemExclamation',
457 'SystemExit', 'SystemHand', 'SystemQuestion', 'SystemStart' sounds are defined
458 for all Win32 implementations. }
459 function PlaySoundFile( const FileName: String; Options: TPlayOptions ): Boolean;
460 {* Call it to play waveform audio file. (This also can be done using
461 TMediaPlayer, but for wide set of audio and video formats). }
462 function PlaySoundStop: Boolean;
463 {* Call it to stop playing sounds, which are yet playing (after calling
464 PlaySountXXXXX functions above to play sounds asynchronously). }
466 function WaveOutChannels( DevID: Integer ): TSoundChannels;
467 {* Returns available sound output channels for given wave out device. Pass
468 -1 (or WAVE_MAPPER) to get channels for wave mapper. If only mono
469 output available, [ chLeft ] is returned. }
470 function WaveOutVolume( DevID: Integer; Chn: TSoundChannel; NewValue: Integer ): Word;
471 {* Sets volume for given channel. If NewValue = -1 passed, new value is not set.
472 Always returns current volume level for a channel (if successful). Volume varies
473 in diapason 0..65535. If passed value > 65535, low word of NewValue is used
474 to set both chLeft and chRight channels. }
477 implementation
479 type
480 {++}(*TControl1 = class;*){--}
481 PControl1 = {-}^{+}TControl1;
482 TControl1 = object( TControl )
483 end;
484 {$G+}
485 ////////////////////////////////////////////////////////////////////////
488 // M P L A Y E R
491 ////////////////////////////////////////////////////////////////////////
493 { -- TMediaPlayer -- }
495 {$IFDEF USE_CONSTRUCTORS}
496 function NewMediaPlayer( const FileName: String; Window: HWND ): PMediaPlayer;
497 begin
498 new( Result, CreateMediaPlayer( FileName, Window ) );
499 end;
500 {$ELSE not_USE_CONSTRUCTORS}
501 {$IFDEF ASM_VERSION}
502 function _NewMediaPlayer: PMediaPlayer;
503 begin
504 New( Result, Create );
505 end;
506 function NewMediaPlayer( const FileName: String; Window: HWND ): PMediaPlayer;
508 PUSH EBX
509 PUSH EDX
510 PUSH EAX
511 CALL _NewMediaPlayer
512 XCHG EBX, EAX
513 MOV ECX, [MediaPlayers]
514 INC ECX
515 LOOP @@ListCreated
516 CALL NewList
517 MOV [MediaPlayers], EAX
518 XCHG ECX, EAX
519 @@ListCreated:
520 XCHG EAX, ECX
521 MOV EDX, EBX
522 CALL TList.Add
523 POP EDX
524 MOV EAX, EBX
525 CALL TMediaPlayer.SetFileName
526 POP ECX
527 MOV EDX, [EBX].TMediaPlayer.FError
528 TEST EDX, EDX
529 JNZ @@exit
531 PUSH ECX
532 MOV EAX, EBX
533 MOV DL, MCI_GETDEVCAPS_HAS_VIDEO //$3
534 CALL TMediaPlayer.GetCapability
535 TEST AL, AL
536 JZ @@noVideo
538 POP EDX
539 PUSH EDX
540 MOV EAX, EBX
541 CALL TMediaPlayer.SetDisplay
542 @@noVideo:
543 POP [EBX].TMediaPlayer.FDisplay
545 @@exit:
546 XCHG EAX, EBX
547 POP EBX
548 end;
549 {$ELSE ASM_VERSION} //Pascal
550 function NewMediaPlayer( const FileName: String; Window: HWND ): PMediaPlayer;
551 begin
552 {#If not[OBJECTS]}
554 New( Result, Create );
555 {+}{++}(*Result := PMediaPlayer.Create;*){--}
556 {#End not[OBJECTS]}
557 if MediaPlayers = nil then
558 MediaPlayers := NewList;
559 MediaPlayers.Add( Result );
560 //Result.FTimeFormat := tfMilliseconds; //by default...
561 Result.FileName := FileName;
562 if Result.FError <> 0 then
563 //MsgOK( 'Error #' + Int2Str( Result.Error ) + ' when opening multimedia:'#13 +
564 // Result.ErrorMessage )
565 else
566 begin
567 if Result.HasVideo then
568 Result.Display := Window;
569 Result.FDisplay := Window;
570 end;
571 end;
572 {$ENDIF ASM_VERSION}
573 {$ENDIF USE_CONSTRUCTORS}
575 {$IFDEF ASM_VERSION}
576 procedure MMNotifyProc( var Msg: TMsg );
578 PUSH EBX
579 XCHG EBX, EAX
580 PUSH ESI
581 PUSH EDI
582 MOV EDX, [MediaPlayers]
583 TEST EDX, EDX
584 JZ @@fin
585 MOV ECX, [EDX].TList.FCount
586 MOV ESI, [EDX].TList.FItems
587 MOV EDI, [EBX].TMsg.lParam
588 @@loo:
589 LODSD
590 CMP [EAX].TMediaPlayer.FDeviceID, EDI
591 JNZ @@nxt
593 MOV ECX, [EAX].TMediaPlayer.fOnNotify.TMethod.Code
594 JECXZ @@fin
595 MOV EDI, ECX
596 XCHG EDX, EAX
597 MOV EAX, [EDX].TMediaPlayer.fOnNotify.TMethod.Data
598 MOV ECX, [EBX].TMsg.wParam
599 DEC ECX
600 CALL EDI
601 JMP @@fin
603 @@nxt:
604 LOOP @@loo
605 @@fin:
606 POP EDI
607 POP ESI
608 POP EBX
609 end;
610 {$ELSE ASM_VERSION} //Pascal
611 procedure MMNotifyProc( var Msg: TMsg );
612 var I: Integer;
613 MP: PMediaPlayer;
614 begin
615 if MediaPlayers <> nil then
616 for I := 0 to MediaPlayers.Count - 1 do
617 begin
618 MP := MediaPlayers.Items[ I ];
619 if MP.FDeviceID = Msg.lParam then
620 begin
621 if Assigned( MP.fOnNotify ) then
622 MP.FOnNotify( MP, TMPNotifyValue( Msg.wParam - 1 ) );
623 break;
624 end;
625 end;
626 end;
627 {$ENDIF ASM_VERSION}
629 { TMediaPlayer }
631 {$IFDEF ASM_VERSION}
632 procedure TMediaPlayer.Close;
634 MOV ECX, [EAX].FDeviceID
635 JECXZ @@exit
636 PUSH EBX
637 XCHG EBX, EAX
638 //PUSH EAX
639 XOR EAX, EAX
640 INC EAX // EAX = MCI_NOTIFY
642 MOV DX, MCI_CLOSE
643 CALL asmSendCommand
644 //TEST EAX, EAX
645 JNZ @@1
646 MOV [EBX].FDeviceID, EAX
647 @@1:
648 //POP ECX
649 POP EBX
650 @@exit:
651 end;
652 {$ELSE ASM_VERSION} //Pascal
653 procedure TMediaPlayer.Close;
654 var GenParm: TMCI_Generic_Parms;
655 begin
656 if FDeviceID = 0 then Exit;
657 GenParm.dwCallback := 0;
658 //if SendCommand( MCI_CLOSE, MCI_NOTIFY, @GenParm ) = 0 then
659 if SendCommand( MCI_CLOSE, MCI_WAIT, @GenParm ) = 0 then
660 FDeviceID := 0;
661 end;
662 {$ENDIF ASM_VERSION}
664 {$IFDEF ASM_noVERSION}
665 destructor TMediaPlayer.Destroy;
667 PUSH EBX
668 MOV EBX, EAX
669 MOV [EBX].FWait, 1
670 XOR EDX, EDX
671 MOV [EBX].FOnNotify.TMethod.Code, EDX
672 CALL Close
673 MOV EAX, [MediaPlayers]
674 PUSH EAX
675 MOV EDX, EBX
676 CALL TList.IndexOf
677 XCHG EDX, EAX
678 POP EAX
679 PUSH EAX
680 PUSH [EAX].TList.fCount
681 CALL TList.Delete
682 POP ECX
683 POP EAX
684 LOOP @@1
685 MOV [MediaPlayers], ECX
686 CALL TObj.Free
687 @@1:
688 MOV ECX, [EBX].FAutoRestore.TMethod.Code
689 JECXZ @@2
690 MOV EAX, EBX
691 CALL ECX
692 @@2:
693 LEA EAX, [EBX].FFileName
694 CALL System.@LStrClr
695 LEA EAX, [EBX].FoldKeyValCDAudio
696 CALL System.@LStrClr
697 XCHG EAX, EBX
698 CALL TObj.Destroy
699 POP EBX
700 end;
701 {$ELSE ASM_VERSION} //Pascal
702 destructor TMediaPlayer.Destroy;
703 var I: Integer;
704 begin
705 FWait := True;
706 FOnNotify := nil;
707 I := MediaPlayers.IndexOf( @Self );
708 if I >= 0 then
709 begin
710 Close;
711 MediaPlayers.Delete( I );
712 end;
713 if MediaPlayers.Count = 0 then
714 begin
715 MediaPlayers.Free;
716 MediaPlayers := nil;
717 end;
718 if Assigned( FAutoRestore ) then
719 FAutoRestore;
720 FFileName := '';
721 FoldKeyValCDAudio := '';
722 inherited;
723 end;
724 {$ENDIF ASM_VERSION}
726 {$IFDEF ASM_VERSION}
727 procedure TMediaPlayer.DoorClose;
729 PUSH EBX
730 XCHG EBX, EAX
731 PUSH ECX // dwAudio
732 PUSH ECX // dwTimeFormat
733 //PUSH ECX // dwCallback
734 XOR EAX, EAX
735 MOV AX, MCI_SET_DOOR_CLOSED or MCI_NOTIFY // $201
737 MOV DX, MCI_SET // $80D
738 CALL asmSendCommand
739 //POP ECX
740 POP ECX
741 POP ECX
742 POP EBX
743 end;
744 {$ELSE ASM_VERSION} //Pascal
745 procedure TMediaPlayer.DoorClose;
746 var SetParm: TMCI_Set_Parms;
747 begin
748 Assert( (FDeviceID = 0) or CanEject, 'Device not support door close operation' );
749 SendCommand( MCI_SET, MCI_SET_DOOR_CLOSED or MCI_NOTIFY, @SetParm );
750 end;
751 {$ENDIF ASM_VERSION}
753 {$IFDEF ASM_VERSION}
754 procedure TMediaPlayer.Eject;
756 PUSH EBX
757 XCHG EBX, EAX
758 PUSH ECX // dwAudio
759 PUSH ECX // dwTimeFormat
760 //PUSH ECX // dwCallback
761 XOR EAX, EAX
762 MOV AX, MCI_SET_DOOR_OPEN or MCI_NOTIFY // $101
764 MOV DX, MCI_SET // $80D
765 CALL asmSendCommand
766 //POP ECX
767 POP ECX
768 POP ECX
769 POP EBX
770 end;
771 {$ELSE ASM_VERSION} //Pascal
772 procedure TMediaPlayer.Eject;
773 var SetParm: TMCI_Set_Parms;
774 begin
775 Assert( (FDeviceID = 0) or CanEject, 'Device not support eject' );
776 SendCommand( MCI_SET, MCI_SET_DOOR_OPEN or MCI_NOTIFY, @SetParm );
777 end;
778 {$ENDIF ASM_VERSION}
780 {$IFDEF ASM_VERSION}
781 function TMediaPlayer.GetCapability( const Index: Integer ): Boolean;
783 CALL GetICapability
784 {$IFDEF PARANOIA}
785 DB $24, $01
786 {$ELSE}
787 AND AL, 1
788 {$ENDIF}
789 end;
790 {$ELSE ASM_VERSION} //Pascal
791 function TMediaPlayer.GetCapability( const Index: Integer ): Boolean;
792 begin
793 Result := Boolean( GetICapability( Index ) );
794 end;
795 {$ENDIF ASM_VERSION}
797 {$IFDEF ASM_VERSION}
798 function TMediaPlayer.GetICapability(const Index: Integer): Integer;
800 PUSH EBX
801 XCHG EBX, EAX
802 MOV EAX, [EBX].FDeviceID
803 TEST EAX, EAX
804 JZ @@exit
806 PUSH EDX // dwItem := Index
807 PUSH ECX // dwReturn
808 //PUSH ECX // dwCallback
809 XOR EAX, EAX
810 MOV AX, MCI_WAIT or MCI_GETDEVCAPS_ITEM // $102
812 MOV DX, MCI_GETDEVCAPS // $80B
813 CALL asmSendCommand
814 //POP ECX // dwCallback
815 POP EDX // dwReturn
816 POP ECX // dwItem
817 //TEST EAX, EAX
818 JZ @@retEDX
819 XOR EDX, EDX
820 @@retEDX:
821 XCHG EAX, EDX // Result := dwRetirn
822 @@exit:
823 POP EBX
824 end;
825 {$ELSE ASM_VERSION} //Pascal
826 function TMediaPlayer.GetICapability(const Index: Integer): Integer;
827 var DevCapParm: TMCI_GetDevCaps_Parms;
828 begin
829 Result := 0;
830 if FDeviceID <> 0 then
831 begin
832 DevCapParm.dwItem := Index;
833 if SendCommand( MCI_GETDEVCAPS, MCI_WAIT or MCI_GETDEVCAPS_ITEM, @DevCapParm ) = 0 then
834 Result := DevCapParm.dwReturn;
835 end;
836 end;
837 {$ENDIF ASM_VERSION}
839 {$IFDEF ASM_VERSION}
840 function TMediaPlayer.GetDeviceType: TMPDeviceType;
842 XOR EDX, EDX
843 MOV DL, MCI_GETDEVCAPS_DEVICE_TYPE // $4
844 CALL GetICapability
845 end;
846 {$ELSE ASM_VERSION} //Pascal
847 function TMediaPlayer.GetDeviceType: TMPDeviceType;
848 begin
849 Result := TMPDeviceType( GetICapability( MCI_GETDEVCAPS_DEVICE_TYPE ) { - 512 } );
850 end;
851 {$ENDIF ASM_VERSION}
853 {$IFDEF ASM_VERSION}
854 function TMediaPlayer.GetDisplayRect: TRect;
856 PUSH EBX
857 XCHG EBX, EAX
858 PUSH EDI
859 MOV EDI, EDX
860 MOV EAX, MCI_ANIM_WHERE_DESTINATION // $40000
862 PUSH EDX
863 PUSH EDX
864 PUSH EDX
865 PUSH EDX // rc = (0,0,0,0)
866 //PUSH ECX // dwCallback
867 MOV DX, MCI_WHERE or MCI_WAIT // $843
868 CALL asmSendCommand
869 //POP ECX // dwCallback
871 JZ @@success
872 MOV EDI, ESP
873 @@success:
874 POP [EDI].TRect.Left
875 POP [EDI].TRect.Top
876 POP [EDI].TRect.Right
877 POP [EDI].TRect.Bottom
879 POP EDI
880 POP EBX
881 end;
882 {$ELSE ASM_VERSION} //Pascal
883 function TMediaPlayer.GetDisplayRect: TRect;
884 var RectParms: TMCI_Anim_Rect_Parms;
885 begin
886 Result := MakeRect( 0, 0, 0, 0 );
887 //if HasVideo then
888 if SendCommand( MCI_WHERE, MCI_ANIM_WHERE_DESTINATION or MCI_WAIT, @RectParms ) = 0 then
889 Result := RectParms.rc;
890 end;
891 {$ENDIF ASM_VERSION}
893 {$IFDEF ASM_VERSION}
894 procedure TMediaPlayer.SetDisplayRect(const Value: TRect);
896 PUSH EBX
897 XCHG EBX, EAX
899 MOV ECX, [EDX].TRect.Right
900 OR ECX, [EDX].TRect.Bottom
901 JNZ @@passValue
903 MOV EAX, [EBX].FHeight
904 ADD EAX, [EDX].TRect.Top
905 PUSH EAX // rc.Bottom
906 MOV EAX, [EBX].FWidth
907 ADD EAX, [EDX].TRect.Left
908 PUSH EAX // rc.Right
910 JMP @@1
911 @@passValue:
912 PUSH [EDX].TRect.Bottom
913 PUSH [EDX].TRect.Right
914 @@1:
915 PUSH [EDX].TRect.Top
916 PUSH [EDX].TRect.Left
918 //PUSH ECX // dwCallback
919 MOV EAX, MCI_ANIM_RECT or MCI_ANIM_PUT_DESTINATION or MCI_WAIT
921 MOV DX, MCI_PUT
922 CALL asmSendCommand
923 ADD ESP, 16
924 POP EBX
925 end;
926 {$ELSE ASM_VERSION} //Pascal
927 procedure TMediaPlayer.SetDisplayRect(const Value: TRect);
928 var RectParms: TMCI_Anim_Rect_Parms;
929 begin
930 if (Value.Bottom = 0) and (Value.Right = 0) then
931 begin
932 {special case, use default width and height}
933 with Value do
934 RectParms.rc := MakeRect(Left, Top, Left+FWidth, Top+FHeight);
936 else RectParms.rc := Value;
937 SendCommand( MCI_PUT, MCI_ANIM_RECT or MCI_ANIM_PUT_DESTINATION or MCI_WAIT,
938 @RectParms );
939 end;
940 {$ENDIF ASM_VERSION}
942 {$IFDEF ASM_VERSION}
943 function TMediaPlayer.GetErrorMessage: String;
945 ADD ESP, -1024
946 MOV ECX, ESP
947 PUSH EDX
948 PUSH 1024
949 PUSH ECX
950 PUSH [EAX].FError
951 CALL mciGetErrorString
952 POP EDX // EDX = @Result
953 TEST EAX, EAX
954 JNZ @@1
955 POP ECX
956 PUSH EAX
957 @@1:
958 XCHG EAX, EDX
959 MOV EDX, ESP
960 CALL System.@LStrFromPChar
961 ADD ESP, 1024
962 end;
963 {$ELSE ASM_VERSION} //Pascal
964 function TMediaPlayer.GetErrorMessage: String;
966 ErrMsg: array[0..1023{129 - in win32.hlp, 128 bytes are always sufficient, but...}] of Char;
967 begin
968 if not mciGetErrorString(FError, ErrMsg, SizeOf(ErrMsg)) then
969 ErrMsg[ 0 ] := #0;
970 Result := ErrMsg;
971 end;
972 {$ENDIF ASM_VERSION}
974 {$IFDEF ASM_VERSION}
975 function TMediaPlayer.GetState: TMPState;
977 XOR EDX, EDX
978 MOV DL, MCI_STATUS_MODE // $4
979 CALL GetIState
980 {$IFDEF PARANOIA}
981 DB $2C, $0C
982 {$ELSE}
983 SUB AL, 12
984 {$ENDIF}
985 end;
986 {$ELSE ASM_VERSION} //Pascal
987 function TMediaPlayer.GetState: TMPState;
988 begin
989 Result := TMPState( GetIState( MCI_STATUS_MODE ) - 524 );
990 end;
991 {$ENDIF ASM_VERSION}
993 {$IFDEF ASM_noVERSION} //alias
994 function TMediaPlayer.Open: Boolean;
996 MOV [FMMNotify], offset[MMNotifyProc]
997 PUSH EBX
998 PUSH ESI
999 XCHG EBX, EAX
1000 MOV ECX, [EBX].FDeviceID
1001 TEST ECX, ECX
1002 JNZ @@exit
1003 PUSH ECX // lpstrAlias
1004 PUSH [EBX].FFileName // lpstrElementName
1005 MOVZX EAX, [EBX].FDeviceType
1007 TEST EAX, EAX
1008 MOV DH, MCI_OPEN_ELEMENT shr 8 // MCI_OPEN_ELEMENT = $200
1009 JZ @@all_types
1010 MOV DX, MCI_OPEN_TYPE or MCI_OPEN_TYPE_ID
1011 ADD AX, 513
1012 @@all_types:
1013 DEC EAX
1014 PUSH EAX // lpstrDeviceType
1015 DEC [EBX].FDeviceID
1016 XCHG EAX, EDX
1017 OR AX, MCI_NOTIFY or MCI_OPEN_SHAREABLE //$101
1019 MOV DX, MCI_OPEN //$803
1020 MOV ESI, EAX
1021 PUSH EAX // wDeviceID
1022 CALL asmSendCommand
1023 JZ @@opened
1024 DEC [EBX].FDeviceID
1025 XCHG EAX, ESI
1026 AND AH, $FE // Flag := Flag and not MCI_OPEN_SHAREABLE
1028 MOV DX, MCI_OPEN
1029 CALL asmSendCommand
1030 @@opened:
1031 POP EDX // EDX = wDeviceID
1032 POP ECX
1033 POP ECX
1034 POP ECX
1035 JNZ @@exit
1036 MOV [EBX].FDeviceID, EDX
1037 MOV [EBX].FWidth, EAX
1038 MOV [EBX].FHeight, EBX
1039 MOV EAX, EBX
1040 XOR EDX, EDX
1041 MOV DL, MCI_GETDEVCAPS_HAS_VIDEO // $3
1042 CALL GetCapability
1043 TEST AL, AL
1044 JZ @@noDisplay
1046 MOV EAX, EBX
1047 MOV EDX, [EBX].FDisplay
1048 CALL SetDisplay
1049 ADD ESP, -16
1050 MOV EAX, EBX
1051 MOV EDX, ESP
1052 CALL GetDisplayRect
1053 POP ECX // Left
1054 POP EDX // Top
1055 POP EAX // Right
1056 SUB EAX, ECX
1057 MOV [EBX].FWidth, EAX
1058 POP EAX // Bottom
1059 SUB EAX, EDX
1060 MOV [EBX].FHeight, EAX
1062 @@noDisplay:
1063 XOR EAX, EAX
1064 MOV word ptr [EBX].FAudioOff, AX
1065 MOV EAX, EBX
1066 MOVZX EDX, [EBX].FTimeFormat
1067 CALL SetTimeFormat
1069 @@exit:
1070 MOV EAX, [EBX].FDeviceID
1071 TEST EAX, EAX
1072 SETNZ AL
1073 POP ESI
1074 POP EBX
1075 end;
1076 {$ELSE ASM_VERSION} //Pascal
1077 function TMediaPlayer.Open: Boolean;
1078 const DevTypes: array [ TMPDeviceType ] of DWORD = ( MCI_ALL_DEVICE_ID,
1079 MCI_DEVTYPE_VCR, MCI_DEVTYPE_VIDEODISC, MCI_DEVTYPE_OVERLAY,
1080 MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_DAT, MCI_DEVTYPE_SCANNER,
1081 MCI_DEVTYPE_ANIMATION, MCI_DEVTYPE_DIGITAL_VIDEO, MCI_DEVTYPE_OTHER,
1082 MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_SEQUENCER );
1084 OpenParm: TMCI_Open_Parms;
1085 Flag: Integer;
1086 DisplayR: TRect;
1087 R: Integer;
1088 begin
1089 FMMNotify := MMNotifyProc;
1090 if FDeviceID <> 0 then Result := True { opened already } else
1091 begin
1092 ASSERT( (FFileName = '') and (FDeviceType <> mmAutoSelect)
1093 or FileExists( FFileName ), 'Multimedia file does not exist' );
1094 ASSERT( not ((FDeviceType in [ mmVideoDisc, mmCDAudio, mmVCR, mmDigitalVideo {more?} ])
1095 and (FFileName <> '')), 'FileName can not be used with simple multimedia device' );
1096 FillChar(OpenParm, SizeOf(TMCI_Open_Parms), 0);
1097 Flag := MCI_OPEN_ELEMENT;
1098 if FDeviceType <> mmAutoSelect then
1099 begin
1100 Flag := MCI_OPEN_TYPE or MCI_OPEN_TYPE_ID;
1101 end;
1102 if FAlias <> '' then
1103 begin
1104 Flag := Flag or MCI_OPEN_ALIAS;
1105 OpenParm.lpstrAlias := PChar( FAlias );
1106 end;
1107 OpenParm.lpstrDeviceType := Pointer( DevTypes[ FDeviceType ] );
1108 OpenParm.lpstrElementName := PChar(FFileName);
1109 FDeviceID := -1;
1110 R := SendCommand( MCI_OPEN, MCI_NOTIFY or MCI_OPEN_SHAREABLE or Flag, @OpenParm );
1111 if (R <> 0) then
1112 begin
1113 FDeviceID := -1;
1114 R := SendCommand( MCI_OPEN, MCI_NOTIFY or Flag, @OpenParm );
1115 end;
1117 if (R <> 0) then
1118 Result := False
1119 else
1120 begin
1121 FDeviceID := OpenParm.wDeviceID;
1122 FWidth := 0;
1123 FHeight := 0;
1124 if HasVideo then
1125 begin
1126 Display := FDisplay;
1127 DisplayR := GetDisplayRect;
1128 FWidth := DisplayR.Right-DisplayR.Left;
1129 FHeight := DisplayR.Bottom-DisplayR.Top;
1130 end;
1131 TimeFormat := FTimeFormat;
1132 FAudioOff[ chLeft ] := False;
1133 FAudioOff[ chRight ] := False;
1134 Result := True;
1135 end;
1136 end;
1137 end;
1138 {$ENDIF ASM_VERSION}
1140 {$IFDEF ASM_VERSION}
1141 function TMediaPlayer.Play( StartPos, PlayLength: Integer ): Boolean;
1143 PUSH EBX
1144 XCHG EBX, EAX
1145 XOR EAX, EAX
1146 TEST ECX, ECX
1147 JL @@noTo
1148 TEST EDX, EDX
1149 PUSH EDX
1150 JGE @@startPlusLen
1151 PUSH ECX
1152 CALL GetPosition
1153 XCHG EDX, EAX
1154 POP ECX
1155 @@startPlusLen:
1156 ADD ECX, EDX
1157 POP EDX
1158 XOR EAX, EAX
1159 MOV AL, MCI_TO // $8
1160 @@noTo:
1161 PUSH ECX // dwTo
1163 TEST EDX, EDX
1164 JZ @@noFrom
1165 {$IFDEF PARANOIA}
1166 DB $0C, $04
1167 {$ELSE}
1168 OR AL, MCI_FROM // $4
1169 {$ENDIF}
1170 @@noFrom:
1171 PUSH EDX // dwFrom
1172 INC EAX // Flags := Flags or MCI_NOTIFY
1174 MOV DX, MCI_PLAY //$806
1175 CALL asmSendCommand
1176 SETZ AL
1177 POP ECX
1178 POP ECX
1179 POP EBX
1180 end;
1181 {$ELSE ASM_VERSION} //Pascal
1182 function TMediaPlayer.Play( StartPos, PlayLength: Integer ): Boolean;
1183 var PlayParm: TMCI_Play_Parms;
1184 Flags: Integer;
1185 begin
1186 Flags := 0;
1187 if StartPos >= 0 then
1188 begin
1189 PlayParm.dwFrom := StartPos;
1190 Flags := MCI_FROM;
1191 end;
1192 if PlayLength >= 0 then
1193 begin
1194 if StartPos >= 0 then
1195 PlayParm.dwTo := StartPos + PlayLength
1196 else
1197 PlayParm.dwTo := Position + PlayLength;
1198 Flags := Flags or MCI_TO;
1199 end;
1200 Result := SendCommand( MCI_PLAY, Flags or MCI_NOTIFY, @PlayParm ) = 0;
1201 end;
1202 {$ENDIF ASM_VERSION}
1204 {$IFDEF ASM_VERSION}
1205 function TMediaPlayer.Save( const aFileName: String ): Boolean;
1207 PUSH EBX
1208 XCHG EAX, EBX
1209 PUSH EDX
1210 XOR EAX, EAX
1212 MOV AX, MCI_SAVE_FILE or MCI_NOTIFY
1213 MOV DX, MCI_SAVE
1214 CALL asmSendCommand
1215 SETZ AL
1216 POP EDX
1217 POP EBX
1218 end;
1219 {$ELSE ASM_VERSION} //Pascal
1220 function TMediaPlayer.Save( const aFileName: String ): Boolean;
1221 var SaveParm: TMCI_SaveParms;
1222 begin
1223 //Result := False;
1224 //if FDeviceID = 0 then Exit;
1225 SaveParm.lpfilename := PChar( aFileName );
1226 Result := SendCommand( MCI_SAVE, MCI_NOTIFY or MCI_SAVE_FILE, @SaveParm ) = 0;
1227 end;
1228 {$ENDIF ASM_VERSION}
1230 {$IFNDEF _FPC}
1231 function TMediaPlayer.asmSendCommand(Flags {in EAX}, Cmd {in EDX}: Integer {; var Buf in stack}): Integer;
1233 POP ECX
1234 PUSH ECX
1235 PUSH ECX
1236 LEA ECX, [ESP+4]
1237 PUSH ECX // Buffer
1238 MOV ECX, [EBX].FDeviceID
1239 JECXZ @@error
1240 {$IFDEF PARANOIA}
1241 DB $A8, $02
1242 {$ELSE}
1243 TEST AL, MCI_WAIT
1244 {$ENDIF}
1245 JNZ @@1
1246 {$IFDEF PARANOIA}
1247 DB $24, $FD
1248 {$ELSE}
1249 AND AL, not MCI_WAIT
1250 {$ENDIF}
1251 CMP [EBX].FWait, 0
1252 JZ @@1
1253 {$IFDEF PARANOIA}
1254 DB $0C, $02
1255 {$ELSE}
1256 OR AL, MCI_WAIT
1257 {$ENDIF}
1258 @@1:
1259 {$IFDEF PARANOIA}
1260 DB $A8, $02
1261 {$ELSE}
1262 TEST AL, MCI_WAIT
1263 {$ENDIF}
1264 JNZ @@clr_notify
1265 CMP [Applet], 0
1266 JNZ @@2
1267 @@clr_notify:
1268 {$IFDEF PARANOIA}
1269 DB $24, $FE
1270 {$ELSE}
1271 AND AL, not MCI_NOTIFY
1272 {$ENDIF}
1273 @@2:
1274 PUSH EAX // Flags
1275 {$IFDEF PARANOIA}
1276 DB $A8, $01
1277 {$ELSE}
1278 TEST AL, MCI_NOTIFY
1279 {$ENDIF}
1280 JZ @@3
1282 MOV EAX, [Applet]
1283 MOV EAX, [EAX].TControl1.FHandle
1284 MOV [ESP+12], EAX // dwCallback := Applet.FHandle
1285 @@3:
1286 PUSH EDX // Cmd
1288 INC ECX
1289 JZ @@4
1290 DEC ECX
1291 @@4: PUSH ECX // FDeviceID=-1?0:FDeviceID
1293 CALL mciSendCommand
1294 XCHG ECX, EAX
1295 INC ECX
1296 PUSH EDX
1297 @@error:
1298 POP EDX
1299 DEC ECX
1300 XCHG EAX, ECX
1301 MOV [EBX].FError, EAX
1302 TEST EAX, EAX // also return "ZF" if OK (no errors)
1303 POP ECX
1304 POP EDX
1305 PUSH ECX
1306 end;
1307 {$ENDIF _FPC}
1309 {$IFDEF ASM_VERSION}
1310 function TMediaPlayer.SendCommand(Cmd, Flags: Integer; Buffer: Pointer): Integer;
1312 PUSH EBX
1313 XCHG EBX, EAX
1314 OR [EBX].FError, -1
1315 XCHG EAX, ECX // EAX=Flags
1316 MOV ECX, [EBX].FDeviceID
1317 JECXZ @@exit
1318 PUSH Buffer // -> Buffer
1319 {$IFDEF PARANOIA}
1320 DB $A8, $02
1321 {$ELSE}
1322 TEST AL, MCI_WAIT
1323 {$ENDIF}
1324 JNZ @@1
1325 {$IFDEF PARANOIA}
1326 DB $24, $FD
1327 {$ELSE}
1328 AND AL, not MCI_WAIT
1329 {$ENDIF}
1330 CMP [EBX].FWait, 0
1331 JZ @@1
1332 {$IFDEF PARANOIA}
1333 DB $0C, $02
1334 {$ELSE}
1335 OR AL, MCI_WAIT
1336 {$ENDIF}
1337 @@1:
1338 {$IFDEF PARANOIA}
1339 DB $A8, $02
1340 {$ELSE}
1341 TEST AL, MCI_WAIT
1342 {$ENDIF}
1343 JNZ @@clrNotify
1344 SUB [Applet], 0
1345 JNZ @@2
1346 @@clrNotify:
1347 {$IFDEF PARANOIA}
1348 DB $24, $FE
1349 {$ELSE}
1350 AND AL, not MCI_NOTIFY
1351 {$ENDIF}
1352 @@2:
1353 PUSH EAX // -> Flags
1354 PUSH EDX // -> Cmd
1355 {$IFDEF PARANOIA}
1356 DB $A8, $01
1357 {$ELSE}
1358 TEST AL, MCI_NOTIFY
1359 {$ENDIF}
1360 JZ @@noNotify
1361 MOV EAX, [Applet]
1362 MOV EAX, [EAX].TControl.FHandle
1363 MOV EDX, [Buffer]
1364 MOV [EDX], EAX
1365 @@noNotify:
1366 INC ECX
1367 JZ @@devID
1368 DEC ECX
1369 @@devID:
1370 PUSH ECX
1371 CALL mciSendCommand
1372 MOV [EBX].FError, EAX
1373 @@exit:
1374 MOV EAX, [EBX].FError
1375 POP EBX
1376 end;
1377 {$ELSE ASM_VERSION} //Pascal
1378 function TMediaPlayer.SendCommand(Cmd, Flags: Integer; Buffer: Pointer): Integer;
1379 var Parms: PMCI_Generic_Parms;
1380 begin
1381 FError := -1;
1382 if FDeviceID <> 0 then
1383 begin
1384 if not LongBool( Flags and MCI_WAIT ) then
1385 begin
1386 Flags := Flags and not MCI_WAIT;
1387 if FWait then
1388 Flags := Flags or MCI_WAIT;
1389 end;
1390 if LongBool( Flags and MCI_WAIT ) or not Assigned( Applet ) then
1391 Flags := Flags and not MCI_NOTIFY;
1392 Parms := Buffer;
1393 //Parms.dwCallback := Applet.FHandle;
1394 if LongBool( Flags and (MCI_NOTIFY {or MCI_WAIT})) then
1395 begin
1396 {if FDisplay <> 0 then
1397 Parms.dwCallback := FDisplay
1398 else}
1399 Parms.dwCallback := PControl1( Applet ).FHandle; // MakeLong( Applet.FHandle, 0 );
1400 end;
1401 if FDeviceID = -1 then
1402 FDeviceID := 0;
1403 FError := mciSendCommand( FDeviceID, Cmd, Flags, Integer(Buffer) );
1404 end;
1405 Result := FError;
1406 end;
1407 {$ENDIF ASM_VERSION}
1409 {$IFDEF ASM_VERSION}
1410 procedure TMediaPlayer.SetDisplay(const Value: HWND);
1412 PUSH EBX
1413 XCHG EBX, EAX
1414 PUSH EDX
1415 MOV EAX, MCI_WAIT or MCI_ANIM_WINDOW_HWND
1417 MOV DX, MCI_WINDOW //$841
1418 CALL asmSendCommand
1419 POP EDX
1420 JNZ @@exit
1421 MOV [EBX].FDisplay, EDX
1422 @@exit:
1423 POP EBX
1424 end;
1425 {$ELSE ASM_VERSION} //Pascal
1426 procedure TMediaPlayer.SetDisplay(const Value: HWND);
1427 var AniWndParm: TMCI_Anim_Window_Parms;
1428 begin
1429 FDisplay := Value;
1430 if Value <> 0 then
1431 AniWndParm.Wnd := Value
1432 else
1433 AniWndParm.Wnd := 0;
1434 if SendCommand( MCI_WINDOW, MCI_WAIT or MCI_ANIM_WINDOW_HWND, @AniWndParm ) <> 0 then
1435 FDisplay := 0;
1436 end;
1437 {$ENDIF ASM_VERSION}
1439 {$IFDEF ASM_VERSION}
1440 procedure TMediaPlayer.SetPause(const Value: Boolean);
1442 PUSH EBX
1443 XCHG EBX, EAX
1444 XOR EAX, EAX
1445 INC EAX
1446 DEC DL
1448 MOV DX, MCI_PAUSE
1449 JZ @@pause
1450 MOV DL, MCI_RESUME and $FF
1451 @@pause:
1452 CALL asmSendCommand
1453 POP EBX
1454 end;
1455 {$ELSE ASM_VERSION} //Pascal
1456 procedure TMediaPlayer.SetPause(const Value: Boolean);
1457 var Cmd: Integer;
1458 GenParm: TMCI_Generic_Parms;
1459 begin
1460 if Value then
1461 Cmd := MCI_PAUSE
1462 else
1463 Cmd := MCI_RESUME;
1464 SendCommand( Cmd, MCI_NOTIFY, @GenParm );
1465 end;
1466 {$ENDIF ASM_VERSION}
1468 {$IFDEF ASM_VERSION}
1469 procedure TMediaPlayer.SetPosition(Value: Integer);
1471 PUSH EBX
1472 XCHG EBX, EAX
1473 PUSH EDX
1474 XOR EAX, EAX
1476 MOV AL, MCI_NOTIFY or MCI_TO //$9
1477 MOV DX, MCI_SEEK
1478 CALL asmSendCommand
1479 POP EDX
1480 POP EBX
1481 end;
1482 {$ELSE ASM_VERSION} //Pascal
1483 procedure TMediaPlayer.SetPosition(Value: Integer);
1484 var SeekParm: TMCI_Seek_Parms;
1485 begin
1486 SeekParm.dwTo := Value;
1487 SendCommand( MCI_SEEK, MCI_NOTIFY or MCI_TO, @SeekParm );
1488 end;
1489 {$ENDIF ASM_VERSION}
1491 {$IFDEF ASM_VERSION}
1492 procedure TMediaPlayer.SetTrack(Value: Integer);
1494 CMP EDX, [EAX].FTrack
1495 JZ @@exit
1496 PUSH EAX
1497 PUSH EDX
1498 XOR EDX, EDX
1499 MOV DL, MCI_STATUS_NUMBER_OF_TRACKS // $3
1500 CALL GetIState
1501 POP EDX
1502 POP ECX
1503 CMP EDX, EAX
1504 JLE @@1
1505 XCHG EDX, EAX
1506 @@1:
1507 MOV [ECX].FTrack, EDX
1508 @@exit:
1509 end;
1510 {$ELSE ASM_VERSION} //Pascal
1511 procedure TMediaPlayer.SetTrack(Value: Integer);
1512 var TC: Integer;
1513 begin
1514 if FTrack = Value then Exit;
1515 TC := TrackCount;
1516 if Value > TC then
1517 Value := TC;
1518 FTrack := Value;
1519 end;
1520 {$ENDIF ASM_VERSION}
1522 {$IFDEF ASM_VERSION}
1523 procedure TMediaPlayer.SetFileName(const Value: String);
1525 PUSHAD
1526 MOV EAX, [EAX].FFileName
1527 CALL System.@LStrCmp
1528 POPAD
1529 JZ @@1
1530 PUSHAD
1531 CALL Close
1532 POPAD
1533 @@1:
1534 PUSHAD
1535 LEA EAX, [EAX].FFileName
1536 CALL System.@LStrAsg
1537 POPAD
1538 TEST EDX, EDX
1539 JNZ Open
1540 end;
1541 {$ELSE ASM_VERSION} //Pascal
1542 procedure TMediaPlayer.SetFileName(const Value: String);
1543 begin
1544 if FFileName <> Value then
1545 Close;
1546 FFileName := Value;
1547 if Value <> '' then
1548 Open;
1549 end;
1550 {$ENDIF ASM_VERSION}
1552 {$IFDEF ASM_VERSION}
1553 function TMediaPlayer.GetBState( const Index: Integer ): Boolean;
1555 CALL GetIState
1556 {$IFDEF PARANOIA}
1557 DB $24, $01
1558 {$ELSE}
1559 AND AL, 1
1560 {$ENDIF}
1561 end;
1562 {$ELSE ASM_VERSION} //Pascal
1563 function TMediaPlayer.GetBState( const Index: Integer ): Boolean;
1564 begin
1565 Result := (GetIState( Index ) and 1) = 1;
1566 end;
1567 {$ENDIF ASM_VERSION}
1569 {$IFDEF ASM_VERSION}
1570 function TMediaPlayer.GetIState(const Index: Integer): Integer;
1572 PUSH EBX
1573 XCHG EBX, EAX
1574 MOV ECX, [EBX].FTrack
1575 PUSH ECX
1576 PUSH EDX
1577 AND byte ptr [ESP+3], $7F
1578 XOR EAX, EAX // flags = 0
1579 PUSH EAX
1580 MOV AX, MCI_WAIT or MCI_STATUS_ITEM
1581 TEST EDX, EDX
1582 JGE @@1
1583 JECXZ @@1
1584 {$IFDEF PARANOIA}
1585 DB $0C, MCI_TRACK
1586 {$ELSE}
1587 OR AL, MCI_TRACK
1588 {$ENDIF}
1589 @@1:
1591 MOV DX, MCI_STATUS
1592 CALL asmSendCommand
1593 POP EAX
1594 POP ECX
1595 POP ECX
1596 JZ @@2
1597 XOR EAX, EAX
1598 @@2:
1599 POP EBX
1600 end;
1601 {$ELSE ASM_VERSION} //Pascal
1602 function TMediaPlayer.GetIState(const Index: Integer): Integer;
1603 var StatusParm: TMCI_Status_Parms;
1604 Flags: Integer;
1605 begin
1606 Flags := 0;
1607 StatusParm.dwItem := Index and $7FFFFFFF;
1608 if Index < 0 then
1609 if FTrack <> 0 then
1610 begin
1611 Flags := MCI_TRACK;
1612 StatusParm.dwTrack := FTrack;
1613 end;
1614 Result := 0;
1615 if SendCommand( MCI_STATUS, MCI_WAIT or MCI_STATUS_ITEM or Flags, @StatusParm ) = 0 then
1616 Result := StatusParm.dwReturn;
1617 end;
1618 {$ENDIF ASM_VERSION}
1620 {$IFDEF ASM_VERSION}
1621 function TMediaPlayer.GetPosition: Integer;
1623 XOR EDX, EDX
1624 MOV DL, MCI_STATUS_POSITION //$2
1625 CALL GetIState
1626 end;
1627 {$ELSE ASM_VERSION} //Pascal
1628 function TMediaPlayer.GetPosition: Integer;
1629 begin
1630 Result := GetIState( MCI_STATUS_POSITION );
1631 end;
1632 {$ENDIF ASM_VERSION}
1634 {$IFDEF ASM_VERSION}
1635 function TMediaPlayer.GetTimeFormat: TMPTimeFormat;
1637 XOR EDX, EDX
1638 MOV DL, MCI_STATUS_TIME_FORMAT // $6
1639 CALL GetIState
1640 end;
1641 {$ELSE ASM_VERSION} //Pascal
1642 function TMediaPlayer.GetTimeFormat: TMPTimeFormat;
1643 begin
1644 Result := TMPTimeFormat( GetIState( MCI_STATUS_TIME_FORMAT ) );
1645 end;
1646 {$ENDIF ASM_VERSION}
1648 {$IFDEF ASM_VERSION}
1649 procedure TMediaPlayer.SetTimeFormat(const Value: TMPTimeFormat);
1651 PUSH EBX
1652 XCHG EBX, EAX
1653 MOVZX EDX, DL
1654 PUSH EDX
1655 XCHG EAX, EDX
1657 MOV AX, MCI_SET_TIME_FORMAT or MCI_NOTIFY
1658 MOV DX, MCI_SET //$80D
1659 CALL asmSendCommand
1660 POP EDX
1661 JNZ @@exit
1662 MOV [EBX].FTimeFormat, DL
1663 @@exit:
1664 POP EBX
1665 end;
1666 {$ELSE ASM_VERSION} //Pascal
1667 procedure TMediaPlayer.SetTimeFormat(const Value: TMPTimeFormat);
1668 var SetParm: TMCI_Set_Parms;
1669 begin
1670 ASSERT( (FDeviceID = 0) or (Value = tfMilliseconds)
1671 or (Value in [ tfBytes, tfSamples ]) and (DeviceType = mmWaveAudio)
1672 or (Value = tfFrames) and (DeviceType in [ mmVCR, mmVideoDisc, mmDigitalVideo ])
1673 or (Value = tfHMS) and (DeviceType in [ mmVCR, mmVideoDisc ])
1674 or (Value in [ tfMSF, tfTMSF ]) and (DeviceType in [ mmCDAudio, mmVCR ])
1675 or (Value in [ tfSMPTE24, tfSMPTE25, tfSMPTE30, tfSMPTE30Drop ])
1676 and (DeviceType in [ mmSequencer, mmVCR ]),
1677 'Time format not supported by multimedia device' );
1678 SetParm.dwTimeFormat := Ord( Value );
1679 if SendCommand( MCI_SET, MCI_NOTIFY or MCI_SET_TIME_FORMAT, @SetParm ) = 0 then
1680 FTimeFormat := Value;
1681 end;
1682 {$ENDIF ASM_VERSION}
1684 function TMediaPlayer.GetPause: Boolean;
1685 begin
1686 Result := State <> mpPlaying;
1687 end;
1689 const Key_CD_AutoPlay: PChar = 'AudioCD\Shell';
1690 Key_CD_AutoRun: PChar = 'Software\Microsoft\Windows\CurrentVersion\Policies\Explorer';
1691 Val_CD_AutoRun: PChar = 'NoDriveTypeAutoRun';
1693 {$IFDEF ASM_VERSION}
1694 procedure TMediaPlayer.Insert;
1696 PUSH EAX
1697 CALL DisableAutoPlay
1698 POP EAX
1699 MOV [EAX].FAutoRestore.TMethod.Code, offset[RestoreAutoPlay]
1700 CALL DoorClose
1701 end;
1702 {$ELSE ASM_VERSION} //Pascal
1703 procedure TMediaPlayer.Insert;
1704 begin
1705 DisableAutoPlay;
1706 FAutoRestore := RestoreAutoPlay;
1707 DoorClose;
1708 end;
1709 {$ENDIF ASM_VERSION}
1711 {$IFDEF ASM_VERSION}
1712 procedure TMediaPlayer.DisableAutoPlay;
1714 PUSH EBX
1715 XCHG EBX, EAX
1716 MOV EDX, [Key_CD_AutoRun]
1717 MOV EAX, HKEY_CURRENT_USER
1718 CALL RegKeyOpenWrite
1719 PUSH EAX // K1
1720 MOV EDX, [Val_CD_AutoRun]
1721 PUSH EDX
1722 CALL RegKeyGetDw
1723 POP EDX
1724 MOV [EBX].FOldKeyValCDData, EAX
1725 {$IFDEF PARANOIA}
1726 DB $A8, $20
1727 {$ELSE}
1728 TEST AL, $20
1729 {$ENDIF}
1730 JNZ @@1
1731 {$IFDEF PARANOIA}
1732 DB $0C, $20
1733 {$ELSE}
1734 OR AL, $20
1735 {$ENDIF}
1736 XCHG ECX, EAX
1737 POP EAX
1738 PUSH EAX
1739 CALL RegKeySetDw
1740 @@1:
1741 POP EAX
1742 CALL RegKeyClose
1744 MOV EAX, HKEY_CURRENT_USER
1745 MOV EDX, [Key_CD_AutoPlay]
1746 PUSH EAX
1747 PUSH EDX
1748 CALL RegKeyOpenWrite
1749 POP EDX
1750 POP ECX
1751 TEST EAX, EAX
1752 JNZ @@2
1754 MOV EAX, HKEY_CLASSES_ROOT
1755 PUSH EAX
1756 CALL RegKeyOpenWrite
1757 POP ECX
1758 @@2:
1759 MOV [EBX].FBaseKeyCDAudio, ECX
1760 PUSH EAX // K2
1761 XOR EDX, EDX
1762 LEA ECX, [EBX].FoldKeyValCDAudio
1763 CALL RegKeyGetStr
1764 MOV ECX, [EBX].FoldKeyValCDAudio
1765 JECXZ @@3
1767 POP EAX
1768 PUSH EAX
1770 XOR EDX, EDX
1771 XOR ECX, ECX
1772 CALL RegKeySetStr
1773 @@3:
1774 POP EAX
1775 CALL RegKeyClose
1777 POP EBX
1778 end;
1779 {$ELSE ASM_VERSION} //Pascal
1780 procedure TMediaPlayer.DisableAutoPlay;
1781 var K1, K2: HKey;
1782 begin
1783 K1 := RegKeyOpenWrite( HKEY_CURRENT_USER, Key_CD_AutoRun );
1784 FoldKeyValCDData := RegKeyGetDw( K1, Val_CD_AutoRun );
1785 if (FoldKeyValCDData and $20) = 0 then
1786 begin
1787 RegKeySetDw( K1, Val_CD_AutoRun, FoldKeyValCDData or $20 );
1788 end;
1789 RegKeyClose( K1 );
1791 FBaseKeyCDAudio := HKEY_CURRENT_USER;
1792 K2 := RegKeyOpenWrite( FBaseKeyCDAudio, Key_CD_AutoPlay );
1793 if K2 = 0 then
1794 begin
1795 FBaseKeyCDAudio := HKEY_CLASSES_ROOT;
1796 K2 := RegKeyOpenWrite( FBaseKeyCDAudio, Key_CD_AutoPlay );
1797 end;
1798 FoldKeyValCDAudio := RegKeyGetStr( K2, '' );
1799 if FoldKeyValCDAudio <> '' then
1800 begin
1801 RegKeySetStr( K2, '', '' );
1802 end;
1803 RegKeyClose( K2 );
1804 end;
1805 {$ENDIF ASM_VERSION}
1807 {$IFDEF ASM_VERSION}
1808 procedure TMediaPlayer.RestoreAutoPlay;
1810 PUSH EBX
1811 XCHG EBX, EAX
1812 XOR EAX, EAX
1813 MOV [EBX].FAutoRestore.TMethod.Code, EAX
1814 MOV EAX, [EBX].FoldKeyValCDData
1815 {$IFDEF PARANOIA}
1816 DB $A8, $20
1817 {$ELSE}
1818 TEST AL, $20
1819 {$ENDIF}
1820 JNZ @@1
1822 PUSH EAX
1823 MOV EAX, HKEY_CURRENT_USER
1824 MOV EDX, [Key_CD_AutoRun]
1825 CALL RegKeyOpenWrite
1826 POP ECX
1827 PUSH EAX
1828 MOV EDX, [Val_CD_AutoRun]
1829 CALL RegKeySetDw
1830 POP EAX
1831 CALL RegKeyClose
1832 @@1:
1833 MOV ECX, [EBX].FoldKeyValCDAudio
1834 JECXZ @@2
1836 PUSH ECX
1837 MOV EAX, [EBX].FBaseKeyCDAudio
1838 MOV EDX, [Key_CD_AutoPlay]
1839 CALL RegKeyOpenWrite
1840 POP ECX
1841 XOR EDX, EDX
1842 PUSH EAX
1843 CALL RegKeySetStr
1844 POP EAX
1845 CALL RegKeyClose
1846 @@2:
1847 POP EBX
1848 end;
1849 {$ELSE ASM_VERSION} //Pascal
1850 procedure TMediaPlayer.RestoreAutoPlay;
1851 var K1, K2: HKey;
1852 begin
1853 FAutoRestore := nil;
1854 if (FoldKeyValCDData and $20) = 0 then
1855 begin
1856 K1 := RegKeyOpenWrite( HKEY_CURRENT_USER, Key_CD_AutoRun );
1857 RegKeySetDw( K1, Val_CD_AutoRun, FoldKeyValCDData );
1858 RegKeyClose( K1 );
1859 end;
1861 if FoldKeyValCDAudio <> '' then
1862 begin
1863 K2 := RegKeyOpenWrite( FBaseKeyCDAudio, Key_CD_AutoPlay );
1864 RegKeySetStr( K2, '', FoldKeyValCDAudio );
1865 RegKeyClose( K2 );
1866 end;
1867 end;
1868 {$ENDIF ASM_VERSION}
1870 {$IFDEF ASM_VERSION}
1871 function TMediaPlayer.StartRecording(FromPos, ToPos: Integer): Boolean;
1873 PUSH EBX
1874 XCHG EBX, EAX
1875 XOR EAX, EAX
1876 INC EAX // MCI_NOTIFY
1877 TEST ECX, ECX
1878 JL @@noTo
1879 {$IFDEF PARANOIA}
1880 DB $0C, MCI_TO
1881 {$ELSE}
1882 OR AL, MCI_TO
1883 {$ENDIF}
1884 @@noTo: PUSH ECX // dwTo
1885 TEST EDX, EDX
1886 JL @@noFrom
1887 {$IFDEF PARANOIA}
1888 DB $0C, MCI_FROM
1889 {$ELSE}
1890 OR AL, MCI_FROM
1891 {$ENDIF}
1892 @@noFrom: PUSH EDX
1894 MOV DX, MCI_RECORD
1895 CALL asmSendCommand
1896 POP EDX
1897 POP ECX
1898 SETZ AL
1899 POP EBX
1900 end;
1901 {$ELSE ASM_VERSION} //Pascal
1902 function TMediaPlayer.StartRecording(FromPos, ToPos: Integer): Boolean;
1903 var RecordParm: TMCI_Record_Parms;
1904 Flags: Integer;
1905 begin
1906 Flags := 0;
1907 if FromPos >= 0 then
1908 begin
1909 RecordParm.dwFrom := FromPos;
1910 Flags := MCI_FROM;
1911 end;
1912 if ToPos >= 0 then
1913 begin
1914 RecordParm.dwTo := ToPos;
1915 Flags := Flags or ToPos;
1916 end;
1917 Result := SendCommand( MCI_RECORD, Flags or MCI_NOTIFY, @RecordParm ) = 0;
1918 end;
1919 {$ENDIF ASM_VERSION}
1921 {$IFDEF ASM_VERSION}
1922 function TMediaPlayer.Stop: Boolean;
1924 PUSH EBX
1925 XCHG EBX, EAX
1926 XOR EAX, EAX
1928 INC EAX
1929 MOV DX, MCI_STOP
1930 CALL asmSendCommand
1931 SETZ AL
1932 POP EBX
1933 end;
1934 {$ELSE ASM_VERSION} //Pascal
1935 function TMediaPlayer.Stop: Boolean;
1936 var GenParm: TMCI_Generic_Parms;
1937 begin
1938 Result := SendCommand( MCI_STOP, MCI_NOTIFY, @GenParm ) = 0;
1939 end;
1940 {$ENDIF ASM_VERSION}
1942 function TMediaPlayer.GetAudioOn(Chn: TSoundChannels): Boolean;
1943 begin
1944 if Chn = [ chLeft, chRight ] then
1945 Result := not FAudioOff[ chLeft ] and not FAudioOff[ chRight ]
1946 else
1947 if Chn = [ ] then
1948 Result := not FAudioOff[ chLeft ] or not FAudioOff[ chRight ]
1949 else
1950 begin
1951 if chLeft in Chn then
1952 Result := not FAudioOff[ chLeft ]
1953 else
1954 //if chRight in Chn then
1955 Result := not FAudioOff[ chRight ];
1956 end;
1957 end;
1959 procedure TMediaPlayer.SetAudioOn(Chn: TSoundChannels; const Value: Boolean);
1960 var What: Integer;
1961 SetParm: TMCI_Set_Parms;
1962 begin
1963 if Chn = [ chLeft, chRight ] then
1964 What := MCI_SET_AUDIO_ALL
1965 else if Chn = [ chLeft ] then
1966 What := MCI_SET_AUDIO_LEFT
1967 else if Chn = [ chRight ] then
1968 What := MCI_SET_AUDIO_RIGHT
1969 else Exit;
1970 if chLeft in Chn then
1971 FAudioOff[ chLeft ] := not Value;
1972 if chRight in Chn then
1973 FAudioOff[ chRight ] := not Value;
1974 SetParm.dwAudio := What;
1975 if Value then
1976 What := MCI_SET_ON
1977 else
1978 What := MCI_SET_OFF;
1979 SendCommand( MCI_SET, What or MCI_WAIT or MCI_SET_AUDIO, @SetParm );
1980 end;
1982 function TMediaPlayer.GetVideoOn: Boolean;
1983 begin
1984 Result := not FVideoOff;
1985 end;
1987 procedure TMediaPlayer.SetVideoOn(const Value: Boolean);
1988 var SetParm: TMCI_Set_Parms;
1989 What: Integer;
1990 begin
1991 FVideoOff := not Value;
1992 if Value then
1993 What := MCI_SET_ON
1994 else
1995 What := MCI_SET_OFF;
1996 SendCommand( MCI_SET, MCI_WAIT or MCI_SET_VIDEO or What, @SetParm );
1997 end;
1999 function TMediaPlayer.DGVGetSpeed: Integer;
2000 begin
2001 Result := GetIState( $4003 {MCI_DGV_STATUS_SPEED} );
2002 end;
2004 procedure TMediaPlayer.DGVSetSpeed(const Value: Integer);
2005 type
2006 TMCI_DGV_Set_Parms = packed record
2007 dwCallback,
2008 dwTimeFormat,
2009 dwAudio,
2010 dwFileFormat,
2011 dwSpeed: DWORD;
2012 end;
2013 var DGVSetParm: TMCI_DGV_Set_Parms;
2014 begin
2015 DGVSetParm.dwSpeed := Value;
2016 SendCommand( MCI_SET, MCI_WAIT or $20000 {MCI_DGV_SET_SPEED}, @DGVSetParm );
2017 end;
2019 { -- PlaySound interafce functions -- }
2021 const PlaySndFlags: array[ TPlayOption ] of Integer = ( SND_LOOP, not SND_ASYNC,
2022 SND_NOSTOP, SND_NOWAIT );
2024 function PlaySoundMemory( Memory: Pointer; Options: TPlayOptions ): Boolean;
2025 begin
2026 Result := PlaySound( Memory, hInstance, MakeFlags( @Options, PlaySndFlags )
2027 or SND_MEMORY or SND_NODEFAULT );
2028 end;
2030 function PlaySoundResourceID( Inst, ResID: Integer; Options: TPlayOptions ): Boolean;
2031 { This does not work (at least, if resource stored in res-file as RC_DATA.
2032 begin
2033 Result := PlaySound( Pointer( ResID ), Inst, MakeFlags( @Options, PlaySndFlags )
2034 or SND_RESOURCE or SND_NODEFAULT );
2035 end;
2037 { This works, but only synchronously.
2038 var MS: PStream;
2039 begin
2040 MS := NewMemoryStream;
2041 Resource2Stream( MS, Inst, Pointer( ResID ), RT_RCDATA );
2042 Result := PlaySoundMemory( MS.Memory, Options + [poWait] );
2043 MS.Free;
2044 end;
2046 { This works asynchronously as it is set in Options (if needed). }
2047 var Find, Res: THandle;
2048 Ptr: Pointer;
2049 begin
2050 Result := False;
2051 Find := FindResource( Inst, Pointer( ResID ), RT_RCDATA );
2052 if Find <> 0 then
2053 begin
2054 Res := LoadResource( Inst, Find );
2055 if Res <> 0 then
2056 begin
2057 Ptr := LockResource( Res );
2058 if Ptr <> nil then
2059 begin
2060 Result := PlaySoundMemory( Ptr, Options );
2061 end;
2062 end;
2063 end;
2064 end;
2066 function PlaySoundResourceName( Inst: Integer; const ResName: String; Options: TPlayOptions ): Boolean;
2067 var Find, Res: THandle;
2068 Ptr: Pointer;
2069 begin
2070 Result := False;
2071 Find := FindResource( Inst, PChar( ResNAme ), RT_RCDATA );
2072 if Find <> 0 then
2073 begin
2074 Res := LoadResource( Inst, Find );
2075 if Res <> 0 then
2076 begin
2077 Ptr := LockResource( Res );
2078 if Ptr <> nil then
2079 begin
2080 Result := PlaySoundMemory( Ptr, Options );
2081 end;
2082 end;
2083 end;
2084 end;
2086 function PlaySoundEvent( const EventName: String; Options: TPlayOptions ): Boolean;
2087 begin
2088 Result := PlaySound( PChar( EventName ), 0, MakeFlags( @Options, PlaySndFlags )
2089 or SND_ALIAS or SND_NODEFAULT );
2090 end;
2092 function PlaySoundFile( const FileName: String; Options: TPlayOptions ): Boolean;
2093 begin
2094 Result := PlaySound( PChar( FileName ), 0, MakeFlags( @Options, PlaySndFlags )
2095 or SND_FILENAME or SND_NODEFAULT );
2096 end;
2098 function PlaySoundStop: Boolean;
2099 begin
2100 Result := PlaySound( nil, 0, SND_PURGE );
2101 end;
2103 function WaveOutChannels( DevID: Integer ): TSoundChannels;
2104 var WC: TWaveOutCaps;
2105 begin
2106 Result := [ ];
2107 if waveOutGetDevCaps( DevID, @WC, sizeof( WC ) ) = MMSYSERR_NOERROR then
2108 begin
2109 if WC.wChannels = 2 then
2110 Result := [ chLeft, chRight ]
2111 else
2112 if WC.dwSupport = 1 then
2113 Result := [ chLeft ];
2114 end;
2115 end;
2117 function WaveOutVolume( DevID: Integer; Chn: TSoundChannel; NewValue: Integer ): Word;
2118 var V, V1: DWORD;
2119 NV : Integer;
2120 begin
2121 Result := 0;
2122 if waveOutGetVolume( DevID, @V ) = MMSYSERR_NOERROR then
2123 begin
2124 V1 := V;
2125 NV := NewValue;
2126 if Chn = chRight then
2127 begin
2128 V1 := V shr 16;
2129 V := V and $FFFF;
2130 NewValue := NewValue shl 16;
2132 else
2133 V := V and $FFFF0000;
2134 if NV >= $10000 then
2135 begin
2136 NewValue := (NV and $FFFF) or (NV shl 16);
2137 V := 0;
2138 end;
2139 Result := Word( V1 );
2140 if NV >= 0 then
2141 waveOutSetVolume( DevID, V or DWORD(NewValue) );
2142 end;
2143 end;
2145 end.