Recent

Author Topic: Hively Library  (Read 1338 times)

Gigatron

  • Full Member
  • ***
  • Posts: 200
  • Amiga Rulez !!
Hively Library
« on: February 13, 2025, 10:08:28 pm »
I had decided to stop with module player libraries.
But one is missing, notably Hively library which plays the AHX and HVL formats. You absolutely must be able to listen to AHX.Cruisin by PINK/Abyss.
So I compiled the .dll with MSYS2 MINGW64 for X86 64 bit

There are still things missing but the player works for now.
You can download over 1300 ahx modules here : https://ftp.modland.com/pub/modules/AHX/


HivelyTracker, from IRIS & Up Rough!
Credits : http://www.hivelytracker.co.uk/shots.php

Hively Tracker is a tracker program based upon the AHX format created in the mid '90s by Dexter and Pink of Abyss [/]. The format was relatively popular, and many songs were created and used in scene productions and games. AHX was designed to create a very SID-like sound on the Amiga.

HivelyTracker can import and export modules and instruments in the AHX format, but it also improves on AHX in several ways and therefore has its own instrument and module formats.

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, Windows,
  9.   mmsystem, hvl;
  10.  
  11. const
  12.   Channels = 2;
  13.   BitsPerSample = 16;
  14.   SampleRate = 44100; // Nombre d'échantillons par seconde
  15.   BUFFNUM = 8; // Nombre de buffers
  16.   BufferSize = (44100 * 2 * 2) div 100; // Taille d'un buffer en octets
  17.  
  18. type
  19.   { TForm1 }
  20.   TForm1 = class(TForm)
  21.     Memo1: TMemo;
  22.     procedure FormCreate(Sender: TObject);
  23.     procedure FormShow(Sender: TObject);
  24.     procedure Mod_Infos;
  25.   private
  26.     audiobuffer: array[0..BUFFNUM-1] of array[0..BufferSize-1] of SmallInt;
  27.     header: array[0..BUFFNUM-1] of TWaveHdr;
  28.     nextbuf: Integer;
  29.     hWaveOut: HWAVEOUT;
  30.     eventh: THandle;
  31.   public
  32.   end;
  33.  
  34.   { TAudioThread }
  35.   TAudioThread = class(TThread)
  36.   protected
  37.     procedure Execute; override;
  38.   end;
  39.  
  40. var
  41.   Form1: TForm1;
  42.   ok_flag: Boolean;
  43.   hvl_musp: Phvl_tune;
  44.  
  45. implementation
  46.  
  47. {$R *.lfm}
  48.  
  49. { TForm1 }
  50.  
  51. procedure InitBuffers;
  52. var
  53.   i: Integer;
  54. begin
  55.   for i := 0 to BUFFNUM - 1 do
  56.   begin
  57.     ZeroMemory(@Form1.header[i], SizeOf(TWaveHdr));
  58.     Form1.header[i].dwBufferLength := BufferSize * SizeOf(SmallInt);
  59.     Form1.header[i].lpData := @Form1.audiobuffer[i][0];
  60.   end;
  61. end;
  62.  
  63. { TAudioThread - Gestion de la lecture audio en arrière-plan }
  64. procedure TAudioThread.Execute;
  65. var
  66.   i: Integer;
  67. begin
  68.   Form1.nextbuf := 0;
  69.  
  70.   // Envoi initial des buffers
  71.   for i := 0 to BUFFNUM - 1 do
  72.   begin
  73.     hvl_DecodeFrame(hvl_musp, @Form1.audiobuffer[i][0],
  74.       Pointer(PByte(@Form1.audiobuffer[i][0]) + 2), 4);
  75.     waveOutPrepareHeader(Form1.hWaveOut, @Form1.header[i], SizeOf(TWaveHdr));
  76.     waveOutWrite(Form1.hWaveOut, @Form1.header[i], SizeOf(TWaveHdr));
  77.   end;
  78.  
  79.   // Boucle principale
  80.   while ok_flag and not Terminated do
  81.   begin
  82.     while waveOutUnprepareHeader(Form1.hWaveOut, @Form1.header[Form1.nextbuf], SizeOf(TWaveHdr)) = WAVERR_STILLPLAYING do
  83.     begin
  84.       if WaitForSingleObject(Form1.eventh, 100) = WAIT_TIMEOUT then
  85.         Break;
  86.     end;
  87.     ResetEvent(Form1.eventh);
  88.  
  89.     hvl_DecodeFrame(hvl_musp, @Form1.audiobuffer[Form1.nextbuf][0],
  90.       Pointer(PByte(@Form1.audiobuffer[Form1.nextbuf][0]) + 2), 4);
  91.  
  92.     waveOutPrepareHeader(Form1.hWaveOut, @Form1.header[Form1.nextbuf], SizeOf(TWaveHdr));
  93.     waveOutWrite(Form1.hWaveOut, @Form1.header[Form1.nextbuf], SizeOf(TWaveHdr));
  94.  
  95.     Form1.nextbuf := (Form1.nextbuf + 1) mod BUFFNUM;
  96.  
  97.     Sleep(10); // wait a bit !! CPU  overload !!
  98.   end;
  99. end;
  100.  
  101. procedure TForm1.FormCreate(Sender: TObject);
  102. begin
  103.   hvl_InitReplayer;
  104.  
  105.   try
  106.     hvl_musp := hvl_LoadTune('AHX.Cruisin', 44100, 2);
  107.     if hvl_musp = nil then
  108.     begin
  109.       ShowMessage('Erreur : Impossible de charger le fichier AHX/HVL.');
  110.       Exit;
  111.     end;
  112.     ShowMessage('Module File OK ');
  113.     // Display mod_infos !!
  114.     Mod_Infos;
  115.  
  116.   except
  117.     on E: Exception do
  118.     begin
  119.       ShowMessage('Erreur fichier : ' + E.Message);
  120.       Exit;
  121.     end;
  122.   end;
  123. end;
  124.  
  125. procedure TForm1.FormShow(Sender: TObject);
  126. var
  127.   wFormat: TWaveFormatEx;
  128.   AudioThread: TAudioThread;
  129. begin
  130.   eventh := CreateEvent(nil, True, False, 'WriteEvent');
  131.  
  132.   with wFormat do
  133.   begin
  134.     wFormatTag := WAVE_FORMAT_PCM;
  135.     nChannels := Channels;
  136.     nSamplesPerSec := SampleRate;
  137.     wBitsPerSample := BitsPerSample;
  138.     nBlockAlign := (wBitsPerSample * nChannels) div 8;
  139.     nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
  140.     cbSize := 0;
  141.   end;
  142.  
  143.   if waveOutOpen(@hWaveOut, WAVE_MAPPER, @wFormat, eventh, 0, CALLBACK_EVENT) <> MMSYSERR_NOERROR then
  144.   begin
  145.     ShowMessage('Erreur : Perif audio');
  146.     Exit;
  147.   end;
  148.  
  149.   InitBuffers;
  150.   ok_flag := True;
  151.  
  152.   // Run Thread on  Quantum World !!
  153.   AudioThread := TAudioThread.Create(False);
  154.   AudioThread.FreeOnTerminate := True;
  155. end;
  156.  
  157. procedure TForm1.Mod_Infos;
  158. var
  159.   Infos: TStringList;
  160. begin
  161.   if hvl_musp = nil then Exit;
  162.  
  163.   Infos := TStringList.Create;
  164.   try
  165.     Infos.Add('Module HVL/AHX : ' + hvl_musp^.ht_Name);
  166.     Infos.Add('BPM : '            + IntToStr(hvl_musp^.ht_Tempo));
  167.     Infos.Add('Channels : '       + IntToStr(hvl_musp^.ht_Channels));
  168.     Infos.Add('Instruments : '    + IntToStr(hvl_musp^.ht_InstrumentNr));
  169.     Infos.Add('Subsongs : '       + IntToStr(hvl_musp^.ht_SubsongNr));
  170.     Memo1.Lines.Assign(Infos);
  171.   finally
  172.     Infos.Free;
  173.   end;
  174. end;
  175.  
  176. end.
  177.  

