Skip to content

Commit f6d77a5

Browse files
committed
GUS OpenAL backend implementation.
1 parent 57216ff commit f6d77a5

14 files changed

Lines changed: 774 additions & 29 deletions

src/gamemng.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -418,18 +418,18 @@ void Gamemng::init(const char* maps_def, const char* objs_def, const char* cars_
418418
}
419419
gbuff_in.fclose();
420420
for (unsigned int i = 0; i != p_cars.size(); ++i) {
421-
gbuff_in.f_open(p_cars[i].fname_sample_engine0, "rb");
421+
gbuff_in.f_open(p_cars[i].fname_sample_engine0, "rb");if (smallSampleRam())gbuff_in.downsampleAudio16();
422422
alGenBuffers(1, &(p_cars[i].p_engine0_sample)); global_al_buffers.push_back(p_cars[i].p_engine0_sample);
423423
swapArrayLE16(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
424424
tweakLoop(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
425-
alBufferData(p_cars[i].p_engine0_sample, AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), 22050);
425+
alBufferData(p_cars[i].p_engine0_sample, AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), smallSampleRam() ? 11025 : 22050);
426426
gbuff_in.fclose();
427427

428-
gbuff_in.f_open(p_cars[i].fname_sample_engine1, "rb");
428+
gbuff_in.f_open(p_cars[i].fname_sample_engine1, "rb");if (smallSampleRam())gbuff_in.downsampleAudio16();
429429
alGenBuffers(1, &(p_cars[i].p_engine1_sample)); global_al_buffers.push_back(p_cars[i].p_engine1_sample);
430430
swapArrayLE16(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
431431
tweakLoop(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
432-
alBufferData(p_cars[i].p_engine1_sample, AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), 22050);
432+
alBufferData(p_cars[i].p_engine1_sample, AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), smallSampleRam() ? 11025 : 22050);
433433
gbuff_in.fclose();
434434
}
435435
}

src/gbuff_in.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "gbuff_in.h"
22

33
#include <cstdio>
4+
#include <cstdint>
45

56
Gbuff_in gbuff_in;
67

@@ -10,6 +11,20 @@ bool Gbuff_in::init_dat(const char* fname)
1011
return p_datdec.init(fname);
1112
}
1213

