]> Shamusworld >> Repos - stargem2/blob - src/sound.cpp
Added config file key bindings, general code cleanup
[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 // JLH  07/21/2009  Moved numeric constants into macros for sanity's sake
16 //
17 // Notes:
18 //   The sound CPU (6808) runs at 894,750 (3,579,000 / 4) Hz.
19 //   At 44.1 KHz, this works out to 894750 / 44100 = 20.289115646... cycles per sample.
20 //
21
22 // Still need to add volume control...
23
24 #include "sound.h"
25
26 #include "SDL.h"
27 #include "types.h"
28 #include "log.h"
29 #include "v6808.h"
30 #include "timing.h"
31
32 //using namespace std;
33
34 //#define AUDIO_SAMPLE_RATE                             44100.0
35 #define AUDIO_SAMPLE_RATE                               48000.0
36 #define CYCLES_TO_EXECUTE                               (M6808_CLOCK_SPEED_IN_HZ / AUDIO_SAMPLE_RATE)
37
38 // Local variables
39
40 static SDL_AudioSpec desired;
41 static bool soundInitialized = false;
42 static uint32 cyclesToExecuteWholePart;
43 static double cyclesToExecuteFractionalPart;
44
45 // Private function prototypes
46
47 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
48
49 //
50 // Initialize the SDL sound system
51 //
52 void SoundInit(void)
53 {
54 //      memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
55
56         desired.freq = AUDIO_SAMPLE_RATE;                               // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
57         desired.format = AUDIO_U8;                                              // This uses the native endian (for portability)...
58         desired.channels = 1;
59 //      desired.samples = 4096;                                                 // Let's try a 4K buffer (can always go lower)
60         desired.samples = 2048;                                                 // Let's try a 2K buffer (can always go lower)
61         desired.callback = SDLSoundCallback;
62
63         if (SDL_OpenAudio(&desired, NULL) < 0)                  // NULL means SDL guarantees what we want
64         {
65                 WriteLog("Sound: Failed to initialize SDL sound.\n");
66                 return;
67         }
68
69         // Setup clock cycles & etc.
70         cyclesToExecuteWholePart = (uint32)CYCLES_TO_EXECUTE;
71         cyclesToExecuteFractionalPart = CYCLES_TO_EXECUTE - (double)cyclesToExecuteWholePart;
72 #if 0
73 printf("Cycles to execute: %lf; cycles W: %u; cycles F: %lf\n", CYCLES_TO_EXECUTE, cyclesToExecuteWholePart, cyclesToExecuteFractionalPart);
74 #endif
75
76         SDL_PauseAudio(false);                                                  // Start playback!
77         soundInitialized = true;
78         WriteLog("Sound: Successfully initialized.\n");
79 }
80
81 //
82 // Close down the SDL sound subsystem
83 //
84 void SoundDone(void)
85 {
86         if (soundInitialized)
87         {
88                 SDL_PauseAudio(true);
89                 SDL_CloseAudio();
90                 WriteLog("Sound: Done.\n");
91         }
92 }
93
94 //
95 // Sound card callback handler
96 //
97 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
98 {
99         extern V6808REGS soundCPU;
100         extern uint8 sram[];
101         int cnt = 0;
102
103         static float overflow = 0.0;
104         static uint32 time = cyclesToExecuteWholePart;
105
106         while (cnt != length)
107         {
108                 Execute6808(&soundCPU, time);
109                 soundCPU.clock -= time;
110                 buffer[cnt++] = sram[0x0400];                           // Fill the buffer with the PIA output value
111                 time = cyclesToExecuteWholePart;
112                 overflow += cyclesToExecuteFractionalPart;
113
114                 if (overflow > 1.0)
115                 {
116                         overflow -= 1.0;
117                         time++;
118                 }
119         }
120 }