hvl Unit
Code: Pascal  [Select][+][-]
  1. unit hvl;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   ctypes;
  9.  
  10. const
  11.   MAX_CHANNELS = 16;
  12.  
  13.   AMIGA_PAL_XTAL      = 28375160;
  14.   AMIGA_NTSC_XTAL     = 28636360;
  15.   AMIGA_CPU_PAL_CLK   = (AMIGA_PAL_XTAL div 4);
  16.   AMIGA_CPU_NTSC_CLK  = (AMIGA_NTSC_XTAL div 4);
  17.   AMIGA_CIA_PAL_CLK   = (AMIGA_CPU_PAL_CLK div 10);
  18.   AMIGA_CIA_NTSC_CLK  = (AMIGA_CPU_NTSC_CLK div 10);
  19.   AMIGA_PAULA_PAL_CLK = (AMIGA_CPU_PAL_CLK div 2);
  20.   AMIGA_PAULA_NTSC_CLK = (AMIGA_CPU_NTSC_CLK div 2);
  21.  
  22. function Period2Freq(period: Double): Double; inline;
  23.  
  24. type
  25.   int8   = ShortInt;
  26.   uint8  = Byte;
  27.   int16  = SmallInt;
  28.   uint16 = Word;
  29.   int32  = LongInt;
  30.   uint32 = Cardinal;
  31.   float64 = Double;
  32.   TEXT = PChar;
  33.  
  34.   hvl_malloc_callback = function(Size: csize_t): Pointer; cdecl;
  35.   hvl_free_callback = procedure(Ptr: Pointer); cdecl;
  36.  
  37.   Phvl_envelope = ^hvl_envelope;
  38.   hvl_envelope = record
  39.     aFrames, aVolume: int16;
  40.     dFrames, dVolume: int16;
  41.     sFrames: int16;
  42.     rFrames, rVolume: int16;
  43.     pad: int16;
  44.   end;
  45.  
  46.   Phvl_plsentry = ^hvl_plsentry;
  47.     hvl_plsentry = record
  48.       ple_Note: uint8;
  49.       ple_Waveform: uint8;
  50.       ple_Fixed: int16;
  51.       ple_FX: array[0..1] of int8;
  52.       ple_FXParam: array[0..1] of int8;
  53.     end;
  54.  
  55.     Phvl_plist = ^hvl_plist;
  56.     hvl_plist = record
  57.       pls_Speed: int16;
  58.       pls_Length: int16;
  59.       pls_Entries: Phvl_plsentry;
  60.     end;
  61.  
  62.     Phvl_instrument = ^hvl_instrument;
  63.     hvl_instrument = record
  64.       ins_Name: array[0..127] of TEXT;
  65.       ins_Volume: uint8;
  66.       ins_WaveLength: uint8;
  67.       ins_FilterLowerLimit: uint8;
  68.       ins_FilterUpperLimit: uint8;
  69.       ins_FilterSpeed: uint8;
  70.       ins_SquareLowerLimit: uint8;
  71.       ins_SquareUpperLimit: uint8;
  72.       ins_SquareSpeed: uint8;
  73.       ins_VibratoDelay: uint8;
  74.       ins_VibratoSpeed: uint8;
  75.       ins_VibratoDepth: uint8;
  76.       ins_HardCutRelease: uint8;
  77.       ins_HardCutReleaseFrames: uint8;
  78.       ins_Envelope: hvl_envelope;
  79.       ins_PList: hvl_plist;
  80.     end;
  81.  
  82.     Phvl_position = ^hvl_position;
  83.     hvl_position = record
  84.       pos_Track: array[0..MAX_CHANNELS-1] of uint8;
  85.       pos_Transpose: array[0..MAX_CHANNELS-1] of int8;
  86.     end;
  87.  
  88.     Phvl_step = ^hvl_step;
  89.     hvl_step = record
  90.       stp_Note: uint8;
  91.       stp_Instrument: uint8;
  92.       stp_FX: uint8;
  93.       stp_FXParam: uint8;
  94.       stp_FXb: uint8;
  95.       stp_FXbParam: uint8;
  96.     end;
  97.  
  98.     Phvl_voice = ^hvl_voice;
  99.     hvl_voice = record
  100.       vc_Track, vc_NextTrack: int16;
  101.       vc_Transpose, vc_NextTranspose, vc_OverrideTranspose: int16;
  102.       vc_ADSRVolume: int32;
  103.       vc_ADSR: hvl_envelope;
  104.       vc_Instrument: Phvl_instrument;
  105.       vc_SamplePos, vc_Delta: uint32;
  106.       vc_InstrPeriod, vc_TrackPeriod, vc_VibratoPeriod, vc_WaveLength: uint16;
  107.       vc_NoteMaxVolume: int16;
  108.       vc_PerfSubVolume: uint16;
  109.       vc_NewWaveform, vc_Waveform, vc_PlantPeriod, vc_VoiceVolume: uint8;
  110.       vc_PlantSquare, vc_IgnoreSquare, vc_FixedNote: uint8;
  111.       vc_VolumeSlideUp, vc_VolumeSlideDown, vc_HardCut: int16;
  112.       vc_HardCutRelease: uint8;
  113.       vc_HardCutReleaseF: int16;
  114.       vc_PeriodSlideOn: uint8;
  115.       vc_PeriodSlideSpeed, vc_PeriodSlidePeriod, vc_PeriodSlideLimit: int16;
  116.       vc_PeriodSlideWithLimit, vc_PeriodPerfSlideSpeed, vc_PeriodPerfSlidePeriod: int16;
  117.       vc_PeriodPerfSlideOn: uint8;
  118.       vc_VibratoDelay, vc_VibratoSpeed, vc_VibratoCurrent, vc_VibratoDepth: int16;
  119.       vc_SquareOn, vc_SquareInit, vc_SquareWait: int16;
  120.       vc_SquareLowerLimit, vc_SquareUpperLimit, vc_SquarePos, vc_SquareSign: int16;
  121.       vc_SquareSlidingIn, vc_SquareReverse: int16;
  122.       vc_FilterOn, vc_FilterInit: uint8;
  123.       vc_FilterWait, vc_FilterSpeed, vc_FilterUpperLimit, vc_FilterLowerLimit: int16;
  124.       vc_FilterPos, vc_FilterSign, vc_FilterSlidingIn, vc_IgnoreFilter: int16;
  125.       vc_PerfCurrent, vc_PerfSpeed, vc_PerfWait: int16;
  126.       vc_PerfList: Phvl_plist;
  127.       vc_AudioPointer, vc_AudioSource: PInt8;
  128.       vc_NoteDelayOn, vc_NoteCutOn: uint8;
  129.       vc_NoteDelayWait, vc_NoteCutWait, vc_AudioPeriod, vc_AudioVolume: int16;
  130.       vc_WNRandom: int32;
  131.       vc_MixSource: PInt8;
  132.       vc_SquareTempBuffer: array[0..$7F] of int8;
  133.       vc_VoiceBuffer: array[0..$282*4-1] of int8;
  134.       vc_VoiceNum, vc_TrackMasterVolume, vc_TrackOn: uint8;
  135.       vc_VoicePeriod: int16;
  136.       vc_Pan, vc_SetPan, vc_PanMultLeft, vc_PanMultRight: uint32;
  137.       vc_RingSamplePos, vc_RingDelta: uint32;
  138.       vc_RingMixSource: PInt8;
  139.       vc_RingPlantPeriod: uint8;
  140.       vc_RingInstrPeriod, vc_RingBasePeriod, vc_RingAudioPeriod: int16;
  141.       vc_RingAudioSource: PInt8;
  142.       vc_RingNewWaveform, vc_RingWaveform, vc_RingFixedPeriod: uint8;
  143.       vc_RingVoiceBuffer: array[0..$282*4-1] of int8;
  144.     end;
  145.  
  146.   Phvl_tune = ^hvl_tune;
  147.   hvl_tune = record
  148.     ht_Name: array[0..127] of Char;  // TEXT ht_Name[128];
  149.     ht_SongNum: UInt16;              // uint16 ht_SongNum;
  150.     ht_Frequency: UInt32;            // uint32 ht_Frequency;
  151.     ht_FreqF: Double;               // float64 ht_FreqF;
  152.     ht_WaveformTab: array[0..MAX_CHANNELS-1] of PInt8;  // const int8 *ht_WaveformTab[MAX_CHANNELS];
  153.     ht_Restart: UInt16;              // uint16 ht_Restart;
  154.     ht_PositionNr: UInt16;           // uint16 ht_PositionNr;
  155.     ht_SpeedMultiplier: UInt8;       // uint8 ht_SpeedMultiplier;
  156.     ht_TrackLength: UInt8;           // uint8 ht_TrackLength;
  157.     ht_TrackNr: UInt8;               // uint8 ht_TrackNr;
  158.     ht_InstrumentNr: UInt8;          // uint8 ht_InstrumentNr;
  159.     ht_SubsongNr: UInt8;             // uint8 ht_SubsongNr;
  160.     ht_PosJump: UInt16;              // uint16 ht_PosJump;
  161.     ht_PlayingTime: UInt32;          // uint32 ht_PlayingTime;
  162.     ht_Tempo: Int16;                 // int16 ht_Tempo;
  163.     ht_PosNr: Int16;                 // int16 ht_PosNr;
  164.     ht_StepWaitFrames: UInt16;       // uint16 ht_StepWaitFrames;
  165.     ht_NoteNr: Int16;                // int16 ht_NoteNr;
  166.     ht_PosJumpNote: UInt16;          // uint16 ht_PosJumpNote;
  167.     ht_GetNewPosition: UInt8;        // uint8 ht_GetNewPosition;
  168.     ht_PatternBreak: UInt8;          // uint8 ht_PatternBreak;
  169.     ht_SongEndReached: UInt8;        // uint8 ht_SongEndReached;
  170.     ht_Stereo: UInt8;                // uint8 ht_Stereo;
  171.     ht_Subsongs: PUInt16;            // uint16 *ht_Subsongs;
  172.     ht_Channels: UInt16;             // uint16 ht_Channels;
  173.     ht_Positions: ^hvl_position;     // struct hvl_position *ht_Positions;
  174.     ht_Tracks: array[0..255, 0..63] of hvl_step;  // struct hvl_step ht_Tracks[256][64];
  175.     ht_Instruments: ^hvl_instrument; // struct hvl_instrument *ht_Instruments;
  176.     ht_Voices: array[0..MAX_CHANNELS-1] of hvl_voice;  // struct hvl_voice ht_Voices[MAX_CHANNELS];
  177.     ht_defstereo: Int32;             // int32 ht_defstereo;
  178.     ht_defpanleft: Int32;            // int32 ht_defpanleft;
  179.     ht_defpanright: Int32;           // int32 ht_defpanright;
  180.     ht_mixgain: Int32;               // int32 ht_mixgain;
  181.     ht_Version: UInt8;               // uint8 ht_Version;
  182.   end;
  183.  
  184.   procedure hvl_DecodeFrame(ht: Pointer; buf1, buf2: PAnsiChar; bufmod: int32); cdecl; external 'hvl.dll';
  185.   procedure hvl_InitReplayer; cdecl; external 'hvl.dll';
  186.   function hvl_InitSubsong(ht: Pointer; nr: uint32): Boolean; cdecl; external 'hvl.dll';
  187.   function hvl_LoadTune(name: PAnsiChar; freq, defstereo: uint32): Phvl_tune; cdecl; external 'hvl.dll';
  188.   function hvl_ParseTune(buf: PByte; buflen, freq, defstereo: uint32): Pointer; cdecl; external 'hvl.dll';
  189.   procedure hvl_FreeTune(ht: Pointer); cdecl; external 'hvl.dll';
  190.  
  191. implementation
  192.  
  193. function Period2Freq(period: Double): Double; inline;
  194. begin
  195.   Result := (AMIGA_PAULA_PAL_CLK * 65536.0) / period;
  196. end;
  197.  
  198. end.
