Forum > Audio and Video
SC68 Player
TRon:
Thank you for the compliment but all that I did was browsing through the c-sources and reading what the developer(s) wrote :)
Here are some other shortcuts:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- if sc68_init(nil) = 0 then writeln('sc68 initialized') else writeln('ERROR: failed initializing sc68');
and
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- decoder := sc68_create(nil); if assigned(decoder) then writeln('sc68 instance created') else writeln('ERROR: unable to create sc68 instance');
Turns out that there is actually no need to provide any custom parameters (only if you really want/need to).
Standard output seems to be 44100 and signed 16 bit samples. The latter suggest to have support for floats but that isn't actually implemented.
Another observation is that none of my sound-fx modules (v1 and v2) seem to work as the emulator stumbles upon an invalid instruction.
In fact almost none of the Amiga released sc68 files seem to have their decoder backend implemented (as was reported by the original author as Amiga was not a priority)
fwiw the returned sc68_process status is driving me insane :D
Gigatron:
Hi, so this is the latest correction for the sc68 player, added subsong or number of tracks,
If number of tracks>1 then play the second track, hope you can improve this player now;
An html5, js version here : http://gigatron3k.free.fr/html5/Sc68player/
Go to UADE NOW !!! I hope I can do something..
Main unit :
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit Unit1;{$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, sc68, mmsystem, windows ; const Channels = 2; BitsPerSample = 16; SampleRate = 44100; // number of samples per second BufSize = 8192 ; // multiple of 2 BufferCount = 2; type { TForm1 } TForm1 = class(TForm) Label1: TLabel; Memo1: TMemo; Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure Process_SC68(BufferIndex: Integer); procedure CloseAudio; private buffers: array[0..BufferCount-1] of array[0..BufSize-1] of byte; waveHeaders: array[0..BufferCount-1] of TWaveHdr; currentBuffer: Integer; Music_Finished: Boolean; public end; var Form1: TForm1; waveOut: HWAVEOUT; waveHeader: TWaveHdr; fsize : integer; // sc68 sc_init: Tsc68Init; sc_cr: Tsc68Create; sc_inst : Pointer; sc_code : Tsc68Code; sc_minfos : Tsc68MusicInfo ; // music infos sc_cinfos : Tsc68CInfo; sc_disc : Tsc68Disk; sc_play : Tsc68Play; SC68Instance: Psc68; implementation {$R *.lfm} { TForm1 } /// audio init et le reste !!procedure HandleError(const Str: PAnsiChar);begin if Str <> nil then begin ShowMessage('Error: Wrong Format ? '+ Str); Halt(1); end;end; function WaveOutCallback(hwo: HWAVEOUT; uMsg: UINT; dwInstance, dwParam1, dwParam2: DWORD_PTR): DWORD; stdcall;begin if uMsg = WOM_DONE then begin Form1.Process_SC68(Form1.currentBuffer); waveOutWrite(hwo, @Form1.waveHeaders[Form1.currentBuffer], SizeOf(TWaveHdr)); Form1.currentBuffer := (Form1.currentBuffer + 1) mod BufferCount; end; Result := 0;end; procedure InitAudio;var wFormat: TWaveFormatEx; i: Integer;begin SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL); with wFormat do begin wFormatTag := 1; // pcm nChannels := Channels; nSamplesPerSec := SampleRate; wBitsPerSample := BitsPerSample; nBlockAlign := (wBitsPerSample * nChannels) div 8; nAvgBytesPerSec := nSamplesPerSec * nBlockAlign; cbSize := 0; end; if waveOutOpen(@waveOut, WAVE_MAPPER, @wFormat, QWORD(@WaveOutCallback), 0, CALLBACK_FUNCTION) <> MMSYSERR_NOERROR then raise Exception.Create('Erreur ouverture periph audio'); // buffers init for i := 0 to BufferCount - 1 do begin ZeroMemory(@Form1.waveHeaders[i], SizeOf(TWaveHdr)); with Form1.waveHeaders[i] do begin lpData := @Form1.buffers[i][0]; dwBufferLength := BufSize * SizeOf(Byte); dwFlags := 0; end; waveOutPrepareHeader(waveOut, @Form1.waveHeaders[i], SizeOf(TWaveHdr)); waveOutWrite(waveOut, @Form1.waveHeaders[i], SizeOf(TWaveHdr)); end; Form1.currentBuffer := 0; end; procedure TForm1.FormCreate(Sender: TObject);var FileName: string; appname: array[0..8] of Char = 'Lazarus'#0; argv: array[0..0] of PChar;begin // Initialise les paramètres SC68 un cauchemar !!!! FillChar(sc_init, SizeOf(Tsc68Init), 0); argv[0] := appname; sc_init.argc := Length(argv); sc_init.argv := @argv[0]; sc_init.Flags.NoLoadConfig:=false; FileName := 'madness.sc68'; sc_init.sampling_rate := 44100; // Initialisation de SC68 if sc68_init(sc_init) < 0 then begin ShowMessage('Erreur d''initialisation SC68'); Exit; end; // instance SC68 FillChar(sc_cr, SizeOf(sc_cr), 0); sc_cr.SamplingRate := 44100; sc_cr.Name := PChar('Lazarus'#0); SC68Instance := sc68_create(sc_cr); if SC68Instance = nil then begin ShowMessage('Erreur lors de la creation de l''instance SC68'); Exit; end; // Charge le fichier SC68 ; if sc68_load_uri(SC68Instance, pchar(Filename)) = 0 then ShowMessage('file '+ Filename + ' Loaded to sc68 memory') else ShowMessage('ERROR: Unable to Load File into sc68 memory ' ); // get music information first and then get number of track sc68_music_info(SC68Instance,sc_minfos,0,sc_disc); // Force track number if >1 ; set to 2 ; if sc_minfos.Tracks>1 then sc68_play(SC68Instance,2,0) // madness has 3 tracks , no-loop else 1 else sc68_play(SC68Instance,-1,0); // default track end; procedure TForm1.FormShow(Sender: TObject);begin Music_Finished := false; InitAudio; sc68_music_info(SC68Instance,sc_minfos,0,sc_disc); memo1.clear; memo1.Lines.Add( Pchar(sc_minfos.Album)); memo1.Lines.Add( Pchar(sc_minfos.Title)); memo1.Lines.Add( Pchar(sc_minfos.Artist)); memo1.Lines.Add( Pchar(sc_minfos.Format)); memo1.Lines.Add( Pchar(sc_minfos.Genre)); memo1.Lines.Add( Pchar(sc_minfos.Year)); memo1.Lines.Add( Pchar(sc_minfos.Ripper)); memo1.Lines.Add( Pchar(sc_minfos.Converter)); memo1.Lines.Add( Pchar(sc_minfos.LastTag)); memo1.Lines.Add( 'Num Tracks :' + InttoStr(sc_minfos.Tracks)); end; procedure TForm1.Process_SC68(BufferIndex: Integer);var Samples: Integer; resultCode: Tsc68Code; begin if not Music_Finished then begin Samples := BufSize div (Channels * (BitsPerSample div 8)); resultCode := Tsc68Code(sc68_process(SC68Instance, @buffers[BufferIndex][0], @Samples)); // resultCode := Tsc68Code(sc68_process(SC68Instance, @buffers[BufferIndex][0], @Samples) div 4 and Int64(SC68_END)); if (Int64(resultCode) and Int64(SC68_END)) <> 0 then begin Music_Finished := True; ShowMessage('Musique terminée!'); sc68_close(SC68Instance); sc68_destroy(SC68Instance); CloseAudio; Exit; end; end;end; procedure TForm1.CloseAudio;var i: Integer;begin for i := 0 to BufferCount - 1 do begin waveOutUnprepareHeader(waveOut, @waveHeaders[i], SizeOf(TWaveHdr)); end; waveOutClose(waveOut);end; // not need here !!!procedure TForm1.Timer1Timer(Sender: TObject);beginend; end.
sc68 unit :
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit sc68; {$mode objfpc}{$H+} interface uses SysUtils; type Psc68 = ^Tsc68; Tsc68 = record end; Tsc68Disk = Pointer; Tsc68MsgHandler = procedure(cat: Integer; sc68: Psc68; fmt: PChar; args: Pointer); cdecl; Tsc68InitFlags = record NoLoadConfig: Boolean; NoSaveConfig: Boolean; end; { Paramètres d'initialisation de l'API } Tsc68Init = record MsgHandler: Tsc68MsgHandler; DebugClrMask: Integer; DebugSetMask: Integer; Argc: Integer; Argv: PChar; Flags: Tsc68InitFlags; shared_path : PChar; user_path : PChar; lmusic_path: PChar; rmusic_path: PChar; sampling_rate : UInt16; end; init68 = ^Tsc68Init; Tsc68Create = record SamplingRate: Cardinal; Name: PChar; Log2Mem: Integer; Emu68Debug: Integer; Cookie: Pointer; end; Tsc68Tag = record Key: PChar; Value: PChar; end; Tsc68CInfo = record Track: Cardinal; TimeMs: Cardinal; TimeStr: array[0..11] of Char; UsesYM: Boolean; UsesSTE: Boolean; UsesAmiga: Boolean; UsesASID: Boolean; HardwareName: PChar; TagCount: Integer; Tags: ^Tsc68Tag; end; Tsc68MusicInfo = record Tracks: Integer; Track : Integer; Addr: Cardinal; Rate: Cardinal; Replay: PChar; DiskInfo: Tsc68CInfo; TrackInfo: Tsc68CInfo; Album: PChar; Title: PChar; Artist: PChar; Format: PChar; Genre: PChar; Year: PChar; Ripper: PChar; Converter: PChar; LastTag: PChar; end; Psc68MusicInfo = ^Tsc68MusicInfo; Tsc68MInfo = Tsc68MusicInfo; type Tsc68Code = ( SC68_IDLE = 1 shl 0, SC68_CHANGE = 1 shl 1, SC68_LOOP = 1 shl 2, SC68_END = 1 shl 3, SC68_SEEK = 1 shl 4, SC68_OK = 0, SC68_ERROR = -1 ); Tsc68Spr = ( SC68_SPR_QUERY = -1, SC68_SPR_DEFAULT = 0 ); Tsc68Play = ( SC68_DSK_TRACK = 0, SC68_DEF_LOOP = 0, SC68_INF_LOOP = -1, SC68_DEF_TRACK = -1, SC68_CUR_TRACK = -2, SC68_CUR_LOOP = -2 ); Tsc68PCM = ( SC68_PCM_S16 = 1, SC68_PCM_F32 = 2 ); Tsc68ASID = ( SC68_ASID_OFF = 0, SC68_ASID_ON = 1, SC68_ASID_FORCE = 2, SC68_ASID_NO_A = 4, SC68_ASID_NO_B = 8, SC68_ASID_NO_C = 16 ); Tsc68Cntl = ( SC68_NOP = 0, SC68_GET_LAST, SC68_GET_NAME, SC68_GET_TRACKS, SC68_GET_TRACK, SC68_GET_DEFTRK, SC68_GET_LOOPS, SC68_GET_LOOP, SC68_GET_DISK, SC68_GET_SPR, SC68_SET_SPR, SC68_GET_LEN, SC68_GET_TRKLEN, SC68_GET_DSKLEN, SC68_GET_ORG, SC68_GET_TRKORG, SC68_GET_POS, SC68_GET_DSKPOS, SC68_GET_PLAYPOS, SC68_SET_POS, SC68_GET_PCM, SC68_SET_PCM, SC68_CAN_ASID, SC68_GET_ASID, SC68_SET_ASID, SC68_GET_COOKIE, SC68_SET_COOKIE, SC68_EMULATORS, SC68_CONFIG_LOAD, SC68_CONFIG_SAVE, SC68_ENUM_OPT, SC68_GET_OPT, SC68_SET_OPT_STR, SC68_SET_OPT_INT, SC68_DIAL, SC68_CNTL_LAST ); function sc68_version: Integer; cdecl; external 'sc68.dll'; function sc68_versionstr: PChar; cdecl; external 'sc68.dll'; function sc68_init(var init: Tsc68Init): Integer; cdecl; external 'sc68.dll' name 'sc68_init'; procedure sc68_shutdown; cdecl; external 'sc68.dll'; function sc68_create(create: Tsc68Create): Pointer; cdecl; external 'sc68.dll' name 'sc68_create'; procedure sc68_destroy(sc68: Psc68); cdecl; external 'sc68.dll'; function sc68_cntl(sc68: Psc68; op: Integer; args: array of const): Integer; cdecl; external 'sc68.dll'; // function sc68_error: PChar; cdecl; external 'sc68.dll' name 'sc68_error'; function sc68_process(sc68: Psc68; buf: Pointer; n: pointer): integer; cdecl; external 'sc68.dll' name 'sc68_process'; function sc68_play(sc68: Psc68; track, loop: Integer): Integer; cdecl; external 'sc68.dll'; function sc68_stop(sc68: Psc68): Integer; cdecl; external 'sc68.dll'; function sc68_music_info(sc68: Psc68; info: Tsc68MusicInfo; track: Integer; disk: Tsc68Disk): Integer; cdecl; external 'sc68.dll'; function sc68_tag_get(sc68: Psc68; tag: Tsc68Tag; track: Integer; disk: Tsc68Disk): Integer; cdecl; external 'sc68.dll'; function sc68_tag(sc68: Psc68; key: PChar; track: Integer; disk: Tsc68Disk): PChar; cdecl; external 'sc68.dll'; function sc68_tag_enum(sc68: Psc68; tag: Tsc68Tag; track, idx: Integer; disk: Tsc68Disk): Integer; cdecl; external 'sc68.dll'; function sc68_mimetype: PChar; cdecl; external 'sc68.dll'; function sc68_vfs(uri: PChar; mode, argc: Integer; args: array of const): Pointer; cdecl; external 'sc68.dll'; function sc68_is_our_uri(uri, exts: PChar; var is_remote: Integer): Integer; cdecl; external 'sc68.dll'; function sc68_load(sc68: Psc68; is_: Pointer): Integer; cdecl; external 'sc68.dll'; function sc68_load_uri(sc68: Psc68; uri: PChar): Integer; cdecl; external 'sc68.dll'; function sc68_load_mem(sc68: Psc68; buffer: Pointer; len: Integer): Integer; cdecl; external 'sc68.dll'; function sc68_load_disk(is_: Pointer): Tsc68Disk; cdecl; external 'sc68.dll'; function sc68_load_disk_uri(uri: PChar): Tsc68Disk; cdecl; external 'sc68.dll'; function sc68_disk_load_mem(buffer: Pointer; len: Integer): Tsc68Disk; cdecl; external 'sc68.dll'; procedure sc68_disk_free(disk: Tsc68Disk); cdecl; external 'sc68.dll'; function sc68_open(sc68: Psc68; disk: Tsc68Disk): Integer; cdecl; external 'sc68.dll'; procedure sc68_close(sc68: Psc68); cdecl; external 'sc68.dll'; function sc68_ym_channels(sc68: Psc68; channels: Integer): Integer; cdecl; external 'sc68.dll'; implementation end.
Gigatron:
--- Quote from: TRon on November 22, 2024, 07:57:51 pm ---Thank you for the compliment but all that I did was browsing through the c-sources and reading what the developer(s) wrote :)
Another observation is that none of my sound-fx modules (v1 and v2) seem to work as the emulator stumbles upon an invalid instruction.
--- End quote ---
Hi @Tron ;
Some Amiga formats played with sc68 must be converted to .sc68 , some soundfx are converted.
Example on my page ; http://gigatron3k.free.fr/html5/Sc68player/ speed is a little fast than original sc68 player !!
Will now work on UADE maybe one day all Amiga obsucre format can played with FPC :)
Regards
TRon:
Thank you for your work Gigatron, especially the sfx examples 👍
I'm having fun with sc68... it is pretty straightforward to add a custom replayer (as long as you know a little 68k assembler).
I am ashamed to admit that I didn't not really payed much attention to this replayer back in the day but the code and solutions used are pretty lean and clean.
Navigation
[0] Message Index
[*] Previous page