Recent

Author Topic: Game Music Emulator  (Read 1151 times)

Gigatron

  • Full Member
  • ***
  • Posts: 154
  • Amiga Rulez !!
Game Music Emulator
« on: September 17, 2024, 01:59:12 am »
Hi nice people,

Today i would like to share usefull stuff: Game Music Emulator from 'BLARGG C++ library' + todo include crédits
I have no time to play gme_file but this is my first attempt at least write .wav file and play.
Later i will share the next improved version ;
Supported formats by this library :

gme_ay_type,
   gme_gbs_type,
   gme_gym_type,
   gme_hes_type,
   gme_kss_type,
   gme_nsf_type,
   gme_nsfe_type,
   gme_sap_type,
   gme_spc_type,
   gme_vgm_type,
   gme_vgz_type;

// test.nsf   file included ; nsf = nintendo system
 

Main unit ;
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs,gme,mmsystem,windows;
  9. const
  10.   FileName = 'test.nsf'; // opens this file (can be any music type)
  11.   SampleRate = 44100; // number of samples per second
  12.   Track = 0; //     (0 = first)
  13.   BufSize = 2048; //   multiple of 2
  14.  
  15. type
  16.   TWaveWriter = class
  17.   private
  18.     FFileStream: TFileStream;
  19.  
  20.     FSampleRate: LongWord;
  21.     FChannels: Word;
  22.     FBytesWritten: LongWord;
  23.   public
  24.     constructor Create(ASampleRate: LongWord; const AFileName: string);
  25.     destructor Destroy; override;
  26.     procedure EnableStereo;
  27.     procedure Write(const Buffer; Count: LongWord);
  28.     procedure Close;
  29.   end;
  30.  
  31. type
  32.  
  33.   { TForm1 }
  34.  
  35.   TForm1 = class(TForm)
  36.     procedure FormCreate(Sender: TObject);
  37.   private
  38.  
  39.   public
  40.    MyFile: AnsiString;
  41.    WavStream : TMemoryStream;
  42.   end;
  43.  
  44. var
  45.   Form1: TForm1;
  46.  
  47.  
  48.   WaveWriter: TWaveWriter;
  49.   Buf: array[0..BufSize-1] of SmallInt;
  50.  
  51. implementation
  52.  
  53. {$R *.lfm}
  54. // console mode to do
  55. procedure HandleError(const Str: PAnsiChar);
  56. begin
  57.   if Str <> nil then
  58.   begin
  59.     WriteLn('Error: ', Str);
  60.     ReadLn;
  61.     Halt(1);
  62.   end;
  63. end;
  64.  
  65. { TWaveWriter }
  66.  
  67. constructor TWaveWriter.Create(ASampleRate: LongWord; const AFileName: string);
  68. var
  69.   Header: array[0..43] of Byte;
  70. begin
  71.   FFileStream := TFileStream.Create(AFileName, fmCreate);
  72.   FSampleRate := ASampleRate;
  73.   FChannels := 2;
  74.   FBytesWritten := 0;
  75.  
  76.   // Write WAVE header
  77.   ZeroMemory(@Header, SizeOf(Header));
  78.   //FillChar(Header, SizeOf(Header), 0);
  79.   Move('RIFF', Header[0], 4);
  80.   Move('WAVEfmt ', Header[8], 8);
  81.   PLongWord(@Header[16])^ := 16;
  82.   PWord(@Header[20])^ := 1;  // PCM
  83.   PWord(@Header[22])^ := FChannels;
  84.   PLongWord(@Header[24])^ := FSampleRate;
  85.   PLongWord(@Header[28])^ := FSampleRate * FChannels * 2;
  86.   PWord(@Header[32])^ := FChannels * 2;
  87.   PWord(@Header[34])^ := 16;
  88.   Move('data', Header[36], 4);
  89.  
  90.   FFileStream.WriteBuffer(Header, SizeOf(Header));
  91. end;
  92.  
  93. destructor TWaveWriter.Destroy;
  94. begin
  95.   Close;
  96.   FFileStream.Free;
  97.   inherited;
  98. end;
  99.  
  100. procedure TWaveWriter.EnableStereo;
  101. begin
  102.   FChannels := 2;
  103. end;
  104.  
  105. procedure TWaveWriter.Write(const Buffer; Count: LongWord);
  106. begin
  107.   FFileStream.WriteBuffer(Buffer, Count * SizeOf(SmallInt));
  108.   Inc(FBytesWritten, Count * SizeOf(SmallInt));
  109. end;
  110.  
  111. procedure TWaveWriter.Close;
  112. var
  113.   FileSize: LongWord;
  114. begin
  115.   FileSize := FFileStream.Size - 8;
  116.   FFileStream.Seek(4, soFromBeginning);
  117.   FFileStream.WriteBuffer(FileSize, 4);
  118.   FFileStream.Seek(40, soFromBeginning);
  119.   FFileStream.WriteBuffer(FBytesWritten, 4);
  120. end;
  121.  
  122. { TForm1 }
  123.  
  124. procedure TForm1.FormCreate(Sender: TObject);
  125. var
  126.    Emu:  PMusic_Emu;
  127. begin
  128.  
  129.   HandleError(gme_open_file(PAnsiChar(FileName), Emu,SampleRate));
  130.  // ShowMessage('Fichier ok');
  131.  
  132.   // Vérifier le démarrage de la piste
  133.   HandleError(gme_start_track(Emu, Track));
  134.  // ShowMessage('Piste ok');
  135.  
  136.   // Ouverture du fichier WAV
  137.   WaveWriter := TWaveWriter.Create(SampleRate, 'out.wav');
  138.   try
  139.      WaveWriter.EnableStereo;
  140.  
  141.     // Enregistrement de 10 secondes
  142.     while gme_tell(Emu) < 10 * 1000 do
  143.     begin
  144.       // Remplir le tampon d'échantillons
  145.       HandleError(gme_play(Emu, BufSize, @Buf[0]));
  146.       WaveWriter.Write(Buf, BufSize);
  147.     end;
  148.  
  149.   finally
  150.     // Nettoyage
  151.     gme_delete(Emu);
  152.     WaveWriter.Free;
  153.   end;
  154.    // lecture du wave genere
  155.     MyFile := Application.Location + 'out.wav';
  156.     WavStream := TMemoryStream.Create;
  157.     WavStream.LoadFromFile(MyFile);
  158.  
  159.     PlaySound(WavStream.Memory, 0, SND_NODEFAULT or SND_ASYNC or SND_MEMORY);
  160.  
  161. end;
  162.  
  163. end.
  164.  