« Last Edit: February 13, 2025, 11:05:53 pm by Gigatron »
Sub Quantum Technology ! Gigatron 68000 Colmar France;

Gigatron

  • Full Member
  • ***
  • Posts: 200
  • Amiga Rulez !!
Re: Hively Library
« Reply #1 on: February 14, 2025, 09:58:07 am »
Hi
The player working with Thread,  now here is normal version, the code is more clear but  like usual , the result is good. I have less than 1% Cpu load !!

** Edit : Added Instruments List

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, Windows,
  9.   mmsystem, hvl;
  10.  
  11. const
  12.   Channels = 2;
  13.   BitsPerSample = 16;
  14.   SampleRate = 44100; // Nombre d'échantillons par seconde
  15.   BufSize =  (44100 * 2 * 2) div 100; // Taille d'un buffer en octets
  16.   BufferCount = 8;
  17.  
  18. type
  19.   { TForm1 }
  20.   TForm1 = class(TForm)
  21.     Memo1: TMemo;
  22.     procedure FormCreate(Sender: TObject);
  23.     procedure FormShow(Sender: TObject);
  24.     procedure Mod_Infos;
  25.   private
  26.     buffers: array[0..BufferCount-1] of array[0..BufSize-1] of SmallInt;
  27.     waveHeaders: array[0..BufferCount-1] of TWaveHdr;
  28.     currentBuffer: Integer;
  29.  
  30.   public
  31.   end;
  32.  
  33. var
  34.   Form1: TForm1;
  35.   waveOut: HWAVEOUT;
  36.   ok_flag: Boolean = false;
  37.   fsize : integer;
  38.   hvl_musp: Phvl_tune;
  39.  
  40. implementation
  41.  
  42. {$R *.lfm}
  43.  
  44. { TForm1 }
  45.  
  46. procedure FillBuff(bufferIndex: Integer);
  47. begin
  48.   if ok_flag then
  49.   begin
  50.  
  51.     bufferIndex := Form1.currentBuffer;
  52.    hvl_DecodeFrame(hvl_musp,@Form1.buffers[bufferIndex][0],
  53.    Pointer(PByte(@Form1.buffers[bufferIndex][0]) + 2), 4);
  54.   end;
  55. end;
  56.  
  57. function WaveOutCallback(hwo: HWAVEOUT; uMsg: UINT; dwInstance, dwParam1, dwParam2: DWORD_PTR): DWORD; stdcall;
  58. begin
  59.   if uMsg = WOM_DONE then
  60.   begin
  61.     if ok_flag then  FillBuff(Form1.currentBuffer);
  62.     waveOutWrite(hwo, @Form1.waveHeaders[Form1.currentBuffer], SizeOf(TWaveHdr));
  63.     Form1.currentBuffer := (Form1.currentBuffer + 1) mod BufferCount;
  64.   end;
  65.   Result := 0;
  66. end;
  67.  
  68. procedure InitAudio;
  69. var
  70.   wFormat: TWaveFormatEx;
  71.   i: Integer;
  72. begin
  73.  
  74.   with wFormat do
  75.   begin
  76.     wFormatTag := WAVE_FORMAT_PCM;
  77.     nChannels := Channels;
  78.     nSamplesPerSec := SampleRate;
  79.     wBitsPerSample := BitsPerSample;
  80.     nBlockAlign := (wBitsPerSample * nChannels) div 8;
  81.     nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
  82.     cbSize := 0;
  83.   end;
  84.  
  85.   if waveOutOpen(@waveOut, WAVE_MAPPER, @wFormat, QWORD(@WaveOutCallback), 0, CALLBACK_FUNCTION) <> MMSYSERR_NOERROR then
  86.     raise Exception.Create('Erreur ouverture periph audio');
  87.  
  88.   // buffers
  89.   for i := 0 to BufferCount - 1 do
  90.   begin
  91.     ZeroMemory(@Form1.waveHeaders[i], SizeOf(TWaveHdr));
  92.      with Form1.waveHeaders[i] do
  93.     begin
  94.       lpData := @Form1.buffers[i][0];
  95.       dwBufferLength := BufSize * SizeOf(SmallInt);
  96.       dwFlags := 0;
  97.     end;
  98.     waveOutPrepareHeader(waveOut, @Form1.waveHeaders[i], SizeOf(TWaveHdr));
  99.   end;
  100.   Form1.currentBuffer := 0;
  101.    for i := 0 to BufferCount - 1 do
  102.       begin
  103.         FillBuff(i);
  104.         waveOutWrite(waveOut, @Form1.waveHeaders[i], SizeOf(TWaveHdr));
  105.       end;
  106.  
  107. end;
  108.  
  109. procedure TForm1.FormCreate(Sender: TObject);
  110. begin
  111.   hvl_InitReplayer;
  112.  
  113.   try
  114.     hvl_musp := hvl_LoadTune('outrun.ahx', 44100, 2);
  115.     if hvl_musp = nil then
  116.     begin
  117.       ShowMessage('Erreur : Impossible de charger le fichier AHX/HVL.');
  118.       Exit;
  119.     end;
  120.  
  121.   except
  122.     on E: Exception do
  123.     begin
  124.       ShowMessage('Erreur fichier : ' + E.Message);
  125.       Exit;
  126.     end;
  127.   end;
  128.     //ShowMessage('Module File OK ');
  129.     // Display mod_infos !!
  130.     Mod_Infos;
  131.  
  132. end;
  133.  
  134. procedure TForm1.FormShow(Sender: TObject);
  135. begin
  136.   InitAudio;
  137.   ok_flag := True;
  138. end;
  139.  
  140. procedure TForm1.Mod_Infos;
  141. var
  142.   Infos: TStringList;
  143.   i : integer;
  144.   aa : Array [0..132] of Pchar;
  145. begin
  146.  
  147.   if hvl_musp = nil then Exit;
  148.  
  149.   Infos := TStringList.Create;
  150.   try
  151.     Infos.Add('Module HVL/AHX : ' + hvl_musp^.ht_Name);
  152.     Infos.Add('BPM : '            + IntToStr(hvl_musp^.ht_Tempo));
  153.     Infos.Add('Channels : '       + IntToStr(hvl_musp^.ht_Channels));
  154.     Infos.Add('Instruments : '    + IntToStr(hvl_musp^.ht_InstrumentNr));
  155.     Infos.Add('Subsongs : '       + IntToStr(hvl_musp^.ht_SubsongNr));
  156.     Infos.Add('');
  157.     Infos.Add('---- Instruments List ---- ');
  158.     Infos.Add('');
  159.     for i := 1 to hvl_musp^.ht_InstrumentNr do
  160.     if hvl_musp^.ht_Instruments[i].ins_Name <> nil then
  161.       Infos.Add(IntToStr(i) + ' : ' + hvl_musp^.ht_Instruments[i].ins_Name);
  162.  
  163.     Memo1.Lines.Assign(Infos);
  164.   finally
  165.     Infos.Free;
  166.   end;
  167. end;
  168.  
  169. end.
  170.  
  171.  

