Recent

Author Topic: AY_FLY Library  (Read 277 times)

Gigatron

  • Full Member
  • ***
  • Posts: 144
  • Amiga Rulez !!
AY_FLY Library
« on: October 04, 2024, 01:07:13 am »
Hi,
Before taking my vacation I would like to share with you a music player:

Ay_Fly from  Copyright (C) 2008 by Deryabin Andrew  andrew@it-optima.ru
This project library is compiled for X64 from me with visual studio 2019, exported some functions of the ayfly.dll;
The result is ok now for listen different music formats; ASC, AY, PSC, PT1,PT2,PT3, SQT, STC, STP, VTX (vortex tracker2 by Sergey
Bulba), and YM from Leonard Oxygene;
aylet player, Vortex, YM, PSC, ASC Sound Master, Pro Tracker 2, Pro Tracker 3, ST Song Compiler, Sound Tracker Pro, Pro Sound Creator, SQ Tracker, Pro Tracker 1

https://bulba.untergrund.net/music_e.htm


I made sure some mistakes but wait a bit :)

So let's share the units and library.dll + 2 musics from Klim and c-Jeff of Phat! + the_project

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,windows,mmsystem,ayfly;
  9.  
  10.  const
  11.   REPLAY_RATE = 44100;
  12.   CHANNELS = 2;
  13.   REPLAY_DEPTH  = 16;
  14.   BuffSize = 65536*2; //   multiple of 2
  15.   BufferCount = 4; // 2
  16.  
  17. type
  18.  
  19.   { TForm1 }
  20.  
  21.   TForm1 = class(TForm)
  22.     Timer1: TTimer;
  23.     procedure FormCreate(Sender: TObject);
  24.   private
  25.      buffers: array[0..BufferCount-1] of array[0..BuffSize-1] of SmallInt;
  26.      waveHeaders: array[0..BufferCount-1] of TWaveHdr;
  27.      currentBuffer: Integer;
  28.   public
  29.  
  30.   end;
  31.  
  32. var
  33.   Form1: TForm1;
  34.  
  35.   waveOut: HWAVEOUT;
  36.   waveHeader: TWaveHdr;
  37.   ok_flag : boolean = true;
  38.   playing: Boolean = true;
  39.   // ayfly
  40.   songInfo: PAYSongInfo;
  41.   songName: PChar;
  42.   FileStream: TFileStream;
  43.  
  44.  
  45. implementation
  46.  
  47. {$R *.lfm}
  48.  
  49. { TForm1 }
  50.  
  51. /// audio init et le reste !!
  52. procedure HandleError(const Str: PAnsiChar);
  53. begin
  54.   if Str <> nil then
  55.   begin
  56.     ShowMessage('Error: Wrong Format ? '+ Str);
  57.     Halt(1);
  58.   end;
  59. end;
  60.  
  61. procedure FillBuffer(bufferIndex: Integer);
  62.  
  63. begin
  64.   if playing then
  65.   begin
  66.     //le buffer avec des données audio
  67.      ay_rendersongbuffer(songInfo, @Form1.buffers[bufferIndex][0], BuffSize * SizeOf(SmallInt) );
  68.      Form1.waveHeaders[bufferIndex].dwFlags := Form1.waveHeaders[bufferIndex].dwFlags and (not WHDR_DONE);
  69.  
  70.   end;
  71. end;
  72.  
  73. function WaveOutCallback(hwo: HWAVEOUT; uMsg: UINT; dwInstance, dwParam1, dwParam2: DWORD_PTR): DWORD; stdcall;
  74. begin
  75.   if uMsg = WOM_DONE then
  76.   begin
  77.     FillBuffer(Form1.currentBuffer);
  78.     waveOutWrite(waveOut, @Form1.waveHeaders[Form1.currentBuffer], SizeOf(TWaveHdr));
  79.     Form1.currentBuffer := (Form1.currentBuffer + 1) mod BufferCount;
  80.   end;
  81.  
  82.   Result := 0;
  83. end;
  84.  
  85. procedure InitAudio;
  86. var
  87.   wFormat: TWaveFormatEx;
  88.   i: Integer;
  89. begin
  90.   SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_LOWEST);
  91.  
  92.   with wFormat do
  93.   begin
  94.  
  95.    wFormatTag := WAVE_FORMAT_PCM; // 1
  96.    nChannels := CHANNELS; // stereo 2
  97.    nSamplesPerSec := REPLAY_RATE; // 44100
  98.    wBitsPerSample := REPLAY_DEPTH; // 16 bits
  99.    nBlockAlign := nChannels * (wBitsPerSample div 8); // Taille echantillon
  100.    nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
  101.    cbSize := 0;
  102.   end;
  103.  
  104.   if waveOutOpen(@waveOut, WAVE_MAPPER, @wFormat, QWORD(@WaveOutCallback), 0, CALLBACK_FUNCTION) <> MMSYSERR_NOERROR then
  105.    ShowMessage('Error: Audio initialization failed');
  106.  
  107.   // buffers
  108.   for i := 0 to BufferCount - 1 do
  109.   begin
  110.     ZeroMemory(@Form1.waveHeaders[i], SizeOf(TWaveHdr));
  111.      with Form1.waveHeaders[i] do
  112.     begin
  113.       lpData := @Form1.buffers[i][0];
  114.       dwBufferLength := BuffSize * SizeOf(SmallInt) ;
  115.       dwFlags := 0 ;
  116.     end;
  117.      waveOutPrepareHeader(waveOut, @Form1.waveHeaders[i], SizeOf(TWaveHdr));
  118.   end;
  119.  
  120.    Form1.currentBuffer := 0;
  121. end;
  122.  
  123. procedure CloseAudio;
  124. begin
  125.   waveOutUnprepareHeader(waveOut, @waveHeader, SizeOf(TWaveHdr));
  126.   waveOutClose(waveOut);
  127. end;
  128.  
  129.  
  130.  
  131. procedure TForm1.FormCreate(Sender: TObject);
  132.  
  133. begin
  134.   InitAudio;
  135.  
  136.    // Init song
  137.    SongInfo := ay_initsong('doubdesh.pt3', 44100,SongInfo);
  138.    ay_rendersongbuffer(songInfo, @Form1.buffers[0][0], BuffSize * SizeOf(SmallInt)  );
  139.   // FillBuffer(0);
  140.     waveOutWrite(waveOut, @waveHeaders[0], SizeOf(TWaveHdr));  // start audio !
  141. end;
  142.  
  143.  
  144. end.
  145.  