Gme Unit :

Code: Pascal  [Select][+][-]
  1. unit GME;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. const
  8.   GME_VERSION = $000603; // 1 byte major, 1 byte minor, 1 byte patch-level
  9.  
  10. type
  11.   PMusic_Emu = ^TMusic_Emu;
  12.   TMusic_Emu = record
  13.     // to doo
  14.   end;
  15.  
  16.   gme_err_t = PAnsiChar;
  17.  
  18.   Pgme_info_t = ^Tgme_info_t;
  19.   Tgme_info_t = record
  20.     length: Integer;
  21.     intro_length: Integer;
  22.     loop_length: Integer;
  23.     play_length: Integer;
  24.     i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15: Integer;
  25.     system: PAnsiChar;
  26.     game: PAnsiChar;
  27.     song: PAnsiChar;
  28.     author: PAnsiChar;
  29.     copyright: PAnsiChar;
  30.     comment: PAnsiChar;
  31.     dumper: PAnsiChar;
  32.     s7, s8, s9, s10, s11, s12, s13, s14, s15: PAnsiChar;
  33.   end;
  34.  
  35.   Tgme_equalizer_t = record
  36.     treble: Double;
  37.     bass: Double;
  38.     d2, d3, d4, d5, d6, d7, d8, d9: Double;
  39.   end;
  40.  
  41.   gme_type_t = Pointer;
  42.  
  43.   gme_reader_t = function(your_data: Pointer; out_: Pointer; count: Integer): gme_err_t; cdecl;
  44.   gme_user_cleanup_t = procedure(user_data: Pointer); cdecl;
  45.  
  46. const
  47.   gme_info_only = -1;
  48.  
  49. var
  50.   gme_ay_type: gme_type_t; external;
  51.   gme_gbs_type: gme_type_t; external;
  52.   gme_gym_type: gme_type_t; external;
  53.   gme_hes_type: gme_type_t; external;
  54.   gme_kss_type: gme_type_t; external;
  55.   gme_nsf_type: gme_type_t; external;
  56.   gme_nsfe_type: gme_type_t; external;
  57.   gme_sap_type: gme_type_t; external;
  58.   gme_spc_type: gme_type_t; external;
  59.   gme_vgm_type: gme_type_t; external;
  60.   gme_vgz_type: gme_type_t; external;
  61.  
  62. //  gme_wrong_file_type: PAnsiChar;   'gme.dll' name 'gme_';
  63.  
  64.  //function gme_wrong_file_type: PAnsiChar; cdecl; external 'gme.dll' name 'gme_wrong_file_type';
  65.   gme_wrong_file_type: PAnsiChar; external 'gme.dll' name 'gme_wrong_file_type';
  66.  
  67. // Basic operations
  68. function gme_open_file(path: PAnsiChar; out out_: PMusic_Emu; sample_rate: Integer): gme_err_t; cdecl; external 'gme.dll' name 'gme_open_file';
  69. function gme_track_count(const emu: PMusic_Emu): Integer; cdecl; external 'gme.dll' name 'gme_track_count';
  70. function gme_start_track(emu: PMusic_Emu; index: Integer): gme_err_t; cdecl; external 'gme.dll' name 'gme_start_track';
  71. function gme_play(emu: PMusic_Emu; count: Integer; out_: PSmallInt): gme_err_t; cdecl; external 'gme.dll' name 'gme_play';
  72. procedure gme_delete(emu: PMusic_Emu); cdecl; external 'gme.dll' name 'gme_delete';
  73.  
  74. // Track position/length
  75. procedure gme_set_fade(emu: PMusic_Emu; start_msec: Integer); cdecl; external 'gme.dll' name 'gme_set_fade';
  76. procedure gme_set_autoload_playback_limit(emu: PMusic_Emu; do_autoload_limit: Integer); cdecl; external 'gme.dll' name 'gme_set_autoload_playback_limit';
  77. function gme_autoload_playback_limit(const emu: PMusic_Emu): Integer; cdecl; external 'gme.dll' name 'gme_autoload_playback_limi';
  78. function gme_track_ended(const emu: PMusic_Emu): Integer; cdecl; external 'gme.dll' name 'gme_track_ended';
  79. function gme_tell(const emu: PMusic_Emu): Integer; cdecl; external 'gme.dll' name 'gme_tell';
  80. function gme_tell_samples(const emu: PMusic_Emu): Integer; cdecl; external 'gme.dll' name 'gme_tell_samples';
  81. function gme_seek(emu: PMusic_Emu; msec: Integer): gme_err_t; cdecl; external 'gme.dll' name 'gme_seek';
  82. function gme_seek_samples(emu: PMusic_Emu; n: Integer): gme_err_t; cdecl; external 'gme.dll' name 'gme_seek_samples';
  83.  
  84. // Informational
  85. function gme_warning(emu: PMusic_Emu): PAnsiChar; cdecl; external 'gme.dll' name 'gme_warning';
  86. function gme_load_m3u(emu: PMusic_Emu; path: PAnsiChar): gme_err_t; cdecl; external 'gme.dll' name 'gme_load_m3u';
  87. procedure gme_clear_playlist(emu: PMusic_Emu); cdecl; external 'gme.dll' name 'gme_clear_playlist';
  88. function gme_track_info(const emu: PMusic_Emu; out out_: Pgme_info_t; track: Integer): gme_err_t; cdecl; external 'gme.dll' name 'gme_track_info';
  89. procedure gme_free_info(info: Pgme_info_t); cdecl; external 'gme.dll'  name 'gme_free_info';
  90.  
  91. // Advanced playback
  92. procedure gme_set_stereo_depth(emu: PMusic_Emu; depth: Double); cdecl; external 'gme.dll' name 'gme_set_stereo_depth';
  93. procedure gme_ignore_silence(emu: PMusic_Emu; ignore: Integer); cdecl; external 'gme.dll' name 'gme_ignore_silence';
  94. procedure gme_set_tempo(emu: PMusic_Emu; tempo: Double); cdecl; external 'gme.dll' name 'gme_set_tempo';
  95. function gme_voice_count(const emu: PMusic_Emu): Integer; cdecl; external 'gme.dll' name 'gme_voice_count';
  96. function gme_voice_name(const emu: PMusic_Emu; i: Integer): PAnsiChar; cdecl; external 'gme.dll' name 'gme_voice_name';
  97. procedure gme_mute_voice(emu: PMusic_Emu; index: Integer; mute: Integer); cdecl; external 'gme.dll' name 'gme_mute_voice';
  98. procedure gme_mute_voices(emu: PMusic_Emu; muting_mask: Integer); cdecl; external 'gme.dll' name 'gme_mute_voices';
  99. procedure gme_equalizer(const emu: PMusic_Emu; out out_: Tgme_equalizer_t); cdecl; external 'gme.dll' name 'gme_equalizer';
  100. procedure gme_set_equalizer(emu: PMusic_Emu; const eq: Tgme_equalizer_t); cdecl; external 'gme.dll' name 'gme_set_equalizer';
  101. procedure gme_enable_accuracy(emu: PMusic_Emu; enabled: Integer); cdecl; external 'gme.dll' name 'gme_enable_accuracy';
  102.  
  103. // Game music types
  104. function gme_type(const emu: PMusic_Emu): gme_type_t; cdecl; external 'gme.dll' name 'gme_type';
  105. function gme_type_list: gme_type_t; cdecl; external 'gme.dll' name 'gme_type_list';
  106. function gme_type_system(type_: gme_type_t): PAnsiChar; cdecl; external 'gme.dll' name 'gme_type_system';
  107. function gme_type_multitrack(type_: gme_type_t): Integer; cdecl; external 'gme.dll' name 'gme_type_multitrack';
  108. function gme_multi_channel(const emu: PMusic_Emu): Integer; cdecl; external 'gme.dll' name 'gme_multi_channel';
  109.  
  110. // Advanced file loading
  111. function gme_open_data(const data: Pointer; size: LongInt; out out_: PMusic_Emu; sample_rate: Integer): gme_err_t; cdecl; external 'gme.dll' name 'gme_open_data';
  112. function gme_identify_header(const header: Pointer): PAnsiChar; cdecl; external 'gme.dll' name 'gme_identify_header';
  113. function gme_identify_extension(path_or_extension: PAnsiChar): gme_type_t; cdecl; external 'gme.dll' name 'gme_identify_extension';
  114. function gme_type_extension(music_type: gme_type_t): PAnsiChar; cdecl; external 'gme.dll' name 'gme_type_extension';
  115. function gme_identify_file(path: PAnsiChar; out type_out: gme_type_t): gme_err_t; cdecl; external 'gme.dll' name 'gme_identify_file';
  116. function gme_new_emu(type_: gme_type_t; sample_rate: Integer): PMusic_Emu; cdecl; external 'gme.dll' name 'gme_new_emu';
  117. function gme_new_emu_multi_channel(type_: gme_type_t; sample_rate: Integer): PMusic_Emu; cdecl; external 'gme.dll' name 'gme_new_emu_multi_channel';
  118. function gme_load_file(emu: PMusic_Emu; path: PAnsiChar): gme_err_t; cdecl; external 'gme.dll' name 'gme_load_data';
  119. function gme_load_data(emu: PMusic_Emu; const data: Pointer; size: LongInt): gme_err_t; cdecl; external 'gme.dll' name 'gme_load_data';
  120. function gme_load_custom(emu: PMusic_Emu; reader: gme_reader_t; file_size: LongInt; your_data: Pointer): gme_err_t; cdecl; external 'gme.dll' name 'gme_load_custom';
  121. function gme_load_m3u_data(emu: PMusic_Emu; const data: Pointer; size: LongInt): gme_err_t; cdecl; external 'gme.dll' name 'gme_load_m3u_data';
  122.  
  123. // User data
  124. procedure gme_set_user_data(emu: PMusic_Emu; new_user_data: Pointer); cdecl; external 'gme.dll' name 'gme_set_user_data';
  125. function gme_user_data(const emu: PMusic_Emu): Pointer; cdecl;external 'gme.dll' name 'gme_user_data';
  126. procedure gme_set_user_cleanup(emu: PMusic_Emu; func: gme_user_cleanup_t); cdecl; external 'gme.dll' name 'gme_set_user_cleanup';
  127.  
  128. implementation
  129.  
  130. end.