hvl Unit
Code: Pascal  [Select][+][-]
  1. unit hvl;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   ctypes;
  9.  
  10. const
  11.   MAX_CHANNELS = 16;
  12.  
  13.   AMIGA_PAL_XTAL      = 28375160;
  14.   AMIGA_NTSC_XTAL     = 28636360;
  15.   AMIGA_CPU_PAL_CLK   = (AMIGA_PAL_XTAL div 4);
  16.   AMIGA_CPU_NTSC_CLK  = (AMIGA_NTSC_XTAL div 4);
  17.   AMIGA_CIA_PAL_CLK   = (AMIGA_CPU_PAL_CLK div 10);
  18.   AMIGA_CIA_NTSC_CLK  = (AMIGA_CPU_NTSC_CLK div 10);
  19.   AMIGA_PAULA_PAL_CLK = (AMIGA_CPU_PAL_CLK div 2);
  20.   AMIGA_PAULA_NTSC_CLK = (AMIGA_CPU_NTSC_CLK div 2);
  21.  
  22. function Period2Freq(period: Double): Double; inline;
  23.  
  24. type
  25.   int8   = ShortInt;
  26.   uint8  = Byte;
  27.   int16  = SmallInt;
  28.   uint16 = Word;
  29.   int32  = LongInt;
  30.   uint32 = Cardinal;
  31.   float64 = Double;
  32.   TEXT = PChar;
  33.  
  34.   hvl_malloc_callback = function(Size: csize_t): Pointer; cdecl;
  35.   hvl_free_callback = procedure(Ptr: Pointer); cdecl;
  36.  
  37.   Phvl_envelope = ^hvl_envelope;
  38.   hvl_envelope = record
  39.     aFrames, aVolume: int16;
  40.     dFrames, dVolume: int16;
  41.     sFrames: int16;
  42.     rFrames, rVolume: int16;
  43.     pad: int16;
  44.   end;
  45.  
  46.   Phvl_plsentry = ^hvl_plsentry;
  47.     hvl_plsentry = record
  48.       ple_Note: uint8;
  49.       ple_Waveform: uint8;
  50.       ple_Fixed: int16;
  51.       ple_FX: array[0..1] of int8;
  52.       ple_FXParam: array[0..1] of int8;
  53.     end;
  54.  
  55.     Phvl_plist = ^hvl_plist;
  56.     hvl_plist = record
  57.       pls_Speed: int16;
  58.       pls_Length: int16;
  59.       pls_Entries: Phvl_plsentry;
  60.     end;
  61.  
  62.     Phvl_instrument = ^hvl_instrument;
  63.     hvl_instrument = record
  64.       ins_Name: array[0..127] of Char;
  65.       ins_Volume: uint8;
  66.       ins_WaveLength: uint8;
  67.       ins_FilterLowerLimit: uint8;
  68.       ins_FilterUpperLimit: uint8;
  69.       ins_FilterSpeed: uint8;
  70.       ins_SquareLowerLimit: uint8;
  71.       ins_SquareUpperLimit: uint8;
  72.       ins_SquareSpeed: uint8;
  73.       ins_VibratoDelay: uint8;
  74.       ins_VibratoSpeed: uint8;
  75.       ins_VibratoDepth: uint8;
  76.       ins_HardCutRelease: uint8;
  77.       ins_HardCutReleaseFrames: uint8;
  78.       ins_Envelope: hvl_envelope;
  79.       ins_PList: hvl_plist;
  80.     end;
  81.  
  82.     Phvl_position = ^hvl_position;
  83.     hvl_position = record
  84.       pos_Track: array[0..MAX_CHANNELS-1] of uint8;
  85.       pos_Transpose: array[0..MAX_CHANNELS-1] of int8;
  86.     end;
  87.  
  88.     Phvl_step = ^hvl_step;
  89.     hvl_step = record
  90.       stp_Note: uint8;
  91.       stp_Instrument: uint8;
  92.       stp_FX: uint8;
  93.       stp_FXParam: uint8;
  94.       stp_FXb: uint8;
  95.       stp_FXbParam: uint8;
  96.     end;
  97.  
  98.     Phvl_voice = ^hvl_voice;
  99.     hvl_voice = record
  100.       vc_Track, vc_NextTrack: int16;
  101.       vc_Transpose, vc_NextTranspose, vc_OverrideTranspose: int16;
  102.       vc_ADSRVolume: int32;
  103.       vc_ADSR: hvl_envelope;
  104.       vc_Instrument: Phvl_instrument;
  105.       vc_SamplePos, vc_Delta: uint32;
  106.       vc_InstrPeriod, vc_TrackPeriod, vc_VibratoPeriod, vc_WaveLength: uint16;
  107.       vc_NoteMaxVolume: int16;
  108.       vc_PerfSubVolume: uint16;
  109.       vc_NewWaveform, vc_Waveform, vc_PlantPeriod, vc_VoiceVolume: uint8;
  110.       vc_PlantSquare, vc_IgnoreSquare, vc_FixedNote: uint8;
  111.       vc_VolumeSlideUp, vc_VolumeSlideDown, vc_HardCut: int16;
  112.       vc_HardCutRelease: uint8;
  113.       vc_HardCutReleaseF: int16;
  114.       vc_PeriodSlideOn: uint8;
  115.       vc_PeriodSlideSpeed, vc_PeriodSlidePeriod, vc_PeriodSlideLimit: int16;
  116.       vc_PeriodSlideWithLimit, vc_PeriodPerfSlideSpeed, vc_PeriodPerfSlidePeriod: int16;
  117.       vc_PeriodPerfSlideOn: uint8;
  118.       vc_VibratoDelay, vc_VibratoSpeed, vc_VibratoCurrent, vc_VibratoDepth: int16;
  119.       vc_SquareOn, vc_SquareInit, vc_SquareWait: int16;
  120.       vc_SquareLowerLimit, vc_SquareUpperLimit, vc_SquarePos, vc_SquareSign: int16;
  121.       vc_SquareSlidingIn, vc_SquareReverse: int16;
  122.       vc_FilterOn, vc_FilterInit: uint8;
  123.       vc_FilterWait, vc_FilterSpeed, vc_FilterUpperLimit, vc_FilterLowerLimit: int16;
  124.       vc_FilterPos, vc_FilterSign, vc_FilterSlidingIn, vc_IgnoreFilter: int16;
  125.       vc_PerfCurrent, vc_PerfSpeed, vc_PerfWait: int16;
  126.       vc_PerfList: Phvl_plist;
  127.       vc_AudioPointer, vc_AudioSource: PInt8;
  128.       vc_NoteDelayOn, vc_NoteCutOn: uint8;
  129.       vc_NoteDelayWait, vc_NoteCutWait, vc_AudioPeriod, vc_AudioVolume: int16;
  130.       vc_WNRandom: int32;
  131.       vc_MixSource: PInt8;
  132.       vc_SquareTempBuffer: array[0..$7F] of int8;
  133.       vc_VoiceBuffer: array[0..$282*4-1] of int8;
  134.       vc_VoiceNum, vc_TrackMasterVolume, vc_TrackOn: uint8;
  135.       vc_VoicePeriod: int16;
  136.       vc_Pan, vc_SetPan, vc_PanMultLeft, vc_PanMultRight: uint32;
  137.       vc_RingSamplePos, vc_RingDelta: uint32;
  138.       vc_RingMixSource: PInt8;
  139.       vc_RingPlantPeriod: uint8;
  140.       vc_RingInstrPeriod, vc_RingBasePeriod, vc_RingAudioPeriod: int16;
  141.       vc_RingAudioSource: PInt8;
  142.       vc_RingNewWaveform, vc_RingWaveform, vc_RingFixedPeriod: uint8;
  143.       vc_RingVoiceBuffer: array[0..$282*4-1] of int8;
  144.     end;
  145.  
  146.   Phvl_tune = ^hvl_tune;
  147.   hvl_tune = record
  148.     ht_Name: array[0..127] of Char;  // TEXT ht_Name[128];
  149.     ht_SongNum: UInt16;              // uint16 ht_SongNum;
  150.     ht_Frequency: UInt32;            // uint32 ht_Frequency;
  151.     ht_FreqF: Double;               // float64 ht_FreqF;
  152.     ht_WaveformTab: array[0..MAX_CHANNELS-1] of PInt8;  // const int8 *ht_WaveformTab[MAX_CHANNELS];
  153.     ht_Restart: UInt16;              // uint16 ht_Restart;
  154.     ht_PositionNr: UInt16;           // uint16 ht_PositionNr;
  155.     ht_SpeedMultiplier: UInt8;       // uint8 ht_SpeedMultiplier;
  156.     ht_TrackLength: UInt8;           // uint8 ht_TrackLength;
  157.     ht_TrackNr: UInt8;               // uint8 ht_TrackNr;
  158.     ht_InstrumentNr: UInt8;          // uint8 ht_InstrumentNr;
  159.     ht_SubsongNr: UInt8;             // uint8 ht_SubsongNr;
  160.     ht_PosJump: UInt16;              // uint16 ht_PosJump;
  161.     ht_PlayingTime: UInt32;          // uint32 ht_PlayingTime;
  162.     ht_Tempo: Int16;                 // int16 ht_Tempo;
  163.     ht_PosNr: Int16;                 // int16 ht_PosNr;
  164.     ht_StepWaitFrames: UInt16;       // uint16 ht_StepWaitFrames;
  165.     ht_NoteNr: Int16;                // int16 ht_NoteNr;
  166.     ht_PosJumpNote: UInt16;          // uint16 ht_PosJumpNote;
  167.     ht_GetNewPosition: UInt8;        // uint8 ht_GetNewPosition;
  168.     ht_PatternBreak: UInt8;          // uint8 ht_PatternBreak;
  169.     ht_SongEndReached: UInt8;        // uint8 ht_SongEndReached;
  170.     ht_Stereo: UInt8;                // uint8 ht_Stereo;
  171.     ht_Subsongs: PUInt16;            // uint16 *ht_Subsongs;
  172.     ht_Channels: UInt16;             // uint16 ht_Channels;
  173.     ht_Positions: ^hvl_position;     // struct hvl_position *ht_Positions;
  174.     ht_Tracks: array[0..255, 0..63] of hvl_step;  // struct hvl_step ht_Tracks[256][64];
  175.     ht_Instruments: ^hvl_instrument; // struct hvl_instrument *ht_Instruments;
  176.     ht_Voices: array[0..MAX_CHANNELS-1] of hvl_voice;  // struct hvl_voice ht_Voices[MAX_CHANNELS];
  177.     ht_defstereo: Int32;             // int32 ht_defstereo;
  178.     ht_defpanleft: Int32;            // int32 ht_defpanleft;
  179.     ht_defpanright: Int32;           // int32 ht_defpanright;
  180.     ht_mixgain: Int32;               // int32 ht_mixgain;
  181.     ht_Version: UInt8;               // uint8 ht_Version;
  182.   end;
  183.  
  184.   procedure hvl_DecodeFrame(ht: Pointer; buf1, buf2: PAnsiChar; bufmod: int32); cdecl; external 'hvl.dll';
  185.   procedure hvl_InitReplayer; cdecl; external 'hvl.dll';
  186.   function hvl_InitSubsong(ht: Pointer; nr: uint32): Boolean; cdecl; external 'hvl.dll';
  187.   function hvl_LoadTune(name: PAnsiChar; freq, defstereo: uint32): Phvl_tune; cdecl; external 'hvl.dll';
  188.   function hvl_ParseTune(buf: PByte; buflen, freq, defstereo: uint32): Pointer; cdecl; external 'hvl.dll';
  189.   procedure hvl_FreeTune(ht: Pointer); cdecl; external 'hvl.dll';
  190.  
  191. implementation
  192.  
  193. function Period2Freq(period: Double): Double; inline;
  194. begin
  195.   Result := (AMIGA_PAULA_PAL_CLK * 65536.0) / period;
  196. end;
  197.  
  198. end.