Ayfly unit

Code: Pascal  [Select][+][-]
  1. unit ayfly;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   ctypes;
  9.  
  10. const
  11.   ayflydll = 'ayfly.dll';
  12.  
  13. type
  14.  
  15.   AY_CHAR = PChar;
  16.  
  17.  
  18.   ELAPSED_CALLBACK = function(arg: Pointer): Boolean; cdecl;
  19.   STOPPED_CALLBACK = procedure(arg: Pointer); cdecl;
  20.  
  21.   AYSongInfo = record
  22.     Author: AY_CHAR;         // Auteur
  23.     Name: AY_CHAR;           // Nom
  24.     FilePath: AY_CHAR;       // Chemin du fichier de la chanson
  25.     PrgName: AY_CHAR;        // Nom programme
  26.     TrackName: AY_CHAR;      // Nom piste
  27.     CompName: AY_CHAR;       // Nom du compilateur
  28.     NumSongs: culong;        // Nombre de chansons
  29.     CurrentSong: culong;     // Chanson actuelle
  30.     Length: culong;          // Longueur de la chanson
  31.     Loop: culong;            // Position de la boucle
  32.     timeElapsed: culong;     // Temps ecoule
  33.     e_callback: ELAPSED_CALLBACK;  // Callback pour la fin de chanson
  34.     s_callback: STOPPED_CALLBACK;  // Callback pour l'arrêt de chanson
  35.   end;
  36.   PAYSongInfo = ^AYSongInfo;
  37.  
  38.   //   DLL   unifinished functions;
  39.   function ay_initsong(FilePath: AY_CHAR; sr: Cardinal; player: Pointer): PAYSongInfo; cdecl; external ayflydll name 'ay_initsong';
  40.   function ay_initsongindirect(module: PByte; sr: Cardinal; size: Cardinal; player: Pointer): PAYSongInfo; cdecl; external ayflydll name 'ay_initsongindirect';
  41.   function ay_getsonginfo(FilePath: AY_CHAR): PAYSongInfo; cdecl; external ayflydll name 'ay_getsonginfo';
  42.   function ay_getsonginfoindirect(module: PByte; size: Cardinal; sr: Cardinal; player: Pointer): PAYSongInfo; cdecl; external ayflydll name 'ay_getsonginfoindirect';
  43.   function ay_getsongname(info: PAYSongInfo): AY_CHAR; cdecl; external ayflydll name 'ay_getsongname';
  44.   procedure ay_closesong(var info: PAYSongInfo); cdecl; external ayflydll name 'ay_closesong';
  45.   procedure ay_startsong(info: PAYSongInfo); cdecl; external ayflydll name 'ay_startsong';
  46.   function ay_songstarted(info: PAYSongInfo): Boolean; cdecl; external ayflydll name 'ay_songstarted';
  47.   function ay_rendersongbuffer(info: Pointer; buffer: PByte; buffer_length: Cardinal): Cardinal; cdecl; external ayflydll name 'ay_rendersongbuffer';
  48.  
  49.  
  50. implementation
  51.  
  52. end.
  53.  
  54.  


 