« Last Edit: September 17, 2024, 02:42:41 am by Gigatron »
Sub Quantum Technology ! Gigatron 68000 Colmar France;

Guva

  • Full Member
  • ***
  • Posts: 115
Re: Game Music Emulator
« Reply #1 on: September 17, 2024, 03:56:07 pm »
 I see if gme_ay_type is a zx spectrum?

TRon

  • Hero Member
  • *****
  • Posts: 3623
Re: Game Music Emulator
« Reply #2 on: September 17, 2024, 04:07:28 pm »
@Gigatron:
Thank you for the work. A bit disappointed to see windows (and static headers) only though  :P

fwiw the whole idea behind things like libao, portaudio and friends is to play audio in a platform agnostic manner (and yes that does require to install a library on windows (or place the dll next to your executable).

if you can decode a specific buffersize (as per your example) then it should be possible to play the decoded (wav) buffer live. In the case gme or the used sound-output solution  does not buffer the decoding then you can either do it manually or use something like a thread/timer.

I am still working on the portaudio stuff so I'll have a better look at these gme headers later.
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

Fred vS

  • Hero Member
  • *****
  • Posts: 3410
    • StrumPract is the musicians best friend
Re: Game Music Emulator
« Reply #3 on: September 17, 2024, 05:46:30 pm »
I am still working on the portaudio stuff...
Excellent (and best imho) choice!
There is a fpc portaudio header with dynamic loading here.
« Last Edit: September 17, 2024, 05:48:49 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

TRon

  • Hero Member
  • *****
  • Posts: 3623
Re: Game Music Emulator
« Reply #4 on: September 17, 2024, 06:10:16 pm »
Excellent (and best imho) choice!
I personally dislike portaudio (too much issues in the past).

I find libao much easier to use but that is personal preference.

Quote
There is a fpc portaudio header with dynamic loading here.
Yes, thank you for that fred vS.

Unfortunately there are some issues with those headers (conversion errors, you could compare when I cleaned up and posted mine) and I personally like consistency e.g. types prefixed with T and P (as i did for the other headers).
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

Fred vS

  • Hero Member
  • *****
  • Posts: 3410
    • StrumPract is the musicians best friend
Re: Game Music Emulator
« Reply #5 on: September 17, 2024, 06:50:26 pm »
Excellent (and best imho) choice!
I personally dislike portaudio (too much issues in the past).
I find libao much easier to use but that is personal preference.

Indeed color and taste are personal.
I liked Xiph when it planned opus format project but it seems that their passion is gone.
Last release of libao is 1.2.0 - January 27, 2014. and last commit in trunk is 5 years ago.
Last release of PortAudio is 19.7.0 - April 6, 2021 and last commit in trunk is 2 weeks ago.
Indeed PortAudio is not easy but it has much more custom access to devices than libao.

That said, libao is very good too.



I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Gigatron

  • Full Member
  • ***
  • Posts: 154
  • Amiga Rulez !!
Re: Game Music Emulator
« Reply #6 on: September 17, 2024, 11:02:11 pm »
Hi ,

Thank you for your advices.... ok the first gme library was to record wav audio, this one is playing music like xmplayer.

*** Edit :  If the player is not playing and no error found, increase track number , the first defaut track is 0, some games have 256 tracks or subsong, you must find them... will study this soon !

  the project attached in zip format;
 
main unit for code analysis !

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs,StdCtrls, ExtCtrls,
  9.   gme, mmsystem, windows;
  10.  
  11. const
  12.  
  13.   Channels = 2;
  14.   BitsPerSample = 16;
  15.  
  16.   FileName = 'gof.spc'; // opens this file (can be any music type)
  17.   SampleRate = 44100; // number of samples per second
  18.   Track = 0; //     (0 = first)
  19.   BufSize = 16384 ; //   multiple of 2
  20.   BufferCount = 2;
  21.  
  22. type
  23.  
  24.   { TForm1 }
  25.  
  26.   TForm1 = class(TForm)
  27.     Label1: TLabel;
  28.     Timer1: TTimer;
  29.     procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  30.     procedure FormCreate(Sender: TObject);
  31.     procedure Timer1Timer(Sender: TObject);
  32.   private
  33.      buffers: array[0..BufferCount-1] of array[0..BufSize-1] of SmallInt;
  34.      waveHeaders: array[0..BufferCount-1] of TWaveHdr;
  35.      currentBuffer: Integer;
  36.   public
  37.  
  38.   end;
  39.  
  40. var
  41.   Form1: TForm1;
  42.   waveOut: HWAVEOUT;
  43.   waveHeader: TWaveHdr;
  44.   Emu:  PMusic_Emu;
  45.   info: Pgme_info_t;
  46.   ok_flag : boolean = false;
  47.  
  48. implementation
  49.  
  50. {$R *.lfm}
  51.  
  52. /// audio init et le reste !!
  53. procedure HandleError(const Str: PAnsiChar);
  54. begin
  55.   if Str <> nil then
  56.   begin
  57.     WriteLn('Error: ', Str);
  58.     ReadLn;
  59.     Halt(1);
  60.   end;
  61. end;
  62.  
  63. procedure FillBuffer(bufferIndex: Integer);
  64. begin
  65.   if ok_flag then
  66.   begin
  67.    gme_play(Emu, BufSize, @Form1.buffers[bufferIndex][0]);
  68.    Form1.waveHeaders[bufferIndex].dwFlags := Form1.waveHeaders[bufferIndex].dwFlags and (not WHDR_DONE);
  69.   end;
  70. end;
  71.  
  72. function WaveOutCallback(hwo: HWAVEOUT; uMsg: UINT; dwInstance, dwParam1, dwParam2: DWORD_PTR): DWORD; stdcall;
  73. begin
  74.   if uMsg = WOM_DONE then
  75.   begin
  76.     FillBuffer(Form1.currentBuffer);
  77.     waveOutWrite(hwo, @Form1.waveHeaders[Form1.currentBuffer], SizeOf(TWaveHdr));
  78.     Form1.currentBuffer := (Form1.currentBuffer + 1) mod BufferCount;
  79.   end;
  80.   Result := 0;
  81. end;
  82.  
  83. procedure InitAudio;
  84. var
  85.   wFormat: TWaveFormatEx;
  86.   i: Integer;
  87. begin
  88.  
  89.   SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_LOWEST);
  90.  
  91.   with wFormat do
  92.   begin
  93.     wFormatTag := WAVE_FORMAT_PCM;
  94.     nChannels := Channels;
  95.     nSamplesPerSec := SampleRate;
  96.     wBitsPerSample := BitsPerSample;
  97.     nBlockAlign := (wBitsPerSample * nChannels) div 8;
  98.     nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
  99.     cbSize := 0;
  100.   end;
  101.  
  102.   if waveOutOpen(@waveOut, WAVE_MAPPER, @wFormat, QWORD(@WaveOutCallback), 0, CALLBACK_FUNCTION) <> MMSYSERR_NOERROR then
  103.     raise Exception.Create('Erreur ouverture periph audio');
  104.  
  105.   // buffers
  106.   for i := 0 to BufferCount - 1 do
  107.   begin
  108.     ZeroMemory(@Form1.waveHeaders[i], SizeOf(TWaveHdr));
  109.      with Form1.waveHeaders[i] do
  110.     begin
  111.       lpData := @Form1.buffers[i][0];
  112.       dwBufferLength := BufSize * SizeOf(SmallInt);
  113.       dwFlags := 0;
  114.     end;
  115.     waveOutPrepareHeader(waveOut, @Form1.waveHeaders[i], SizeOf(TWaveHdr));
  116.   end;
  117.   Form1.currentBuffer := 0;
  118. end;
  119.  
  120.  
  121. { TForm1 }
  122.  
  123. procedure TForm1.FormCreate(Sender: TObject);
  124. begin
  125.   InitAudio;
  126.   HandleError(gme_open_file(PAnsiChar(FileName), Emu, SampleRate));
  127.   HandleError(gme_start_track(Emu, Track));   /// **** Edit
  128.   ok_flag := true;
  129.  
  130.   // Remplir et envoyer les deux premiers buffers
  131.   FillBuffer(0);
  132.   FillBuffer(1);
  133.   waveOutWrite(waveOut, @waveHeaders[0], SizeOf(TWaveHdr));
  134.   waveOutWrite(waveOut, @waveHeaders[1], SizeOf(TWaveHdr));
  135.  
  136.   Timer1.Enabled := True;
  137.  
  138.      HandleError( gme_track_info( emu, &info, track ) );
  139.      label1.Caption := label1.Caption +'System : ' + (info^.systeme)+#10 ;
  140.      label1.Caption := label1.Caption + 'Game : ' + (info^.game)+#10;
  141.      label1.Caption := label1.Caption + 'Song : ' + (info^.song)+#10;
  142.      label1.Caption := label1.Caption +'Author : ' + (info^.author)+#10;
  143.      label1.Caption := label1.Caption +'Copyright : ' + (info^.copyright)+#10;
  144.      label1.Caption := label1.Caption +'Comment : ' + (info^.comment)+#10;
  145.      label1.Caption := label1.Caption +'Dumper : ' + (info^.dumper)+#10;
  146.  
  147.  
  148. end;
  149.  
  150. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  151. var
  152.   i: Integer;
  153. begin
  154.   Timer1.Enabled := False;
  155.  
  156.   for i := 0 to BufferCount - 1 do
  157.    waveOutUnprepareHeader(waveOut, @waveHeaders[i], SizeOf(TWaveHdr));
  158.    waveOutClose(waveOut);
  159.   gme_delete(Emu);
  160. end;
  161.  
  162. procedure TForm1.Timer1Timer(Sender: TObject);
  163. begin
  164.    if ok_flag then
  165.   begin
  166.  
  167.     // si fini then end
  168.     if gme_track_ended(Emu) <> 0 then
  169.     begin
  170.       Timer1.Enabled := False;
  171.  
  172.     end;
  173.   end;
  174. end;
  175.  
  176. end.
  177.  


