diff options
author | Wolfram Sang <wsa@the-dreams.de> | 2022-03-04 18:37:30 +0100 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2023-02-07 09:19:32 -0500 |
commit | e8135fea5a10dba25fefe991bf6bc36f351e2919 (patch) | |
tree | a17571dc0c1bc25a824f639be88d461245d62e89 /lib/rbcodec/codecs/cRSID/libcRSID.c | |
parent | 1c26f565bf0ae50495dc8d2139f76bd367728cd6 (diff) | |
download | rockbox-e8135fea5a10dba25fefe991bf6bc36f351e2919.tar.gz rockbox-e8135fea5a10dba25fefe991bf6bc36f351e2919.zip |
codec: sid: add cRSID-1.0 for 21st century SID playback
Plain import of the library parts first. Adaptions to Rockbox will
follow. A *lot* of kudos go to Mihaly Horvath for creating this library
from his already lightweight cSID-light, mainly for Rockbox. Besides a
lot of other things, he made his algorithms integer-only and
significantly improved the C64 emulation, so finally RSIDs could be
played as well as PSIDs. TinySID was nice for what it is, but this is a
quantum leap in SID playback quality for Rockbox. Check for example:
https://hvsc.csdb.dk/MUSICIANS/P/Page_Jason/Eighth.sid
https://hvsc.csdb.dk/MUSICIANS/J/Jeff/Blowing.sid
Change-Id: I353e12fbfd7cd8696b834616e55743e7b844a73e
Diffstat (limited to 'lib/rbcodec/codecs/cRSID/libcRSID.c')
-rw-r--r-- | lib/rbcodec/codecs/cRSID/libcRSID.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/cRSID/libcRSID.c b/lib/rbcodec/codecs/cRSID/libcRSID.c new file mode 100644 index 0000000000..f7ef713e12 --- /dev/null +++ b/lib/rbcodec/codecs/cRSID/libcRSID.c | |||
@@ -0,0 +1,134 @@ | |||
1 | // cRSID lightweight (integer-only) RealSID library (with API-calls) by Hermit (Mihaly Horvath), Year 2022 | ||
2 | // License: WTF - do what the fuck you want with the code, but please mention me as the original author | ||
3 | |||
4 | #include <stdlib.h> | ||
5 | //#include <stdint.h> | ||
6 | #ifdef CRSID_PLATFORM_PC | ||
7 | #include <stdio.h> | ||
8 | #endif | ||
9 | |||
10 | #include "libcRSID.h" | ||
11 | |||
12 | #include "C64/C64.c" | ||
13 | #include "host/file.c" | ||
14 | #include "host/audio.c" | ||
15 | |||
16 | |||
17 | cRSID_C64instance* cRSID_init (unsigned short samplerate, unsigned short buflen) { | ||
18 | static cRSID_C64instance* C64 = &cRSID_C64; | ||
19 | |||
20 | C64 = cRSID_createC64 (C64, samplerate); | ||
21 | #ifdef CRSID_PLATFORM_PC | ||
22 | if ( cRSID_initSound (C64, samplerate,buflen) == NULL) return NULL; | ||
23 | #else | ||
24 | if (buflen) return C64; //this is here just to eliminate unused 'buflen' variable warning | ||
25 | #endif | ||
26 | |||
27 | return C64; | ||
28 | } | ||
29 | |||
30 | |||
31 | void cRSID_initSIDtune (cRSID_C64instance* C64, cRSID_SIDheader* SIDheader, char subtune) { //subtune: 1..255 | ||
32 | static const unsigned char PowersOf2[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; | ||
33 | unsigned int InitTimeout=10000000; //allowed instructions, value should be selected to allow for long-running memory-copiers in init-routines (e.g. Synth Sample) | ||
34 | |||
35 | if (subtune==0) subtune = 1; | ||
36 | else if (subtune > SIDheader->SubtuneAmount) subtune = SIDheader->SubtuneAmount; | ||
37 | C64->SubTune = subtune; | ||
38 | |||
39 | cRSID_setC64(C64); cRSID_initC64(C64); //cRSID_writeMemC64(C64,0xD418,0xF); //set C64 hardware and init (reset) it | ||
40 | |||
41 | //determine init-address: | ||
42 | C64->InitAddress = ((SIDheader->InitAddressH)<<8) + (SIDheader->InitAddressL); //get info from BASIC-startupcode for some tunes | ||
43 | if (C64->RAMbank[1] == 0x37) { //are there SIDs with routine under IO area? some PSIDs don't set bank-registers themselves | ||
44 | if ( (0xA000 <= C64->InitAddress && C64->InitAddress < 0xC000) | ||
45 | || (C64->LoadAddress < 0xC000 && C64->EndAddress >= 0xA000) ) C64->RAMbank[1] = 0x36; | ||
46 | else if (C64->InitAddress >= 0xE000 || C64->EndAddress >=0xE000) C64->RAMbank[1] = 0x35; | ||
47 | } | ||
48 | cRSID_initCPU( &C64->CPU, C64->InitAddress ); //prepare init-routine call | ||
49 | C64->CPU.A = subtune - 1; | ||
50 | |||
51 | if (!C64->RealSIDmode) { | ||
52 | //call init-routine: | ||
53 | for (InitTimeout=10000000; InitTimeout>0; InitTimeout--) { if ( cRSID_emulateCPU()>=0xFE ) break; } //give error when timed out? | ||
54 | } | ||
55 | |||
56 | //determine timing-source, if CIA, replace FrameCycles previouisly set to VIC-timing | ||
57 | if (subtune>32) C64->TimerSource = C64->SIDheader->SubtuneTimeSources[0] & 0x80; //subtunes above 32 should use subtune32's timing | ||
58 | else C64->TimerSource = C64->SIDheader->SubtuneTimeSources[(32-subtune)>>3] & PowersOf2[(subtune-1)&7]; | ||
59 | if (C64->TimerSource || C64->IObankWR[0xDC05]!=0x40 || C64->IObankWR[0xDC04]!=0x24) { //CIA1-timing (probably multispeed tune) | ||
60 | C64->FrameCycles = ( ( C64->IObankWR[0xDC04] + (C64->IObankWR[0xDC05]<<8) ) ); //<< 4) / C64->ClockRatio; | ||
61 | C64->TimerSource = 1; //if init-routine changed DC04 or DC05, assume CIA-timing | ||
62 | } | ||
63 | |||
64 | //determine playaddress: | ||
65 | C64->PlayAddress = (SIDheader->PlayAddressH<<8) + SIDheader->PlayAddressL; | ||
66 | if (C64->PlayAddress) { //normal play-address called with JSR | ||
67 | if (C64->RAMbank[1] == 0x37) { //are there SIDs with routine under IO area? | ||
68 | if (0xA000 <= C64->PlayAddress && C64->PlayAddress < 0xC000) C64->RAMbank[1] = 0x36; | ||
69 | } | ||
70 | else if (C64->PlayAddress >= 0xE000) C64->RAMbank[1] = 0x35; //player under KERNAL (e.g. Crystal Kingdom Dizzy) | ||
71 | } | ||
72 | else { //IRQ-playaddress for multispeed-tunes set by init-routine (some tunes turn off KERNAL ROM but doesn't set IRQ-vector!) | ||
73 | C64->PlayAddress = (C64->RAMbank[1] & 3) < 2 ? cRSID_readMemC64(C64,0xFFFE) + (cRSID_readMemC64(C64,0xFFFF)<<8) //for PSID | ||
74 | : cRSID_readMemC64(C64,0x314) + (cRSID_readMemC64(C64,0x315)<<8); | ||
75 | if (C64->PlayAddress==0) { //if 0, still try with RSID-mode fallback | ||
76 | cRSID_initCPU( &C64->CPU, C64->PlayAddress ); //point CPU to play-routine | ||
77 | C64->Finished=1; C64->Returned=1; return; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | if (!C64->RealSIDmode) { //prepare (PSID) play-routine playback: | ||
82 | cRSID_initCPU( &C64->CPU, C64->PlayAddress ); //point CPU to play-routine | ||
83 | C64->FrameCycleCnt=0; C64->Finished=1; C64->SampleCycleCnt=0; //C64->CIAisSet=0; | ||
84 | } | ||
85 | else { C64->Finished=0; C64->Returned=0; } | ||
86 | |||
87 | } | ||
88 | |||
89 | |||
90 | #ifdef CRSID_PLATFORM_PC | ||
91 | |||
92 | |||
93 | char cRSID_playSIDfile(cRSID_C64instance* C64, char* filename, char subtune) { | ||
94 | static cRSID_SIDheader* SIDheader; | ||
95 | |||
96 | SIDheader = cRSID_loadSIDtune(C64,filename); | ||
97 | if (SIDheader==NULL) return CRSID_ERROR_LOAD; | ||
98 | |||
99 | cRSID_initSIDtune (C64 , SIDheader , subtune); | ||
100 | cRSID_playSIDtune (); | ||
101 | |||
102 | return CRSID_STATUS_OK; | ||
103 | } | ||
104 | |||
105 | |||
106 | cRSID_SIDheader* cRSID_loadSIDtune(cRSID_C64instance* C64, char* filename) { | ||
107 | enum SIDspecs { CRSID_FILESIZE_MAX = 100000 }; | ||
108 | int FileSize; | ||
109 | static unsigned char SIDfileData [CRSID_FILESIZE_MAX]; //use memset? | ||
110 | |||
111 | FileSize = cRSID_loadSIDfile( SIDfileData, filename, CRSID_FILESIZE_MAX); | ||
112 | if ( FileSize == CRSID_ERROR_LOAD ) return NULL; | ||
113 | |||
114 | return cRSID_processSIDfile ( C64, SIDfileData, FileSize ); | ||
115 | } | ||
116 | |||
117 | |||
118 | void cRSID_close() { | ||
119 | cRSID_closeSound(); | ||
120 | } | ||
121 | |||
122 | |||
123 | void cRSID_playSIDtune (void) { | ||
124 | cRSID_startSound(); | ||
125 | } | ||
126 | |||
127 | |||
128 | void cRSID_pauseSIDtune (void) { | ||
129 | cRSID_stopSound(); | ||
130 | } | ||
131 | |||
132 | |||
133 | #endif | ||
134 | |||