]> Shamusworld >> Repos - stargem2/blob - src/sound.cpp
2f7522047072082c2b3c32fba6a6e04be0f340d4
[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 #include "timing.h"
30
31 //using namespace std;
32
33 #define AUDIO_SAMPLE_RATE       44100
34
35 // Local variables
36
37 SDL_AudioSpec desired;
38 bool soundInitialized = false;
39
40 // Private function prototypes
41
42 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
43
44 //
45 // Initialize the SDL sound system
46 //
47 void SoundInit(void)
48 {
49 //      memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
50
51         desired.freq = AUDIO_SAMPLE_RATE;                               // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
52         desired.format = AUDIO_U8;                                              // This uses the native endian (for portability)...
53         desired.channels = 1;
54 //      desired.samples = 4096;                                                 // Let's try a 4K buffer (can always go lower)
55         desired.samples = 2048;                                                 // Let's try a 2K buffer (can always go lower)
56         desired.callback = SDLSoundCallback;
57
58         if (SDL_OpenAudio(&desired, NULL) < 0)                  // NULL means SDL guarantees what we want
59         {
60                 WriteLog("Sound: Failed to initialize SDL sound.\n");
61 //              exit(1);
62                 return;
63         }
64
65         SDL_PauseAudio(false);                                                  // Start playback!
66         soundInitialized = true;
67         WriteLog("Sound: Successfully initialized.\n");
68 }
69
70 //
71 // Close down the SDL sound subsystem
72 //
73 void SoundDone(void)
74 {
75         if (soundInitialized)
76         {
77                 SDL_PauseAudio(true);
78                 SDL_CloseAudio();
79                 WriteLog("Sound: Done.\n");
80         }
81 }
82
83 /*
84 The way to determine the # of cycles for each sample is to take the CPU clock frequency
85 and divide by the sample rate.
86
87 Like so:
88 double cycles = M6808_CLOCK_SPEED_IN_HZ / AUDIO_SAMPLE_RATE;
89 Then we need to separate out the fractional part from the integer part.
90 */
91
92 //
93 // Sound card callback handler
94 //
95 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
96 {
97         extern V6808REGS soundCPU;
98         extern uint8 sram[];
99         int cnt = 0;
100
101 #define CYCLE_EXACT_SOUND
102 #ifdef CYCLE_EXACT_SOUND
103         static float overflow = 0.0;
104         static uint32 time = 20;
105 #endif
106
107         while (cnt != length)
108         {
109                 // This is close, but not cycle exact (exact would be 20.289115646...)
110
111 //Need to figure out how to get that fraction to execute... !!! FIX !!! [DONE]
112 /*
113 One way would be to use a fractional accumulator, then subtract 1 every
114 time it overflows. Like so:
115
116 double overflow = 0;
117 uint32 time = 20;
118 while (!done)
119 {
120         Execute6808(&soundCPU, time);
121         overflow += 0.289115646;
122         if (overflow > 1.0)
123         {
124                 overflow -= 1.0;
125                 time = 21;
126         }
127         else
128                 time = 20;
129 }
130 */
131 #ifdef CYCLE_EXACT_SOUND
132                 Execute6808(&soundCPU, time);
133                 soundCPU.clock -= time;
134 #else
135                 Execute6808(&soundCPU, 20);
136                 soundCPU.clock -= 20;
137 #endif
138                 buffer[cnt++] = sram[0x0400];                           // Fill the buffer with the PIA output value
139 #ifdef CYCLE_EXACT_SOUND
140                 overflow += 0.289115646;                                        // Fractional part of CPU cycles...
141
142                 if (overflow > 1.0)
143                 {
144                         overflow -= 1.0;
145                         time = 21;
146                 }
147                 else
148                         time = 20;
149 #endif
150         }
151 }