« Last Edit: September 18, 2024, 02:51:10 am by Gigatron »
Sub Quantum Technology ! Gigatron 68000 Colmar France;

Fred vS

  • Hero Member
  • *****
  • Posts: 3410
    • StrumPract is the musicians best friend
Re: Game Music Emulator
« Reply #7 on: September 18, 2024, 12:28:56 am »
Hi ,
  the project attached in zip format;
Excellent!
Many thanks, it works great!   ;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Fred vS

  • Hero Member
  • *****
  • Posts: 3410
    • StrumPract is the musicians best friend
Re: Game Music Emulator
« Reply #8 on: September 18, 2024, 04:15:46 am »
Hello Gigatron.

Here your updated project with Linux target.
For Linux it uses the root alsa lib for audio.
Also gme.pas has dynamic loading.
Once again, many thanks for this great addition.

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

TRon

  • Hero Member
  • *****
  • Posts: 3623
Re: Game Music Emulator
« Reply #9 on: September 18, 2024, 04:24:36 am »
Ah, you just crossed me Fred  :)

my feeble attempt...
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

Guva

  • Full Member
  • ***
  • Posts: 115
Re: Game Music Emulator
« Reply #10 on: September 18, 2024, 05:25:58 am »
« Last Edit: September 19, 2024, 07:33:11 pm by Guva »