14+
void Gbuff_in::downsampleAudio16()
15+
{
16+
size_t newSize = p_datdec.p_buff.size() / 4 * 2;
17+
int16_t* p = (int16_t*)p_datdec.p_buff.data();
18+
for (unsigned int i = 0; i != newSize / 2; ++i)
19+
{
20+
int32_t sum = 0;
21+
sum += p[i * 2] + p[i * 2 + 1];
22+
sum /= 2;
23+
p[i] = sum;
24+
}
25+
p_datdec.p_buff.resize(newSize);
26+
}
27+
1328
void Gbuff_in::rewind()
1429
{
1530
if (p_bactive)

src/gbuff_in.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class Gbuff_in {
1717
// fce pro práci s textovým souborem
1818
char* fgets(char* str, int num); // normálně char * fgets ( char * str, int num, FILE * stream )
1919
void rewind();
20+
void downsampleAudio16(); // hack
2021
// fce pro práci s binárním souborem
2122
/*const*/ unsigned char* fbuffptr();
2223
unsigned int fbuffsz();

src/gus.cpp

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
#include "gus.h"
2+
3+
#include <dos.h>
4+
5+
#include <cmath>
6+
7+
static uint32_t Base = 0;
8+
static uint32_t Divisor = 1;
9+
10+
/* Read a value from GUS memory */
11+
uint8_t GUSPeek(uint32_t loc)
12+
{
13+
uint16_t addLo = loc & 0xFFFF;
14+
uint8_t addHi = loc >> 16;
15+
outportb(Base + 0x103, 0x43);
16+
outportw(Base + 0x104, addLo);
17+
outportb(Base + 0x103, 0x44);
18+
outportb(Base + 0x105, addHi);
19+
20+
uint8_t b = inportb(Base + 0x107);
21+
return b;
22+
}
23+
24+
/* Write a value into GUS memory */
25+
void GUSPoke(uint32_t loc, uint8_t b)
26+
{
27+
uint16_t addLo = loc & 0xFFFF;
28+
uint8_t addHi = loc >> 16;
29+
outportb(Base + 0x103, 0x43);
30+
outportw(Base + 0x104, addLo);
31+
outportb(Base + 0x103, 0x44);
32+
outportb(Base + 0x105, addHi);
33+
outportb(Base + 0x107, b);
34+
}
35+
36+
/* Returns TRUE if there is a GUS at I/O address BASE */
37+
bool GUSProbe(void)
38+
{
39+
outportb(Base + 0x103, 0x4C);
40+
outportb(Base + 0x105, 0);
41+
delay(1);
42+
outportb(Base + 0x103, 0x4C);
43+
outportb(Base + 0x105, 1);
44+
GUSPoke(0, 0xAA);
45+
GUSPoke(0x100, 0x55);
46+
uint8_t b = GUSPeek(0);
47+
return (b == 0xAA);
48+
}
49+
50+
/* Search all possible I/O addresses for the GUS */
51+
uint32_t GUSFind(void)
52+
{
53+
for (uint16_t i = 1; i <= 8; ++i)
54+
{
55+
Base = 0x200 + i * 0x10;
56+
if (GUSProbe())
57+
{
58+
break;
59+
}
60+
}
61+
if (Base < 0x280)
62+
{
63+
return Base;
64+
}
65+
return 0;
66+
}
67+
68+
/* Returns how much RAM is available on the GUS */
69+
uint32_t GUSFindMem(void)
70+
{
71+
uint32_t ret;
72+
GUSPoke(0x40000, 0xAA);
73+
if (GUSPeek(0x40000) != 0xAA)
74+
{
75+
ret = 0x40000;
76+
}
77+
else
78+
{
79+
GUSPoke(0x80000, 0xAA);
80+
if (GUSPeek(0x80000) != 0xAA)
81+
{
82+
ret = 0x80000;
83+
}
84+
else
85+
{
86+
GUSPoke(0xC0000, 0xAA);
87+
if (GUSPeek(0xC0000) != 0xAA)
88+
{
89+
ret = 0xC0000;
90+
}
91+
else
92+
{
93+
ret = 0x100000;
94+
}
95+
}
96+
}
97+
return ret;
98+
}
99+
100+
/* An incomplete routine to initialise the GUS for output. */
101+
void GUSReset(uint8_t voices)
102+
{
103+
if (voices < 14)
104+
{
105+
voices = 14;
106+
}
107+
else if (voices > 32)
108+
{
109+
voices = 32;
110+
}
111+
Divisor = std::floor(1000000.0 / (1.619695497 * voices) + 0.5);
112+
outportb(Base + 0x103, 0x4C);
113+
outportb(Base + 0x105, 1);
114+
delay(1);
115+
outportb(Base + 0x103, 0x4C);
116+
outportb(Base + 0x105, 7);
117+
outportb(Base + 0x103, 0x0E);
118+
// outportb(Base + 0x105, 14 | 0x0C0);
119+
outportb(Base + 0x105, (voices - 1) | 0x0C0);
120+
121+
for (int i = 0; i != voices; ++i)
122+
{
123+
GUSVoiceControl(i, GUS_VOICE_STOP);
124+
}
125+
}
126+
127+
/* Set the volume of channel voi to vol, a 16bit logarithmic scale
128+
volume value - 0 is off, $ffff is full volume, $e0000 is half volume, etc */
129+
void GUSSetVolume(uint8_t voi, uint16_t vol)
130+
{
131+
if (vol > 511)
132+
vol = 511;
133+
static const uint16_t volumes[512] = {
134+
0x0000, 0x7000, 0x7ff0, 0x8800, 0x8ff0, 0x9400, 0x9800, 0x9c00, 0x9ff0, 0xa200, 0xa400, 0xa600, 0xa800, 0xaa00,
135+
0xac00, 0xae00, 0xaff0, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700, 0xb800, 0xb900, 0xba00, 0xbb00,
136+
0xbc00, 0xbd00, 0xbe00, 0xbf00, 0xbff0, 0xc080, 0xc100, 0xc180, 0xc200, 0xc280, 0xc300, 0xc380, 0xc400, 0xc480,
137+
0xc500, 0xc580, 0xc600, 0xc680, 0xc700, 0xc780, 0xc800, 0xc880, 0xc900, 0xc980, 0xca00, 0xca80, 0xcb00, 0xcb80,
138+
0xcc00, 0xcc80, 0xcd00, 0xcd80, 0xce00, 0xce80, 0xcf00, 0xcf80, 0xcff0, 0xd040, 0xd080, 0xd0c0, 0xd100, 0xd140,
139+
0xd180, 0xd1c0, 0xd200, 0xd240, 0xd280, 0xd2c0, 0xd300, 0xd340, 0xd380, 0xd3c0, 0xd400, 0xd440, 0xd480, 0xd4c0,
140+
0xd500, 0xd540, 0xd580, 0xd5c0, 0xd600, 0xd640, 0xd680, 0xd6c0, 0xd700, 0xd740, 0xd780, 0xd7c0, 0xd800, 0xd840,
141+
0xd880, 0xd8c0, 0xd900, 0xd940, 0xd980, 0xd9c0, 0xda00, 0xda40, 0xda80, 0xdac0, 0xdb00, 0xdb40, 0xdb80, 0xdbc0,
142+
0xdc00, 0xdc40, 0xdc80, 0xdcc0, 0xdd00, 0xdd40, 0xdd80, 0xddc0, 0xde00, 0xde40, 0xde80, 0xdec0, 0xdf00, 0xdf40,
143+
0xdf80, 0xdfc0, 0xdff0, 0xe020, 0xe040, 0xe060, 0xe080, 0xe0a0, 0xe0c0, 0xe0e0, 0xe100, 0xe120, 0xe140, 0xe160,
144+
0xe180, 0xe1a0, 0xe1c0, 0xe1e0, 0xe200, 0xe220, 0xe240, 0xe260, 0xe280, 0xe2a0, 0xe2c0, 0xe2e0, 0xe300, 0xe320,
145+
0xe340, 0xe360, 0xe380, 0xe3a0, 0xe3c0, 0xe3e0, 0xe400, 0xe420, 0xe440, 0xe460, 0xe480, 0xe4a0, 0xe4c0, 0xe4e0,
146+
0xe500, 0xe520, 0xe540, 0xe560, 0xe580, 0xe5a0, 0xe5c0, 0xe5e0, 0xe600, 0xe620, 0xe640, 0xe660, 0xe680, 0xe6a0,
147+
0xe6c0, 0xe6e0, 0xe700, 0xe720, 0xe740, 0xe760, 0xe780, 0xe7a0, 0xe7c0, 0xe7e0, 0xe800, 0xe820, 0xe840, 0xe860,
148+
0xe880, 0xe8a0, 0xe8c0, 0xe8e0, 0xe900, 0xe920, 0xe940, 0xe960, 0xe980, 0xe9a0, 0xe9c0, 0xe9e0, 0xea00, 0xea20,
149+
0xea40, 0xea60, 0xea80, 0xeaa0, 0xeac0, 0xeae0, 0xeb00, 0xeb20, 0xeb40, 0xeb60, 0xeb80, 0xeba0, 0xebc0, 0xebe0,
150+
0xec00, 0xec20, 0xec40, 0xec60, 0xec80, 0xeca0, 0xecc0, 0xece0, 0xed00, 0xed20, 0xed40, 0xed60, 0xed80, 0xeda0,
151+
0xedc0, 0xede0, 0xee00, 0xee20, 0xee40, 0xee60, 0xee80, 0xeea0, 0xeec0, 0xeee0, 0xef00, 0xef20, 0xef40, 0xef60,
152+
0xef80, 0xefa0, 0xefc0, 0xefe0, 0xeff0, 0xf010, 0xf020, 0xf030, 0xf040, 0xf050, 0xf060, 0xf070, 0xf080, 0xf090,
153+
0xf0a0, 0xf0b0, 0xf0c0, 0xf0d0, 0xf0e0, 0xf0f0, 0xf100, 0xf110, 0xf120, 0xf130, 0xf140, 0xf150, 0xf160, 0xf170,
154+
0xf180, 0xf190, 0xf1a0, 0xf1b0, 0xf1c0, 0xf1d0, 0xf1e0, 0xf1f0, 0xf200, 0xf210, 0xf220, 0xf230, 0xf240, 0xf250,
155+
0xf260, 0xf270, 0xf280, 0xf290, 0xf2a0, 0xf2b0, 0xf2c0, 0xf2d0, 0xf2e0, 0xf2f0, 0xf300, 0xf310, 0xf320, 0xf330,
156+
0xf340, 0xf350, 0xf360, 0xf370, 0xf380, 0xf390, 0xf3a0, 0xf3b0, 0xf3c0, 0xf3d0, 0xf3e0, 0xf3f0, 0xf400, 0xf410,
157+
0xf420, 0xf430, 0xf440, 0xf450, 0xf460, 0xf470, 0xf480, 0xf490, 0xf4a0, 0xf4b0, 0xf4c0, 0xf4d0, 0xf4e0, 0xf4f0,
158+
0xf500, 0xf510, 0xf520, 0xf530, 0xf540, 0xf550, 0xf560, 0xf570, 0xf580, 0xf590, 0xf5a0, 0xf5b0, 0xf5c0, 0xf5d0,
159+
0xf5e0, 0xf5f0, 0xf600, 0xf610, 0xf620, 0xf630, 0xf640, 0xf650, 0xf660, 0xf670, 0xf680, 0xf690, 0xf6a0, 0xf6b0,
160+
0xf6c0, 0xf6d0, 0xf6e0, 0xf6f0, 0xf700, 0xf710, 0xf720, 0xf730, 0xf740, 0xf750, 0xf760, 0xf770, 0xf780, 0xf790,
161+
0xf7a0, 0xf7b0, 0xf7c0, 0xf7d0, 0xf7e0, 0xf7f0, 0xf800, 0xf810, 0xf820, 0xf830, 0xf840, 0xf850, 0xf860, 0xf870,
162+
0xf880, 0xf890, 0xf8a0, 0xf8b0, 0xf8c0, 0xf8d0, 0xf8e0, 0xf8f0, 0xf900, 0xf910, 0xf920, 0xf930, 0xf940, 0xf950,
163+
0xf960, 0xf970, 0xf980, 0xf990, 0xf9a0, 0xf9b0, 0xf9c0, 0xf9d0, 0xf9e0, 0xf9f0, 0xfa00, 0xfa10, 0xfa20, 0xfa30,
164+
0xfa40, 0xfa50, 0xfa60, 0xfa70, 0xfa80, 0xfa90, 0xfaa0, 0xfab0, 0xfac0, 0xfad0, 0xfae0, 0xfaf0, 0xfb00, 0xfb10,
165+
0xfb20, 0xfb30, 0xfb40, 0xfb50, 0xfb60, 0xfb70, 0xfb80, 0xfb90, 0xfba0, 0xfbb0, 0xfbc0, 0xfbd0, 0xfbe0, 0xfbf0,
166+
0xfc00, 0xfc10, 0xfc20, 0xfc30, 0xfc40, 0xfc50, 0xfc60, 0xfc70, 0xfc80, 0xfc90, 0xfca0, 0xfcb0, 0xfcc0, 0xfcd0,
167+
0xfce0, 0xfcf0, 0xfd00, 0xfd10, 0xfd20, 0xfd30, 0xfd40, 0xfd50, 0xfd60, 0xfd70, 0xfd80, 0xfd90, 0xfda0, 0xfdb0,
168+
0xfdc0, 0xfdd0, 0xfde0, 0xfdf0, 0xfe00, 0xfe10, 0xfe20, 0xfe30, 0xfe40, 0xfe50, 0xfe60, 0xfe70, 0xfe80, 0xfe90,
169+
0xfea0, 0xfeb0, 0xfec0, 0xfed0, 0xfee0, 0xfef0, 0xff00, 0xff10, 0xff20, 0xff30, 0xff40, 0xff50, 0xff60, 0xff70,
170+
0xff80, 0xff90, 0xffa0, 0xffb0, 0xffc0, 0xffd0, 0xffe0, 0xfff0};
171+
172+
outportb(Base + 0x102, voi);
173+
outportb(Base + 0x102, voi);
174+
outportb(Base + 0x102, voi);
175+
outportb(Base + 0x103, 9);
176+
outportw(Base + 0x104, volumes[vol]); /* 0-0ffffh, log scale not linear */
177+
}
178+
179+
/* set the pan position (from 0 to 15, 0 being left, 15 right and 7 middle) */
180+
void GUSSetBalance(uint8_t v, uint8_t b)
181+
{
182+
outportb(Base + 0x102, v);
183+
outportb(Base + 0x102, v);
184+
outportb(Base + 0x102, v);
185+
outportb(Base + 0x103, 0xC);
186+
outportb(Base + 0x105, b);
187+
}
188+
189+
/* frequency at which the sample should be played */
190+
void GUSSetFreq(uint8_t v, uint32_t freq)
191+
{
192+
uint32_t fc = (uint32_t)(((freq << 9L) + (Divisor >> 1L)) / Divisor);
193+
fc = fc << 1;
194+
if (fc > 65535)
195+
{
196+
fc = 65535;
197+
}
198+
else if (fc < 16)
199+
{
200+
fc = 16;
201+
}
202+
outportb(Base + 0x102, v);
203+
outportb(Base + 0x102, v);
204+
outportb(Base + 0x102, v);
205+
outportb(Base + 0x103, 1);
206+
outportw(Base + 0x104, fc);
207+
}
208+
209+
/* This routine tells the GUS to play a sample commencing at vBegin,
210+
starting at location vStart, and stopping at vEnd */
211+
void GUSPlayVoice(uint8_t v, uint8_t mode, uint32_t vBegin, uint32_t vStart, uint32_t vEnd)
212+
{
213+
outportb(Base + 0x102, v);
214+
outportb(Base + 0x102, v);
215+
outportb(Base + 0x103, 0x0A);
216+
outportw(Base + 0x104, (vBegin >> 7) & 8191);
217+
outportb(Base + 0x103, 0x0B);
218+
outportw(Base + 0x104, (vBegin & 127) << 8);
219+
outportb(Base + 0x103, 0x02);
220+
outportw(Base + 0x104, (vStart >> 7) & 8191);
221+
outportb(Base + 0x103, 0x03);
222+
outportw(Base + 0x104, (vStart & 127) << 8);
223+
outportb(Base + 0x103, 0x04);
224+
outportw(Base + 0x104, ((vEnd) >> 7) & 8191);
225+
outportb(Base + 0x103, 0x05);
226+
outportw(Base + 0x104, ((vEnd)&127) << 8);
227+
outportb(Base + 0x103, 0);
228+
outportb(Base + 0x105, mode);
229+
230+
/* The below part isn't mentioned as necessary, but the card won't play anything without it! */
231+
outportb(Base, 1);
232+
outportb(Base + 0x103, 0x4C);
233+
outportb(Base + 0x105, 3);
234+
}
235+
236+
/* This routine will return the memory location that the channel v is currently playing. If the GUS has reached the end
237+
* of the sample, then the returned value will be vEnd. If you want to see what BYTE value is currently being played
238+
* (for visual output of the sample's waveform), then you simply PEEK the location pointed to by this routine. */
239+
uint32_t GUSVoicePos(uint8_t v)
240+
{
241+
outportb(Base + 0x102, v);
242+
outportb(Base + 0x102, v);
243+
outportb(Base + 0x102, v);
244+
outportb(Base + 0x103, 0x8A);
245+
uint16_t temp0 = inportw(Base + 0x104);
246+
outportb(Base + 0x103, 0x8B);
247+
uint16_t temp1 = inportw(Base + 0x104);
248+
return (temp0 << 7) + (temp1 >> 8);
249+
}
250+
251+
/* stop the playback on channel v */
252+
void GUSStopVoice(uint8_t v)
253+
{
254+
outportb(Base + 0x102, v);
255+
outportb(Base + 0x102, v);
256+
outportb(Base + 0x102, v);
257+
outportb(Base + 0x103, 0x80);
258+
uint8_t temp = inportb(Base + 0x105);
259+
outportb(Base + 0x103, 0);
260+
outportb(Base + 0x105, (temp & 0xdf) | 3);
261+
delay(1);
262+
outportb(Base + 0x103, 0);
263+
outportb(Base + 0x105, (temp & 0xdf) | 3);
264+
}
265+
266+
void GUSVoiceControl(uint8_t v, uint8_t b)
267+
{
268+
outportb(Base + 0x102, v);
269+
outportb(Base + 0x102, v);
270+
outportb(Base + 0x103, 0);
271+
outportb(Base + 0x105, b);
272+
}

src/gus.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#ifndef GUS_H
2+
#define GUS_H
3+
4+
#include <cstdint>
5+
6+
/* Read a value from GUS memory */
7+
uint8_t GUSPeek(uint32_t loc);
8+
9+
/* Write a value into GUS memory */
10+
void GUSPoke(uint32_t loc, uint8_t b);
11+
12+
/* Returns TRUE if there is a GUS at I/O address BASE */
13+
bool GUSProbe(void);
14+
15+
/* Search all possible I/O addresses for the GUS */
16+
uint32_t GUSFind(void);
17+
18+
/* Returns how much RAM is available on the GUS */
19+
uint32_t GUSFindMem(void);
20+
21+
/* An incomplete routine to initialise the GUS for output. */
22+
void GUSReset(uint8_t voices = 14);
23+
24+
/* Set the volume of channel voi to vol, a 16bit logarithmic scale
25+
volume value - 0 is off, $ffff is full volume, $e0000 is half volume, etc */
26+
void GUSSetVolume(uint8_t voi, uint16_t vol);
27+
28+
/* set the pan position (from 0 to 15, 0 being left, 15 right and 7 middle) */
29+
void GUSSetBalance(uint8_t v, uint8_t b);
30+
31+
/* frequency at which the sample should be played */
32+
void GUSSetFreq(uint8_t v, uint32_t f);
33+
34+
/* This routine tells the GUS to play a sample commencing at vBegin,
35+
starting at location vStart, and stopping at vEnd */
36+
void GUSPlayVoice(uint8_t v, uint8_t mode, uint32_t vBegin, uint32_t vStart, uint32_t vEnd);
37+
38+
/* This routine will return the memory location that the channel v is currently playing. If the GUS has reached the end
39+
* of the sample, then the returned value will be vEnd. If you want to see what BYTE value is currently being played
40+
* (for visual output of the sample's waveform), then you simply PEEK the location pointed to by this routine. */
41+
uint32_t GUSVoicePos(uint8_t v);
42+
43+
/* stop the playback on channel v */
44+
/*void GUSStopVoice(uint8_t v);*/
45+
46+
void GUSVoiceControl(uint8_t v, uint8_t b);
47+
48+
#define GUS_VOICE_STOPPED 1
49+
#define GUS_VOICE_STOP 2
50+
#define GUS_VOICE_16BIT 4
51+
#define GUS_LOOP_ENABLE 8
52+
#define GUS_BIDIRECTIONAL_LOOP 16
53+
#define GUS_WAVETABLE_IRQ 32
54+
#define GUS_DIRECTION 64
55+
#define GUS_IRQ_PENDING 128
56+
57+
#endif // GUS_H

0 commit comments

Comments
 (0)