« Last Edit: October 04, 2024, 08:37:16 pm by Gigatron »
Sub Quantum Technology ! Ufo Landing : Ezekiel 1-4;

Gigatron

  • Full Member
  • ***
  • Posts: 144
  • Amiga Rulez !!
Re: AY_FLY Library
« Reply #1 on: October 04, 2024, 07:58:37 pm »
Hi,
Well it seems that there is a problem with the buffer which causes a slight delay when listening to the music, I will look into that when I return. For now I modified the code a little.

Main unit; no change on ayfly.pas :

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
  9.   windows, mmsystem, ayfly;
  10.  
  11.  const
  12.   REPLAY_RATE = 48000;
  13.   CHANNELS = 2;
  14.   REPLAY_DEPTH  = 16;
  15.   BuffSize = 65536*2; //   multiple of 2
  16.   BufferCount = 2;
  17.  
  18. type
  19.  
  20.   { TForm1 }
  21.  
  22.   TForm1 = class(TForm)
  23.     Memo1: TMemo;
  24.     Timer1: TTimer;
  25.     procedure FormCreate(Sender: TObject);
  26.   private
  27.      buffers: array[0..BufferCount-1] of array[0..BuffSize-1] of UInt32;
  28.      waveHeaders: array[0..BufferCount-1] of TWaveHdr;
  29.      currentBuffer: Integer;
  30.   public
  31.  
  32.   end;
  33.  
  34. var
  35.   Form1: TForm1;
  36.   waveOut: HWAVEOUT;
  37.   waveHeader: TWaveHdr;
  38.   playing: Boolean = true;
  39.   // ayfly
  40.   songInfo: PAYSongInfo;
  41.  
  42. implementation
  43.  
  44. {$R *.lfm}
  45.  
  46. { TForm1 }
  47.  
  48. /// audio init et le reste !!
  49. procedure HandleError(const Str: PAnsiChar);
  50. begin
  51.   if Str <> nil then
  52.   begin
  53.     ShowMessage('Error: Wrong Format ? '+ Str);
  54.     Halt(1);
  55.   end;
  56. end;
  57.  
  58. procedure FillBuffer(bufferIndex: Integer);
  59. begin
  60.   if playing then
  61.   begin
  62.     //le buffer avec des données audio
  63.      bufferIndex := Form1.currentBuffer;
  64.      ay_rendersongbuffer(songInfo, @Form1.buffers[bufferIndex][0], BuffSize * SizeOf(UInt32) );
  65.   end;
  66. end;
  67.  
  68. function WaveOutCallback(hwo: HWAVEOUT; uMsg: UINT; dwInstance, dwParam1, dwParam2: DWORD_PTR): DWORD; stdcall;
  69. begin
  70.   if uMsg = WOM_DONE then
  71.   begin
  72.     FillBuffer(Form1.currentBuffer);
  73.     waveOutWrite(waveOut, @Form1.waveHeaders[Form1.currentBuffer], SizeOf(TWaveHdr));
  74.     Form1.currentBuffer := (Form1.currentBuffer + 1) mod BufferCount;
  75.   end;
  76.   Result := 0;
  77. end;
  78.  
  79. procedure InitAudio;
  80. var
  81.   wFormat: TWaveFormatEx;
  82.   i: Integer;
  83. begin
  84.  // SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_LOWEST);  // if needed
  85.  
  86.   with wFormat do
  87.   begin
  88.    wFormatTag := WAVE_FORMAT_PCM; // 1
  89.    nChannels := CHANNELS; // stereo 2
  90.    nSamplesPerSec := REPLAY_RATE; // 48000
  91.    wBitsPerSample := REPLAY_DEPTH; // 16 bits
  92.    nBlockAlign := nChannels * (wBitsPerSample div 8); // Taille echantillon
  93.    nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
  94.    cbSize := 0;
  95.   end;
  96.  
  97.   if waveOutOpen(@waveOut, WAVE_MAPPER, @wFormat, QWORD(@WaveOutCallback), 0, CALLBACK_FUNCTION) <> MMSYSERR_NOERROR then
  98.    ShowMessage('Error: Audio initialization failed');
  99.  
  100.   // buffers
  101.   for i := 0 to BufferCount - 1 do
  102.   begin
  103.     ZeroMemory(@Form1.waveHeaders[i], SizeOf(TWaveHdr));
  104.      with Form1.waveHeaders[i] do
  105.     begin
  106.       lpData := @Form1.buffers[i][0];
  107.       dwBufferLength := BuffSize * SizeOf(UInt32); // ** to-do type ! Unsigned int
  108.       dwFlags := 0 ;
  109.     end;
  110.      waveOutPrepareHeader(waveOut, @Form1.waveHeaders[i], SizeOf(TWaveHdr));
  111.   end;
  112.     Form1.currentBuffer := 0;
  113. end;
  114.  
  115. procedure CloseAudio;
  116. begin
  117.   waveOutUnprepareHeader(waveOut, @waveHeader, SizeOf(TWaveHdr));
  118.   waveOutClose(waveOut);
  119. end;
  120.  
  121. procedure TForm1.FormCreate(Sender: TObject);
  122. begin
  123.    InitAudio;
  124.    // Init song
  125.    SongInfo := ay_initsong('cs.pt3', REPLAY_RATE,SongInfo);
  126.    fillbuffer(0);
  127.    waveOutWrite(waveOut, @waveHeaders[0], SizeOf(TWaveHdr));  // start audio !
  128.    // song infos
  129.    Memo1.Clear;
  130.    Memo1.Lines.Add('Song name : ' + (SongInfo^.Name));
  131.    Memo1.Lines.Add('Song author : ' + (SongInfo^.Author));
  132. end;
  133.  
  134. end.
Sub Quantum Technology ! Ufo Landing : Ezekiel 1-4;

 

TinyPortal © 2005-2018