Gigatron

  • Full Member
  • ***
  • Posts: 154
  • Amiga Rulez !!
Re: Game Music Emulator
« Reply #11 on: September 18, 2024, 05:32:28 pm »
Ok , i'am very happy if this library is usefull for lazarus FPC users,
so thank you @Tron , @Fred vS and @Guva.

My initial goal was how to  calling external external .dll function from FPC and very inspired from @Guva Raylaz.pas unit (thx alot).

The next goal is Amiga delitracker ? maybe :) I can know export .dll function with visual studio 2019/2022 if got c++ sources just for
my system X64 , (X86 or Linux is not made)  this job is for @Tron or  @Fred vS :)

Regards

Gtr 
« Last Edit: September 18, 2024, 05:34:05 pm by Gigatron »
Sub Quantum Technology ! Gigatron 68000 Colmar France;

TRon

  • Hero Member
  • *****
  • Posts: 3623
Re: Game Music Emulator
« Reply #12 on: September 18, 2024, 06:05:58 pm »
Ok , i'am very happy if this library is usefull for lazarus FPC users,
It is. Most bindings are for that matter.

The unfortunate thing is that those bindings are (or seem) all scattered over the internets which makes them hard to find and also seems to get outdated pretty quick because nobody seems to know and/or use them.

Quote
The next goal is Amiga delitracker ? maybe :) I can know export .dll function with visual studio 2019/2022 if got c++ sources just for
my system X64 , (X86 or Linux is not made)  this job is for @Tron or  @Fred vS :)
Although for windows it is not required because of the delayed loading, please consider creating headers that load the library and its functions dynamically. That works the same for windows as it does for all other platforms and saves us a butt-load of time  :)
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

