]> Shamusworld >> Repos - stargem2/blob - src/sound.cpp
Some more fixes to the V6809 core to prevent clock destruction, fixes to
[stargem2] / src / sound.cpp
1 //
2 // Sound Interface v2.0
3 //
4 // by James L. Hammons
5 // (c) 2006 Underground Software
6 //
7 // JLH = James L. Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  06/15/2006  Added changelog ;-)
12 // JLH  06/15/2006  Scrubbed all BYTE, WORD & DWORD references from the code
13 // JLH  02/10/2009  Fixed sound IRQ callback so that CPU samples are taken at
14 //                  cycle exact boundaries
15 //
16 // Notes:
17 //   The sound CPU (6808) runs at 894,750 (3,579,000 / 4) Hz.
18 //   At 44.1 KHz, this works out to 894750 / 44100 = 20.289115646... cycles per sample.
19 //
20
21 // Still need to add volume control...
22
23 #include "sound.h"
24
25 #include "SDL.h"
26 #include "types.h"
27 #include "log.h"
28 #include "v6808.h"
29
30 //using namespace std;
31
32 // Local variables
33
34 SDL_AudioSpec desired;
35 bool soundInitialized = false;
36
37 // Private function prototypes
38
39 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
40
41 //
42 // Initialize the SDL sound system
43 //
44 void SoundInit(void)
45 {
46 //      memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
47
48         desired.freq = 44100;                                                   // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
49         desired.format = AUDIO_U8;                                              // This uses the native endian (for portability)...
50         desired.channels = 1;
51 //      desired.samples = 4096;                                                 // Let's try a 4K buffer (can always go lower)
52         desired.samples = 2048;                                                 // Let's try a 2K buffer (can always go lower)
53         desired.callback = SDLSoundCallback;
54
55         if (SDL_OpenAudio(&desired, NULL) < 0)                  // NULL means SDL guarantees what we want
56         {
57                 WriteLog("Sound: Failed to initialize SDL sound.\n");
58 //              exit(1);
59                 return;
60         }
61
62         SDL_PauseAudio(false);                                                  // Start playback!
63         soundInitialized = true;
64         WriteLog("Sound: Successfully initialized.\n");
65 }
66
67 //
68 // Close down the SDL sound subsystem
69 //
70 void SoundDone(void)
71 {
72         if (soundInitialized)
73         {
74                 SDL_PauseAudio(true);
75                 SDL_CloseAudio();
76                 WriteLog("Sound: Done.\n");
77         }
78 }
79
80 //
81 // Sound card callback handler
82 //
83 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
84 {
85         extern V6808REGS soundCPU;
86 //      extern uint8 * sram;
87         extern uint8 sram[];
88         int cnt = 0;
89
90 #define CYCLE_EXACT_SOUND
91 #ifdef CYCLE_EXACT_SOUND
92         static float overflow = 0.0;
93         static uint32 time = 20;
94 #endif
95
96         while (cnt != length)
97         {
98                 // This is close, but not cycle exact (exact would be 20.289115646...)
99
100 //Need to figure out how to get that fraction to execute... !!! FIX !!! [DONE]
101 /*
102 One way would be to use a fractional accumulator, then subtract 1 every
103 time it overflows. Like so:
104
105 double overflow = 0;
106 uint32 time = 20;
107 while (!done)
108 {
109         Execute6808(&soundCPU, time);
110         overflow += 0.289115646;
111         if (overflow > 1.0)
112         {
113                 overflow -= 1.0;
114                 time = 21;
115         }
116         else
117                 time = 20;
118 }
119 */
120 #ifdef CYCLE_EXACT_SOUND
121                 Execute6808(&soundCPU, time);
122                 soundCPU.clock -= time;
123 #else
124                 Execute6808(&soundCPU, 20);
125                 soundCPU.clock -= 20;
126 #endif
127                 buffer[cnt++] = sram[0x0400];                           // Fill the buffer with the PIA output value
128 #ifdef CYCLE_EXACT_SOUND
129                 overflow += 0.289115646;                                        // Fractional part of CPU cycles...
130
131                 if (overflow > 1.0)
132                 {
133                         overflow -= 1.0;
134                         time = 21;
135                 }
136                 else
137                         time = 20;
138 #endif
139         }
140 }