« Last Edit: February 14, 2025, 01:22:33 pm by Gigatron »
Sub Quantum Technology ! Gigatron 68000 Colmar France;

Gigatron

  • Full Member
  • ***
  • Posts: 200
  • Amiga Rulez !!
Re: Hively Library
« Reply #2 on: February 14, 2025, 03:27:34 pm »
Hi,

This library is now finished , you can download project and songs on attached file. (.dll is not changed)
Sure i forgot some stuff but you can do the rest ;

Have Fun

Gigatron
Sub Quantum Technology ! Gigatron 68000 Colmar France;

Guva

  • Full Member
  • ***
  • Posts: 142
  • 🌈 ZX-Spectrum !!!
Re: Hively Library
« Reply #3 on: February 16, 2025, 04:46:52 am »
Hi @Gigatron

Code: Pascal  [Select][+][-]
  1. procedure hvl_DecodeFrame(ht: Pointer; buf1, buf2: PAnsiChar; bufmod: int32); cdecl; external 'hvl.dll';
Why PAnsiChar?

Code: C  [Select][+][-]
  1. void hvl_DecodeFrame( struct hvl_tune *ht, int8 *buf1, int8 *buf2, int32 bufmod );
It looks like it should be an 8-bit signed integer.

Code: Pascal  [Select][+][-]
  1. hvl_DecodeFrame: procedure(ht: Pointer; buf1, buf2: Pint8; bufmod: int32); cdecl;