TRon

  • Hero Member
  • *****
  • Posts: 3623
Re: Game Music Emulator
« Reply #13 on: September 18, 2024, 06:49:15 pm »
The next goal is Amiga delitracker ? maybe :)
I completely overlooked that tiny part of the paragraph  :)

You mean delitracker itself or uade ?

Last time I checked there was not a separated library and static linking was not an options for uade (xmp did allow static linking, at least in the past, but I was not aware there was a library which ofc makes things much easier to handle)

Would be nice if you were able to get somewhere with uade because it is one of the best re-players/emulators around.
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

Gigatron

  • Full Member
  • ***
  • Posts: 154
  • Amiga Rulez !!
Re: Game Music Emulator
« Reply #14 on: September 18, 2024, 06:59:55 pm »
The next goal is Amiga delitracker ? maybe :)
I completely overlooked that tiny part of the paragraph  :)

You mean delitracker itself or uade ?

Last time I checked there was not a separated library and static linking was not an options for uade (xmp did allow static linking, at least in the past, but I was not aware there was a library which ofc makes things much easier to handle)

Would be nice if you were able to get somewhere with uade because it is one of the best re-players/emulators around.

I will look inside uade code, if you know https://support.xmplay.com/ there is a plugin called delix wich play all obscure format from amiga
it use starscream mc68000 emulator (for amiga hardware emulation) https://support.xmplay.com/files_view.php?file_id=499.
Eagle player on amiga and source is now open....
Maybe one day we can see delitracker for lazarus fpc , why not ? :)



Sub Quantum Technology ! Gigatron 68000 Colmar France;

 

TinyPortal © 2005-2018