// 导入需要的单元
uses
  System.IOUtils, System.SysUtils, FMX.Media, FMX.Types, Data.DB, FireDAC.Comp.Client, FireDAC.Stan.Param;

// 定义一个全局变量,表示数据库连接
var
  DBConnection: TFDConnection;

// 定义一个函数,初始化数据库连接
procedure InitDBConnection;
begin
  // 创建一个TFDConnection对象
  DBConnection := TFDConnection.Create(nil);
  // 设置数据库驱动为SQLite
  DBConnection.DriverName := 'SQLite';
  // 设置数据库文件的路径,如果不存在则自动创建
  DBConnection.Params.Values['Database'] := TPath.Combine(TPath.GetDocumentsPath, 'songs.db');
  // 打开数据库连接
  DBConnection.Open;
end;

// 定义一个函数,创建一个表,用于存储歌曲的信息
procedure CreateTable;
var
  SQL: string;
begin
  // 定义一个SQL语句,创建一个名为songs的表,包含三个字段:id(整数,主键),name(字符串),data(二进制)
  SQL := 'create table if not exists songs (id integer primary key, name text, data blob)';
  // 执行SQL语句
  DBConnection.ExecSQL(SQL);
end;

// 定义一个函数,把一首mp3歌曲存入数据库
procedure SaveSongToDB(const FileName: string);
var
  SongStream: TFileStream;
  SongName: string;
  SQL: string;
  Query: TFDQuery;
begin
  // 检查文件是否存在
  if not TFile.Exists(FileName) then
    raise Exception.Create('File not found: ' + FileName);
  // 检查文件是否为mp3格式
  if not SameText(TPath.GetExtension(FileName), '.mp3') then
    raise Exception.Create('File is not mp3: ' + FileName);
  // 获取歌曲的文件名(不含扩展名)
  SongName := TPath.GetFileNameWithoutExtension(FileName);
  // 创建一个文件流,用于读取歌曲的数据
  SongStream := TFileStream.Create(FileName, fmOpenRead);
  try
    // 定义一个SQL语句,向songs表中插入一条记录,使用参数化查询
    SQL := 'insert into songs (name, data) values (:name, :data)';
    // 创建一个TFDQuery对象,用于执行SQL语句
    Query := TFDQuery.Create(nil);
    try
      // 设置TFDQuery对象的连接为DBConnection
      Query.Connection := DBConnection;
      // 设置TFDQuery对象的SQL语句为SQL
      Query.SQL.Text := SQL;
      // 为SQL语句中的参数赋值,分别为歌曲的文件名和数据
      Query.ParamByName('name').AsString := SongName;
      Query.ParamByName('data').LoadFromStream(SongStream, ftBlob);
      // 执行SQL语句
      Query.ExecSQL;
    finally
      // 释放TFDQuery对象
      Query.Free;
    end;
  finally
    // 释放文件流
    SongStream.Free;
  end;
end;

// 定义一个函数,从数据库中读取一首mp3歌曲,并播放
procedure PlaySongFromDB(const SongName: string);
var
  SQL: string;
  Query: TFDQuery;
  SongStream: TMemoryStream;
  MediaPlayer: TMediaPlayer;
begin
  // 定义一个SQL语句,从songs表中查询一条记录,根据歌曲的文件名,使用参数化查询
  SQL := 'select data from songs where name = :name';
  // 创建一个TFDQuery对象,用于执行SQL语句
  Query := TFDQuery.Create(nil);
  try
    // 设置TFDQuery对象的连接为DBConnection
    Query.Connection := DBConnection;
    // 设置TFDQuery对象的SQL语句为SQL
    Query.SQL.Text := SQL;
    // 为SQL语句中的参数赋值,为歌曲的文件名
    Query.ParamByName('name').AsString := SongName;
    // 执行SQL语句,打开查询结果集
    Query.Open;
    // 检查查询结果集是否为空
    if Query.IsEmpty then
      raise Exception.Create('Song not found: ' + SongName);
    // 创建一个内存流,用于存储歌曲的数据
    SongStream := TMemoryStream.Create;
    try
      // 从查询结果集中的第一条记录的第一个字段(data)中读取歌曲的数据,保存到内存流中
      Query.Fields[0].SaveToStream(SongStream);
      // 将内存流的位置设置为0,以便从头开始读取
      SongStream.Position := 0;
      // 创建一个TMediaPlayer对象,用于播放歌曲
      MediaPlayer := TMediaPlayer.Create(nil);
      try
        // 设置TMediaPlayer对象的文件名为内存流的文件名
        MediaPlayer.FileName := SongStream.FileName;
        // 设置TMediaPlayer对象的媒体类型为音频
        MediaPlayer.MediaType := TMediaType.Audio;
        // 打开TMediaPlayer对象
        MediaPlayer.Open;
        // 播放TMediaPlayer对象
        MediaPlayer.Play;
      finally
        // 释放TMediaPlayer对象
        MediaPlayer.Free;
      end;
    finally
      // 释放内存流
      SongStream.Free;
    end;
  finally
    // 释放TFDQuery对象
    Query.Free;
  end;
end;

// 定义一个函数,关闭数据库连接
procedure CloseDBConnection;
begin
  // 如果数据库连接已经打开,关闭数据库连接
  if DBConnection.Connected then
    DBConnection.Close;
  // 释放数据库连接对象
  DBConnection.Free;
end;

// 定义一个例程,演示如何使用上述函数
procedure Demo;
var
  SongFileName: string;
begin
  // 初始化数据库连接
  InitDBConnection;
  try
    // 创建表
    CreateTable;
    // 设置要存入数据库的歌曲的文件名,这里假设歌曲文件在当前目录下
    SongFileName := TPath.Combine(TPath.GetDocumentsPath, 'song.mp3');
    // 把歌曲存入数据库
    SaveSongToDB(SongFileName);
    // 从数据库中读取歌曲,并播放
    PlaySongFromDB('song');
  finally
    // 关闭数据库连接
    CloseDBConnection;
  end;
end;