Guva

  • Full Member
  • ***
  • Posts: 142
  • 🌈 ZX-Spectrum !!!
Re: Hively Library
« Reply #4 on: February 16, 2025, 04:59:34 am »
the version with the modified script has removed the dependency on libsdl
for build:
./autogen.sh && ./configure && make && ls .libs

Gigatron

  • Full Member
  • ***
  • Posts: 200
  • Amiga Rulez !!
Re: Hively Library
« Reply #5 on: February 16, 2025, 12:21:08 pm »
Hi @Gigatron

Code: Pascal  [Select][+][-]
  1. procedure hvl_DecodeFrame(ht: Pointer; buf1, buf2: PAnsiChar; bufmod: int32); cdecl; external 'hvl.dll';
Why PAnsiChar?

Code: C  [Select][+][-]
  1. void hvl_DecodeFrame( struct hvl_tune *ht, int8 *buf1, int8 *buf2, int32 bufmod );
It looks like it should be an 8-bit signed integer.

Code: Pascal  [Select][+][-]
  1. hvl_DecodeFrame: procedure(ht: Pointer; buf1, buf2: Pint8; bufmod: int32); cdecl;

Hi @Guva

It's a Pointer but why it's an Ansi  Char Pointer ?
As it works for me I didn't pay attention during the first tests by loading the module into a buffer sure.

