如何从资源中播放wav文件

How to play wav file from the resources

我需要从资源中播放和循环播放 WAV 音轨。

我在这里找到了类似问题的答案:

但是当我将它粘贴到我的代码中时,它是这样说的:

我的资源是这样的(不要介意项目名称):

我粘贴到项目中的代码是:

procedure TForm1.FormShow(Sender: TObject);
begin
  PlaySound(BG, 0, SND_RESOURCE or SND_ASYNC);
end;

整个事情看起来像这样:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Imaging.pngimage, Vcl.ExtCtrls, Unit2, Unit3, Unit4, Unit5,
  Vcl.MPlayer, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    MediaPlayer1: TMediaPlayer;
    Button1: TButton;
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure MediaPlayer1Enter(Sender: TObject);
    procedure MediaPlayer1Notify(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
procedure TForm1.FormShow(Sender: TObject);
begin
  PlaySound(BG, 0, SND_RESOURCE or SND_ASYNC);
end;

也许我需要包含一些库或其他东西?我是 Delphi.

的新手

要在 Delphi 中使用 PlaySound(),您只需将 Winapi.MMSystem 单元添加到 uses 子句中。

但是,由于您的项目中也有一个 TMediaPlayer,您可以使用它来代替 PlaySound(),这会有额外的好处,让您可以更好地控制播放(pausing/resuming、跳过等)。

TMediaPlayer 本机 不支持从资源播放 WAV 音频,但可以通过一些额外的编码来完成。

在内部,TMediaPlayer 使用 MCI via the mciSendCommand() function. According to Microsoft (HOWTO: Use MCI to Play AVI/WAVE Files from Memory),您可以设置 MCI 从内存(例如资源)播放 WAV 音频,方法是安装自定义 IO 回调,然后在打开时指定该回调播放器设备。幸运的是,回调是由文件扩展名触发的,因此这种方法兼容 TMediaPlayer.FileName 属性.

因此,您应该能够编写一个带有自定义文件扩展名的 IO 回调函数(例如,.RES 用于资源),并让该回调加载 WAV 资源并读取其数据,然后您可以将 MediaPlayer1.DeviceType 设置为 dtWaveAudio 并将 MediaPlayer1.FileName 设置为以自定义扩展名结尾的文件名。剩下的由OS为您处理,然后您可以根据需要使用MediaPlayer1控制播放。

例如:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Imaging.pngimage, Vcl.ExtCtrls, Unit2, Unit3, Unit4, Unit5,
  Vcl.MPlayer, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    MediaPlayer1: TMediaPlayer;
    Button1: TButton;
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure MediaPlayer1Enter(Sender: TObject);
    procedure MediaPlayer1Notify(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.MMSystem;
  
{$R *.dfm}

function MAKEFOURCC(ch0, ch1, ch2, ch3: BYTE): FOURCC;
begin
  Result := DWORD(ch0) or (DWORD(ch1) shl 8) or (DWORD(ch2) shl 16) or (DWORD(ch3) shl 24); 
end;

function MyResourceIOProc(lpMMIOInfo: PMMIOInfo; uMessage: UINT; lParam1, lParam2: LPARAM): LRESULT; stdcall;
var
  Res: TResourceStream;

  function GetResourceStream: TResourceStream;
  begin
    Move(lpMMIOInfo.adwInfo, Result, SizeOf(TResourceStream));
  end;

  procedure SetResourceStream(Stream: TResourceStream);
  begin
    Move(Stream, lpMMIOInfo.adwInfo, SizeOf(TResourceStream));
  end;

begin
  case uMessage of
    MMIOM_OPEN: begin
      try
        Res := TResourceStream.Create(ChangeFileExt(PChar(lParam1), ''), 'WAVE');
      except
        SetResourceStream(nil);
        Exit(MMIOM_CANNOTOPEN);
      end;
      SetResourceStream(Res);
      lpMMIOInfo.lDiskOffset := 0;
      Exit(MMSYSERR_NOERROR);
    end;   
    MMIOM_CLOSE: begin
      Res := GetResourceStream;
      SetResourceStream(nil);
      Res.Free;
      Exit(MMSYSERR_NOERROR);
    end;   
    MMIOM_READ: begin
      Res := GetResourceStream;
      Move((PByte(Res.Memory) + lpMMIOInfo.lDiskOffset)^, Pointer(lParam1)^, lParam2);
      Inc(lpMMIOInfo.lDiskOffset, lParam2);
      Exit(lParam2);
    end;
    MMIOM_SEEK: begin
      case lParam2 of
        SEEK_SET: begin
          lpMMIOInfo.lDiskOffset := lParam1;
        end;
        SEEK_CUR: begin
          Inc(lpMMIOInfo.lDiskOffset, lParam1);
        end;
        SEEK_END: begin
          Res := GetResourceStream;
          lpMMIOInfo.lDiskOffset := Res.Size - 1 - lParam1;
        end;
      end;
      Exit(lpMMIOInfo.lDiskOffset);
    end;
  else
    Exit(MMSYSERR_NOERROR);
  end;
end;

const
  ccRES: FOURCC = MAKEFOURCC(Ord('R'), Ord('E'), Ord('S'), Ord(' '));

procedure TForm1.FormCreate(Sender: TObject);
begin
  mmioInstallIOProc(ccRES, TFNMMIOProc(MyResourceIOProc), MMIO_INSTALLPROC or MMIO_GLOBALPROC); 
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  mmioInstallIOProc(ccRES, nil, MMIO_REMOVEPROC);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  MediaPlayer1.FileName := 'BG.RES+';
  MediaPlayer1.Open;
  MediaPlayer1.Play;
end;