1 /***************************************************************************
2 Interface to Ported Z80 Code.
3 Handles the interface between 68000 program code and Z80.
4
5 Also abstracted here, so the more complex OSound class isn't exposed
6 to the main code directly
7
8 Copyright Chris White.
9 See license.txt for more details.
10 ***************************************************************************/
11
12 #include "engine/outrun.hpp"
13 #include "engine/audio/osound.hpp"
14 #include "engine/audio/osoundint.hpp"
15
16 OSoundInt osoundint;
17 OSound osound;
18
OSoundInt()19 OSoundInt::OSoundInt()
20 {
21 pcm_ram = new uint8_t[PCM_RAM_SIZE];
22 has_booted = false;
23 }
24
~OSoundInt()25 OSoundInt::~OSoundInt()
26 {
27 delete[] pcm_ram;
28 }
29
init()30 void OSoundInt::init()
31 {
32 if (pcm == NULL)
33 pcm = new SegaPCM(SOUND_CLOCK, &roms.pcm, pcm_ram, SegaPCM::BANK_512);
34
35 if (ym == NULL)
36 ym = new YM2151(0.5f, SOUND_CLOCK);
37
38 pcm->init(config.sound.rate, config.fps);
39 ym->init(config.sound.rate, config.fps);
40
41 reset();
42
43 // Clear PCM Chip RAM
44 for (uint16_t i = 0; i < PCM_RAM_SIZE; i++)
45 pcm_ram[i] = 0;
46
47 for (uint8_t i = 0; i < 8; i++)
48 engine_data[i] = 0;
49
50 osound.init(ym, pcm_ram);
51 }
52
53 // Clear sound queue
54 // Source: 0x5086
reset()55 void OSoundInt::reset()
56 {
57 sound_counter = 0;
58 sound_head = 0;
59 sound_tail = 0;
60 sounds_queued = 0;
61
62 audio_ticks = 0;
63 }
64
tick()65 void OSoundInt::tick()
66 {
67 // The audio code is updated 125 times per second
68 audio_ticks += (125.0 / config.fps);
69
70 // Ticks per frame will vary between 2 and 3 at 60fps.
71 const int max_ticks = (int) audio_ticks;
72
73 for (int i = 0; i < max_ticks; i++)
74 {
75 play_queued_sound(); // Process audio commands from main program code
76 osound.tick(); // Tick Ported Z80 Audio Code
77 }
78
79 audio_ticks -= max_ticks;
80 }
81
82 // ----------------------------------------------------------------------------
83 // Sound Queuing Code
84 // ----------------------------------------------------------------------------
85
86 // Play Queued Sounds & Send Engine Noise Commands to Z80
87 // Was called by horizontal interrupt routine
88 // Source: 0x564E
play_queued_sound()89 void OSoundInt::play_queued_sound()
90 {
91 if (!has_booted)
92 {
93 sound_head = 0;
94 sounds_queued = 0;
95 return;
96 }
97
98 // Process the lot in one go.
99 for (int counter = 0; counter < 8; counter++)
100 {
101 // Process queued sound
102 if (counter == 0)
103 {
104 if (sounds_queued != 0)
105 {
106 osound.command_input = queue[sound_head];
107 sound_head = (sound_head + 1) & QUEUE_LENGTH;
108 sounds_queued--;
109 }
110 else
111 {
112 osound.command_input = sound::RESET;
113 }
114 }
115 // Process player engine sounds and passing traffic
116 else
117 {
118 osound.engine_data[counter] = engine_data[counter];
119 }
120 }
121 }
122
123 // Queue a sound in service mode
124 // Used to trigger both sound effects and music
125 // Source: 0x56C6
queue_sound_service(uint8_t snd)126 void OSoundInt::queue_sound_service(uint8_t snd)
127 {
128 if (has_booted)
129 add_to_queue(snd);
130 else
131 queue_clear();
132 }
133
134 // Queue a sound in-game
135 // Note: This version has an additional check, so that certain sounds aren't played depending on game mode
136 // Source: 0x56D4
queue_sound(uint8_t snd)137 void OSoundInt::queue_sound(uint8_t snd)
138 {
139 if (has_booted)
140 {
141 if (outrun.game_state == GS_ATTRACT)
142 {
143 // Return if we are not playing sound in attract mode
144 if (!config.sound.advertise && snd != sound::COIN_IN) return;
145
146 // Do not play music in attract mode, even if attract sound enabled
147 if (snd == sound::MUSIC_BREEZE || snd == sound::MUSIC_MAGICAL ||
148 snd == sound::MUSIC_SPLASH || snd == sound::MUSIC_LASTWAVE)
149 return;
150 }
151 add_to_queue(snd);
152 }
153 else
154 queue_clear();
155 }
156
add_to_queue(uint8_t snd)157 void OSoundInt::add_to_queue(uint8_t snd)
158 {
159 // Add sound to the tail end of the queue
160 queue[sound_tail] = snd;
161 sound_tail = (sound_tail + 1) & QUEUE_LENGTH;
162 sounds_queued++;
163 }
164
queue_clear()165 void OSoundInt::queue_clear()
166 {
167 sound_tail = 0;
168 sounds_queued = 0;
169 }