Regards
« Last Edit: February 16, 2025, 12:24:01 pm by Gigatron »
Sub Quantum Technology ! Gigatron 68000 Colmar France;

Guva

  • Full Member
  • ***
  • Posts: 142
  • 🌈 ZX-Spectrum !!!
Re: Hively Library
« Reply #6 on: February 16, 2025, 05:46:43 pm »
Well, the library itself is working. I get track information. 
But I have not been able to achieve any sound using raylib.

Code: Pascal  [Select][+][-]
  1. procedure FillAudio(bufferData: Pointer; frames: LongWord); cdecl;
  2. var samples: Pint16;
  3.     left, right: Pint8;
  4.     frame: integer;
  5. begin
  6.   samples:= Pint16(bufferData);
  7.   frames := frames div 2;
  8.   for frame := 0 to frames -1 do
  9.   begin
  10.     left := @samples[frame * 2];
  11.     right := @samples[frame * 2 + 1];
  12.     hvl_DecodeFrame(hvl_musp, PInt8(left), PInt8(right), 2);
  13.   end;
  14. end;  
  15.  

Anyway, I still couldn't figure out how to play the audio.

Gigatron

  • Full Member
  • ***
  • Posts: 200
  • Amiga Rulez !!
Re: Hively Library
« Reply #7 on: February 16, 2025, 07:17:00 pm »
Well, the library itself is working. I get track information. 
But I have not been able to achieve any sound using raylib.

Code: Pascal  [Select][+][-]
  1. procedure FillAudio(bufferData: Pointer; frames: LongWord); cdecl;
  2. var samples: Pint16;
  3.     left, right: Pint8;
  4.     frame: integer;
  5. begin
  6.   samples:= Pint16(bufferData);
  7.   frames := frames div 2;
  8.   for frame := 0 to frames -1 do
  9.   begin
  10.     left := @samples[frame * 2];
  11.     right := @samples[frame * 2 + 1];
  12.     hvl_DecodeFrame(hvl_musp, PInt8(left), PInt8(right), 2);
  13.   end;
  14. end;  
  15.  

Anyway, I still couldn't figure out how to play the audio.

Ok here is the fillbuffer :

Code: Pascal  [Select][+][-]
  1. procedure FillBuff(bufferIndex: Integer);
  2. begin
  3.   if ok_flag then
  4.   begin
  5.  
  6.     bufferIndex := Form1.currentBuffer;
  7.    hvl_DecodeFrame(hvl_musp,@Form1.buffers[bufferIndex][0],
  8.    Pointer(PByte(@Form1.buffers[bufferIndex][0]) + 2), 4);
  9.   end;
  10. end;

This buffer is attached to audio call back , when the module is loaded and initAudio is done  and we can decodeframe and the mmsystem start to playing pcm_data filled on @Form1.buffers[bufferIndex][0]  + @Form1.buffers[bufferIndex][0] +2 . No play option on the the .dll .

I like challenge , send the project please ...
« Last Edit: February 16, 2025, 07:23:46 pm by Gigatron »
Sub Quantum Technology ! Gigatron 68000 Colmar France;

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: Hively Library
« Reply #8 on: February 16, 2025, 09:00:34 pm »
Anyway, I still couldn't figure out how to play the audio.
The buffer for hvl works a bit different than usual. It is a single buffer but the separate (stereo) channels are decoded interleaved. The bufmod parameter is actually the modulo of the samples (which for stereo mode should be 4).

The size if the buffer is equivalent to the frame-length (or a multiple thereof) which for stereo can be calculated with:   framelen = freq * 2 * channels div 50; // f.e. 3528 bytes for 44100 and 2 channels, 50 is refresh-rate in hertz.

BTW: thank you very much for the make-voodoo 👍
« Last Edit: February 16, 2025, 09:12:59 pm by TRon »
Today is tomorrow's yesterday.

Guva

  • Full Member
  • ***
  • Posts: 142
  • 🌈 ZX-Spectrum !!!
Re: Hively Library
« Reply #9 on: February 17, 2025, 02:49:04 am »
Quote
BTW: thank you very much for the make-voodoo 👍

 :D :D :D I was ready to call the devil.

Here's an official example with his magic. But it just stumped me even more.

