Кроссплатформенная поддержка аудио в Delphi - PullRequest
0 голосов
/ 15 мая 2018

Я использую Delphi Tokyo и ищу способ воспроизведения звука на Windows и Android (и, может быть, в какой-то момент на iOS).

В Windows я могу сделать что-то вроде PlaySound(PChar(ResourceName), 0, SND_RESOURCE or SND_ASYNC), но я застрял на Android.Я пробовал TMediaPlayer, но до начала воспроизведения требуется около секунды, что слишком долго для щелчка мышью или касания экрана.

В основном я создал клон Сапера и ищу звукподдержка (если вы хотите знать фон).

Предложения?

1 Ответ

0 голосов
/ 15 мая 2018

Есть несколько демонстрационных примеров аркадных игр с аудио классами, которые вы можете использовать. Смотри https://github.com/Embarcadero/DelphiArcadeGames

Вы также можете увидеть этот вопрос stackoverflow Есть ли альтернатива TMediaPlayer для многоплатформенных быстрых звуковых эффектов? для описания некоторых проблем, возникающих на Android с классом управления звуком в этих демонстрациях.

С последней версией аудио-менеджера, представленной в примерах игр, разработчик просто удаляет все уведомления / проверяет, что аудио-файл действительно загружен и готов к воспроизведению. Мне лично не понравилась идея просто ожидать, что аудио будет готово для воспроизведения.

Мои классы управления аудио слишком сложны, чтобы просто публиковать их, но, если вам нужна эта функциональность, надеюсь, этот кусочек псевдокода может дать некоторые подсказки о том, как я исправил недостатки «AudioManager», представленные в демонстрационных версиях игры. Идея состоит в том, чтобы создать обратный вызов в моем основном приложении, который вызывается, когда аудиофайл готов к воспроизведению. С помощью небольшого поиска в Интернете я обнаружил, что следующие ссылки являются полезными для моей реализации: https://developer.android.com/reference/android/media/SoundPool https://www.101apps.co.za/articles/using-android-s-soundpool-class-a-tutorial.html

1 - Определите тип уведомления, который предоставит достаточную информацию о аудиофайле, который готов к воспроизведению. Моя выглядит так:

TSoundLoadedEvent = procedure(Sender: TObject; ASoundID: integer; AStatus: Integer) of object;

2 - В соответствии с документацией определите класс, который обрабатывает JSoundPool OnLoadCompleteListener. Обратите внимание, что класс использует наше пользовательское событие, определенное как TSoundLoadedEvent, что означает, что AudioManager должен будет реализовать этот обратный вызов.

TMyAudioLoadedListener = class(TJavaLocal, JSoundPool_OnLoadCompleteListener)
  private
    FSoundPool       : JSoundPool;
    FOnJLoadCompleted : TSoundLoadedEvent;
  public
    procedure onLoadComplete(soundPool: JSoundPool; sampleId,status: Integer); cdecl;
    property  OnLoadCompleted: TSoundLoadedEvent read FOnJLoadCompleted write FOnJLoadCompleted;
    property  SoundPool: JSoundPool read FSoundPool;
  end;
...
procedure TMyAudioLoadedListener.onLoadComplete(soundPool: JSoundPool; sampleId, status: Integer);
begin
  FSoundPool := soundPool;
  if Assigned(FOnJLoadCompleted) then
    FOnJLoadCompleted(Self, sampleID, status);
end;

3 - Изменить класс аудио-менеджера для реализации слушателя. :

  TAudioManager = Class
    Private
      fAudioMgr              : JAudioManager;
      fSoundPool             : JSoundPool;
      fmyAudioLoadedListener : TMyAudioLoadedListener;
      fOnPlatformLoadComplete : TSoundLoadedEvent;
    Public
      Constructor Create; override;
      ...
      procedure DoOnLoadComplete(Sender: TObject; sampleId: Integer; status: Integer);
      ...
      property  OnLoadComplete: TSoundLoadedEvent read fOnPlatformLoadComplete write fOnPlatformLoadComplete;

4 - Реализовать прослушиватель JSoundPool и подключить обратный вызов от прослушивателя к нашему AudioManager:

constructor TAudioManger.Create;
begin
  ...
  //create our listener
  fmyAudioLoadedListener := TMyAudioLoadedListener.Create;

  // set the listener callback 
  fmyAudioLoadedListener.OnLoadCompleted := DoOnLoadComplete;

  // inform JSoundPool that we have a listener
  fSoundPool.setOnLoadCompleteListener( fmyAudioLoadedListener ); 
  ...

И

procedure TAudioManager.DoOnLoadComplete(Sender: TObject; sampleId: Integer; status: Integer);
begin
  if Succeeded(status) then  //remove this if you want all notifications
  begin
    if Assigned(Self.fOnPlatformLoadComplete) then
      fOnPlatformLoadComplete( self, sampleID, status );
  end;
end;

5 - Последнее, что нужно сделать для обратного вызова в основном приложении

TMainForm = class(TForm)
  ...
  fAudioMgr   :  TAudioManager;
  ...
  procedure OnSoundLoaded(Sender: TObject; ASoundID: integer; AStatus: integer);

Затем при создании AudioManager назначьте новый TSoundLoadedEvent локальной процедуре, которую я вызвал OnSoundLoaded.

TMainForm.FormCreate(Sender: TObject);
...
begin
  ...
  fAudioMgr := TAudioManager.Create;
  fAudioMgr.OnSoundLoaded := OnSoundLoaded;

Теперь, когда аудиофайл готов к воспроизведению, вы должны получить уведомление.

procedure TMainForm.OnSoundLoaded(Sender: TObject; ASoundID: integer; AStatus: integer);
begin
  // track IDs when loading sounds to identify which one is ready
  // check status to confirm that the audio was loadded successfully
end;

Это определенно только кусочки, но, надеюсь, может быть полезным.

...