Ignore:
Timestamp:
May 8, 2020, 11:14:09 AM (5 years ago)
Author:
chronos
Message:
  • Fixed: Sound was played only once because LCL doesn't handle MM_MCINOTIFY message in same way as Delphi does. Added workaround to capture and handle that message.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Packages/CevoComponents/Sound.pas

    r189 r201  
    1212  TPlayStyle = (psAsync, psSync);
    1313
     14  { TSoundPlayer }
     15
    1416  TSoundPlayer = class(TForm)
    1517  private
    1618    {$IFDEF WINDOWS}
     19    PrevWndProc: WNDPROC;
    1720    procedure OnMCI(var m: TMessage); message MM_MCINOTIFY;
     21  public
     22    constructor Create(AOwner: TComponent); override;
    1823    {$ENDIF}
    1924  end;
     
    2328  TSound = class
    2429  private
     30    {$IFDEF LINUX}
    2531    PlayCommand: string;
    26     {$IFDEF LINUX}
    2732    SoundPlayerAsyncProcess: TAsyncProcess;
    2833    SoundPlayerSyncProcess: TProcess;
     
    8287    OpenParm.lpstrElementName := PChar(FFileName);
    8388    mciSendCommand(0, MCI_Open, MCI_WAIT or MCI_OPEN_ELEMENT or
    84       MCI_OPEN_SHAREABLE, integer(@OpenParm));
     89      MCI_OPEN_SHAREABLE, DWORD_PTR(@OpenParm));
    8590    FDeviceID := OpenParm.wDeviceID;
    8691  end
     
    239244
    240245{$IFDEF WINDOWS}
     246function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;
     247var
     248  Message: TMessage;
     249begin
     250  if (uMsg = MM_MCINOTIFY) then begin
     251    Message.msg := uMsg;
     252    Message.wParam := wParam;
     253    Message.lParam := lParam;
     254    SoundPlayer.OnMCI(Message);
     255  end;
     256  Result := CallWindowProc(SoundPlayer.PrevWndProc, Ahwnd, uMsg, WParam, LParam);
     257end;
     258
    241259procedure TSoundPlayer.OnMCI(var m: TMessage);
    242260begin
    243   if (m.wParam = MCI_Notify_Successful) and (PlayingSound <> nil) then
     261  if (m.wParam = MCI_NOTIFY_SUCCESSFUL) and (PlayingSound <> nil) then
    244262  begin
    245263    PlayingSound.Reset;
    246264    PlayingSound := nil;
    247265  end;
     266end;
     267
     268constructor TSoundPlayer.Create(AOwner: TComponent);
     269begin
     270  inherited;
     271  // MM_MCINOTIFY is not handled by LCL, fallback to low lever handling
     272  // https://wiki.lazarus.freepascal.org/Win32/64_Interface#Processing_non-user_messages_in_your_window
     273  PrevWndProc := Windows.WNDPROC(SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback)));
    248274end;
    249275{$ENDIF}
     
    274300
    275301function Play(Item: string; Index: Integer = -1): Boolean;
    276 {$IFNDEF DEBUG}
    277302var
    278303  WavFileName: string;
    279 {$ENDIF}
    280304begin
    281305  Result := False;
    282 {$IFNDEF DEBUG}
    283306  if (Sounds = nil) or (SoundMode = smOff) or (Item = '') then
    284307  begin
     
    292315    // SndPlaySound(pchar(GetSoundsDir + DirectorySeparator + WavFileName + '.wav'), SND_ASYNC)
    293316    PlaySound(GetSoundsDir + DirectorySeparator + WavFileName);
    294 {$ENDIF}
    295317end;
    296318
    297319procedure PreparePlay(Item: string; Index: Integer = -1);
    298 {$IFNDEF DEBUG}
    299320var
    300321  WavFileName: string;
    301 {$ENDIF}
    302 begin
    303 {$IFNDEF DEBUG}
     322begin
    304323  if (Sounds = nil) or (SoundMode = smOff) or (Item = '') then
    305324    Exit;
     
    308327  if (WavFileName <> '') and (WavFileName[1] <> '[') and (WavFileName <> '*') then
    309328    PrepareSound(GetSoundsDir + DirectorySeparator + WavFileName);
    310 {$ENDIF}
    311329end;
    312330
Note: See TracChangeset for help on using the changeset viewer.