Added mixer and sound (c side)
This commit is contained in:
@@ -20,12 +20,15 @@
|
||||
#include "image.h"
|
||||
#include "palette.h"
|
||||
#include "package.h"
|
||||
#include "soundblaster.h"
|
||||
#include "mixer.h"
|
||||
|
||||
|
||||
static lua_State *L;
|
||||
|
||||
static void deinit(void) {
|
||||
/* Deinit and clear up everything. Called at exit */
|
||||
soundblaster_deinit();
|
||||
vga_deinit();
|
||||
keyboard_deinit();
|
||||
lua_close(L);
|
||||
@@ -59,6 +62,7 @@ int main(int argc, char **argv) {
|
||||
palette_init();
|
||||
keyboard_init();
|
||||
mouse_init();
|
||||
soundblaster_init(mixer_getNextBlock);
|
||||
|
||||
/* Init lua */
|
||||
L = luaL_newstate();
|
||||
|
||||
90
src/mixer.c
Normal file
90
src/mixer.c
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <string.h>
|
||||
#include <dos.h>
|
||||
#include <stdbool.h>
|
||||
#include "mixer.h"
|
||||
#include "soundblaster.h"
|
||||
|
||||
#define MIXER_MAX_SOUNDS 8
|
||||
|
||||
typedef struct {
|
||||
int offset;
|
||||
sound_t const *sound;
|
||||
} mixed_sound_t;
|
||||
|
||||
static mixed_sound_t sounds[MIXER_MAX_SOUNDS];
|
||||
static int activeSounds = 0;
|
||||
static int16_t data[SOUNDBLASTER_SAMPLES_PER_BUFFER] = {0};
|
||||
static bool canmix = true;
|
||||
|
||||
void mixer_init(void) {
|
||||
}
|
||||
|
||||
int16_t const * mixer_getNextBlock(void) {
|
||||
canmix = true;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void mixer_play(sound_t const *sound) {
|
||||
if(activeSounds == MIXER_MAX_SOUNDS) {
|
||||
// TODO Replace older sound with new one instead?
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = 0; i < activeSounds; ++i) {
|
||||
if(sounds[i].sound == sound) {
|
||||
sounds[i].offset = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sounds[activeSounds].offset = 0;
|
||||
sounds[activeSounds].sound = sound;
|
||||
++activeSounds;
|
||||
}
|
||||
|
||||
static inline int16_t mix(int32_t a, int32_t b) {
|
||||
int32_t res = a + b;
|
||||
if(res > INT16_MAX)
|
||||
res = INT16_MAX;
|
||||
if(res < INT16_MIN)
|
||||
res = INT16_MIN;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void mixer_mix(void) {
|
||||
if(!canmix)
|
||||
return;
|
||||
|
||||
memset(data, 0, SOUNDBLASTER_SAMPLES_PER_BUFFER);
|
||||
|
||||
for(int i = 0; i < activeSounds; ++i) {
|
||||
mixed_sound_t *snd = sounds + i;
|
||||
int len = snd->sound->sampleCount;
|
||||
int16_t const* soundBuf = snd->sound->samples;
|
||||
|
||||
if(len > SOUNDBLASTER_SAMPLES_PER_BUFFER) {
|
||||
len = SOUNDBLASTER_SAMPLES_PER_BUFFER;
|
||||
}
|
||||
|
||||
for(int offset = 0; offset < len; ++offset) {
|
||||
data[offset] = mix(data[offset], soundBuf[offset]);
|
||||
}
|
||||
|
||||
snd->offset += len;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
for(int i = activeSounds-1; i >= 0; --i) {
|
||||
mixed_sound_t *snd = sounds + i;
|
||||
if(snd->offset == snd->sound->sampleCount) {
|
||||
*snd = sounds[activeSounds-1];
|
||||
--activeSounds;
|
||||
}
|
||||
}
|
||||
|
||||
canmix = false;
|
||||
}
|
||||
11
src/mixer.h
Normal file
11
src/mixer.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sound.h"
|
||||
|
||||
|
||||
void mixer_init(void);
|
||||
void mixer_deinit(void);
|
||||
int16_t const* mixer_getNextBlock(void);
|
||||
void mixer_play(sound_t const *sound);
|
||||
void mixer_mix(void);
|
||||
15
src/sound.c
Normal file
15
src/sound.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <stdint.h>
|
||||
#include "sound.h"
|
||||
#include "lib/dmt/dmt.h"
|
||||
|
||||
int sound_init(sound_t *self, int samples) {
|
||||
self->sampleCount = samples;
|
||||
self->samples = (int16_t*)dmt_malloc(samples * sizeof(int16_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sound_deinit(sound_t *self) {
|
||||
dmt_free(self->samples);
|
||||
}
|
||||
|
||||
14
src/sound.h
Normal file
14
src/sound.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef SOUND_H
|
||||
#define SOUND_H
|
||||
|
||||
|
||||
typedef struct {
|
||||
int sampleCount;
|
||||
int16_t *samples;
|
||||
} sound_t;
|
||||
|
||||
int sound_init(sound_t *self, int samples);
|
||||
void sound_deinit(sound_t *self);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -44,6 +44,8 @@ static uint16_t dmaChannel;
|
||||
#define BLASTER_PROGRAM_STEREO 0x20
|
||||
#define BLASTER_PROGRAM_SIGNED 0x10
|
||||
#define BLASTER_SPEAKER_ON_CMD 0xD1
|
||||
#define BLASTER_SPEAKER_OFF_CMD 0xD3
|
||||
#define BLASTER_EXIT_AUTO_DMA 0xD9
|
||||
|
||||
|
||||
// PIC
|
||||
@@ -78,8 +80,10 @@ static const struct {
|
||||
{ 0xC8, 0xCA, 0xD4, 0xD6, 0xD8, 0x89 },
|
||||
{ 0xCC, 0xCE, 0xD4, 0xD6, 0xD8, 0x8A }
|
||||
};
|
||||
int stopDma = 0;
|
||||
|
||||
// ISR data
|
||||
int isrInstalled = 0;
|
||||
static _go32_dpmi_seginfo oldBlasterHandler, newBlasterHandler;
|
||||
int writePage = 0;
|
||||
|
||||
@@ -87,14 +91,13 @@ static soundblaster_getSampleProc getSamples;
|
||||
|
||||
static void writeDSP(uint8_t value) {
|
||||
while((inportb(baseAddress + BLASTER_WRITE_PORT) &
|
||||
BLASTER_WRITE_BUFFER_STATUS_UNAVAIL) != 0)
|
||||
;
|
||||
BLASTER_WRITE_BUFFER_STATUS_UNAVAIL) != 0) {}
|
||||
|
||||
outportb(baseAddress + BLASTER_WRITE_PORT, value);
|
||||
}
|
||||
|
||||
|
||||
static int resetBlaster() {
|
||||
static int resetBlaster(void) {
|
||||
for(int j = 0; j < 1000; ++j) {
|
||||
outportb(baseAddress + BLASTER_RESET_PORT, 1);
|
||||
delay(1);
|
||||
@@ -112,7 +115,11 @@ static int resetBlaster() {
|
||||
}
|
||||
|
||||
|
||||
static void soundblasterISR() {
|
||||
static void soundblasterISR(void) {
|
||||
if(stopDma == 1) {
|
||||
writeDSP(BLASTER_EXIT_AUTO_DMA);
|
||||
stopDma = 2;
|
||||
} else {
|
||||
outportb(baseAddress + BLASTER_MIXER_OUT_PORT,
|
||||
BLASTER_MIXER_INTERRUPT_STATUS);
|
||||
uint8_t status = inportb(baseAddress + BLASTER_MIXER_IN_PORT);
|
||||
@@ -126,6 +133,7 @@ static void soundblasterISR() {
|
||||
writePage = 1 - writePage;
|
||||
inportb(baseAddress + BLASTER_INTERRUPT_ACKNOWLEDGE_16BIT);
|
||||
}
|
||||
}
|
||||
|
||||
if(irq >= 8) {
|
||||
outportb(PIC2_COMMAND, PIC_EOI);
|
||||
@@ -134,7 +142,7 @@ static void soundblasterISR() {
|
||||
}
|
||||
|
||||
|
||||
static void setBlasterISR() {
|
||||
static void setBlasterISR(void) {
|
||||
// Map IRQ to interrupt number on the CPU
|
||||
uint16_t interruptVector = irq + irq + (irq < 8)
|
||||
? PIC_IRQ07_MAP
|
||||
@@ -156,6 +164,8 @@ static void setBlasterISR() {
|
||||
uint8_t irqmask = inportb(PIC2_DATA);
|
||||
outportb(PIC2_DATA, irqmask & ~(1<<(irq-8)));
|
||||
}
|
||||
|
||||
isrInstalled = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +185,7 @@ static int parseBlasterSettings(void) {
|
||||
}
|
||||
|
||||
|
||||
static int allocSampleBuffer() {
|
||||
static int allocSampleBuffer(void) {
|
||||
static int maxRetries = 10;
|
||||
int selectors[maxRetries];
|
||||
int current;
|
||||
@@ -211,11 +221,16 @@ static int allocSampleBuffer() {
|
||||
}
|
||||
|
||||
|
||||
static void turnSpeakerOn() {
|
||||
static void turnSpeakerOn(void) {
|
||||
writeDSP(BLASTER_SPEAKER_ON_CMD);
|
||||
}
|
||||
|
||||
|
||||
static void turnSpeakerOff(void) {
|
||||
writeDSP(BLASTER_SPEAKER_OFF_CMD);
|
||||
}
|
||||
|
||||
|
||||
static void dmaSetupTransfer(int channel,
|
||||
uint8_t direction,
|
||||
bool autoReload,
|
||||
@@ -252,7 +267,7 @@ static void dmaSetupTransfer(int channel,
|
||||
}
|
||||
|
||||
|
||||
static void startDMAOutput() {
|
||||
static void startDMAOutput(void) {
|
||||
uint32_t offset = (uint32_t)sampleBuffer;
|
||||
|
||||
uint32_t samples = SAMPLE_BUFFER_SIZE / sizeof(int16_t);
|
||||
@@ -302,6 +317,33 @@ int soundblaster_init(soundblaster_getSampleProc getsamplesproc) {
|
||||
}
|
||||
|
||||
|
||||
void soundblaster_deinit(void) {
|
||||
|
||||
static void deallocSampleBuffer(void) {
|
||||
__dpmi_free_dos_memory(sampleBufferSelector);
|
||||
}
|
||||
|
||||
|
||||
static void resetBlasterISR(void) {
|
||||
if(isrInstalled == 1) {
|
||||
uint16_t interruptVector = irq + irq + (irq < 8)
|
||||
? PIC_IRQ07_MAP
|
||||
: PIC_IRQ8F_MAP;
|
||||
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(interruptVector, &oldBlasterHandler);
|
||||
isrInstalled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void stopDMAOutput(void) {
|
||||
stopDma = 1;
|
||||
while(stopDma == 1) {}
|
||||
}
|
||||
|
||||
|
||||
void soundblaster_deinit(void) {
|
||||
turnSpeakerOff();
|
||||
stopDMAOutput();
|
||||
resetBlaster();
|
||||
resetBlasterISR();
|
||||
deallocSampleBuffer();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user