Code: C  [Select][+][-]
  1. #include <stdio.h>
  2. #include <strings.h>
  3. #include <stdlib.h>
  4. #include <math.h>
  5.  
  6. #include <assert.h>
  7. #include <SDL/SDL.h>
  8.  
  9. #include <hvl/hvl_replay.h>
  10.  
  11. #define FREQ 48000
  12. #define HIVELY_LEN FREQ/50
  13. #define OUTPUT_LEN 4096
  14.  
  15. int16 audiobuffer[2][FREQ / 50];
  16. int16 outputBuffer[FREQ / 25];
  17. struct hvl_tune *tune;
  18. size_t hivelyIndex;
  19. int16 hivelyLeft[HIVELY_LEN], hivelyRight[HIVELY_LEN];
  20.  
  21. void mix_and_play( struct hvl_tune *ht, uint8 *stream, int length );
  22.  
  23. BOOL init( void )
  24. {
  25.   uint32 i;
  26.   SDL_AudioSpec wanted;
  27.  
  28.   if(SDL_Init(SDL_INIT_AUDIO)< 0) {
  29.     printf("Could not initialize SDL: %s\n", SDL_GetError());
  30.     SDL_Quit();
  31.     return FALSE;
  32.   }
  33.  
  34.   wanted.freq = FREQ;
  35.   wanted.format = AUDIO_S16SYS;
  36.   wanted.channels = 2; /* 1 = mono, 2 = stereo */
  37.   //wanted.samples = FREQ / 50;
  38.   wanted.samples = OUTPUT_LEN; // HIVELY_LEN;
  39.  
  40.   wanted.callback = (void*) mix_and_play;
  41.   wanted.userdata = tune;
  42.  
  43.   if(SDL_OpenAudio(&wanted, NULL) < 0) {
  44.     printf("Failed to open audio device.\n");
  45.     SDL_Quit();
  46.     return FALSE;
  47.   }
  48.  
  49.   return TRUE;
  50. }
  51.  
  52. void mix_and_play( struct hvl_tune *ht, uint8 *stream, int length )
  53. {
  54.   int16 *out;
  55.   //int16 *buf1, *buf2;
  56.   int i;
  57.         size_t streamPos = 0;
  58.         length = length >> 1;
  59.  
  60.   if(tune) {
  61.                 // Mix to 16bit interleaved stereo
  62.                 out = (int16*) stream;
  63.                 // Flush remains of previous frame
  64.                 for(i = hivelyIndex; i < (HIVELY_LEN); i++) {
  65.                         out[streamPos++] = hivelyLeft[i];
  66.                         out[streamPos++] = hivelyRight[i];
  67.                 }
  68.  
  69.                 while(streamPos < length) {
  70.                         hvl_DecodeFrame( tune, (int8 *) hivelyLeft, (int8 *) hivelyRight, 2 );
  71.                         for(i = 0; i < (HIVELY_LEN) && streamPos < length; i++) {
  72.                                 out[streamPos++] = hivelyLeft[i];
  73.                                 out[streamPos++] = hivelyRight[i];
  74.                         }
  75.                 }
  76.                 hivelyIndex = i;
  77.   }
  78. }
  79.  
  80. int main( int argc, char *argv[] )
  81. {
  82.   int i;
  83.         hivelyIndex = HIVELY_LEN;
  84.   if( argc < 2 )
  85.   {
  86.     printf( "Usage: play_hvl <tune>\n" );
  87.     return 0;
  88.   }
  89.  
  90.   if( init() )
  91.   {
  92.     hvl_InitReplayer();
  93.     tune = hvl_LoadTune( argv[1], FREQ, 4 );
  94.     if( tune )
  95.     {
  96.       BOOL done;
  97.       uint32 gotsigs;
  98.  
  99.       hvl_InitSubsong( tune, 0 );
  100.  
  101.       printf( "Songname: %s\nChannels: %i\n", tune->ht_Name, tune->ht_Channels );
  102.       printf( "Instruments:\n" );
  103.       for( i=1; i <= tune->ht_InstrumentNr; i++ )
  104.         printf( "%02ld: %s\n", i, tune->ht_Instruments[i].ins_Name );
  105.      printf( "\n\nHit Enter to quit..\n" );
  106.  
  107.       SDL_PauseAudio(0);
  108.  
  109.       // Uncomment to disable looping:
  110.       /*while(!tune->ht_SongEndReached)
  111.           sleep(1);*/
  112.       getchar();
  113.       SDL_PauseAudio(1);
  114.       hvl_FreeTune( tune );
  115.     }
  116.   }
  117.   SDL_Quit();
  118.   return 0;
  119. }
  120.  

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: Hively Library
« Reply #10 on: February 17, 2025, 08:17:36 pm »
Well, I sort of get it.

The issue with raylib is that the callback 'dictates' how many samples you are required to provide. As Said, hively does not play ball with that. It decodes a 'frame' as being an actual (screen-) frame (hence the 50hz frequency).

It will thus (always) decode the amount of bytes/samples as indicated in my previous post.

I do not know if and how it is possible to force raudio to literally accept that amount of bytes/samples. In case that isn't possible, then you would have to decode the frame (having set amount of samples/bytes) and feed the amount of samples that raudio requires to keep raudio satisfied. The remainder of decoded bytes/samples should then be used in the next iteration of the callback and only make a call to the decodeframe function again when the decoded buffer is actually empty.

In the following snippet I use libao and am able to instruct ao to accept the amount of samples/bytes that match that from the decoding function so that it all works well together:
Code: Pascal  [Select][+][-]
  1.  
  2. const
  3.   framelen = freq * 2 * channels div 50; // framelen = 3528 bytes
  4.  
  5. var
  6.   buffer : packed array[0..pred(framelen)] of byte;  
  7.  
  8. // playloop
  9.   while true do
  10.   begin
  11.     hvl_DecodeFrame(HivelyTune, @buffer[0], @buffer[2], 4);
  12.     ao_play(aodev, @buffer[0], framelen);
  13.   end;
  14.  

I don't know what would be the best approach for raudio but am able to understand why the code you showed requires to do what it does.

PS: it is either that or I do not understand what raudio's  SetAudioStreamBufferSizeDefault actually does because the frames count in the callback keeps returning 512 and 314 (in a continues sequence).
« Last Edit: February 17, 2025, 08:29:52 pm by TRon »
Today is tomorrow's yesterday.

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: Hively Library
« Reply #11 on: March 05, 2025, 10:49:59 pm »
🐧🐧🐧  almost forgot about this  🐧🐧🐧
Today is tomorrow's yesterday.

Guva

  • Full Member
  • ***
  • Posts: 142
  • 🌈 ZX-Spectrum !!!
Re: Hively Library
« Reply #12 on: March 08, 2025, 03:31:06 am »
🐧🐧🐧  almost forgot about this  🐧🐧🐧
@TRon Yes it works with raudio BIG thanks !!!
@Gigatron Thank you for such a march through the world of tracker music. I've never heard this format sound before. I liked it very much.

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: Hively Library
« Reply #13 on: March 08, 2025, 03:07:24 pm »
@TRon Yes it works with raudio BIG thanks !!!
You're welcome  :)

Glad to hear that it works for you. Thank you very much for trying and the feedback.
Today is tomorrow's yesterday.

 

TinyPortal © 2005-2018