Added mixer and sound (c side)
This commit is contained in:
@@ -20,12 +20,15 @@
|
|||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
#include "package.h"
|
#include "package.h"
|
||||||
|
#include "soundblaster.h"
|
||||||
|
#include "mixer.h"
|
||||||
|
|
||||||
|
|
||||||
static lua_State *L;
|
static lua_State *L;
|
||||||
|
|
||||||
static void deinit(void) {
|
static void deinit(void) {
|
||||||
/* Deinit and clear up everything. Called at exit */
|
/* Deinit and clear up everything. Called at exit */
|
||||||
|
soundblaster_deinit();
|
||||||
vga_deinit();
|
vga_deinit();
|
||||||
keyboard_deinit();
|
keyboard_deinit();
|
||||||
lua_close(L);
|
lua_close(L);
|
||||||
@@ -59,6 +62,7 @@ int main(int argc, char **argv) {
|
|||||||
palette_init();
|
palette_init();
|
||||||
keyboard_init();
|
keyboard_init();
|
||||||
mouse_init();
|
mouse_init();
|
||||||
|
soundblaster_init(mixer_getNextBlock);
|
||||||
|
|
||||||
/* Init lua */
|
/* Init lua */
|
||||||
L = luaL_newstate();
|
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_STEREO 0x20
|
||||||
#define BLASTER_PROGRAM_SIGNED 0x10
|
#define BLASTER_PROGRAM_SIGNED 0x10
|
||||||
#define BLASTER_SPEAKER_ON_CMD 0xD1
|
#define BLASTER_SPEAKER_ON_CMD 0xD1
|
||||||
|
#define BLASTER_SPEAKER_OFF_CMD 0xD3
|
||||||
|
#define BLASTER_EXIT_AUTO_DMA 0xD9
|
||||||
|
|
||||||
|
|
||||||
// PIC
|
// PIC
|
||||||
@@ -78,8 +80,10 @@ static const struct {
|
|||||||
{ 0xC8, 0xCA, 0xD4, 0xD6, 0xD8, 0x89 },
|
{ 0xC8, 0xCA, 0xD4, 0xD6, 0xD8, 0x89 },
|
||||||
{ 0xCC, 0xCE, 0xD4, 0xD6, 0xD8, 0x8A }
|
{ 0xCC, 0xCE, 0xD4, 0xD6, 0xD8, 0x8A }
|
||||||
};
|
};
|
||||||
|
int stopDma = 0;
|
||||||
|
|
||||||
// ISR data
|
// ISR data
|
||||||
|
int isrInstalled = 0;
|
||||||
static _go32_dpmi_seginfo oldBlasterHandler, newBlasterHandler;
|
static _go32_dpmi_seginfo oldBlasterHandler, newBlasterHandler;
|
||||||
int writePage = 0;
|
int writePage = 0;
|
||||||
|
|
||||||
@@ -87,14 +91,13 @@ static soundblaster_getSampleProc getSamples;
|
|||||||
|
|
||||||
static void writeDSP(uint8_t value) {
|
static void writeDSP(uint8_t value) {
|
||||||
while((inportb(baseAddress + BLASTER_WRITE_PORT) &
|
while((inportb(baseAddress + BLASTER_WRITE_PORT) &
|
||||||
BLASTER_WRITE_BUFFER_STATUS_UNAVAIL) != 0)
|
BLASTER_WRITE_BUFFER_STATUS_UNAVAIL) != 0) {}
|
||||||
;
|
|
||||||
|
|
||||||
outportb(baseAddress + BLASTER_WRITE_PORT, value);
|
outportb(baseAddress + BLASTER_WRITE_PORT, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int resetBlaster() {
|
static int resetBlaster(void) {
|
||||||
for(int j = 0; j < 1000; ++j) {
|
for(int j = 0; j < 1000; ++j) {
|
||||||
outportb(baseAddress + BLASTER_RESET_PORT, 1);
|
outportb(baseAddress + BLASTER_RESET_PORT, 1);
|
||||||
delay(1);
|
delay(1);
|
||||||
@@ -112,19 +115,24 @@ static int resetBlaster() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void soundblasterISR() {
|
static void soundblasterISR(void) {
|
||||||
outportb(baseAddress + BLASTER_MIXER_OUT_PORT,
|
if(stopDma == 1) {
|
||||||
BLASTER_MIXER_INTERRUPT_STATUS);
|
writeDSP(BLASTER_EXIT_AUTO_DMA);
|
||||||
uint8_t status = inportb(baseAddress + BLASTER_MIXER_IN_PORT);
|
stopDma = 2;
|
||||||
|
} else {
|
||||||
|
outportb(baseAddress + BLASTER_MIXER_OUT_PORT,
|
||||||
|
BLASTER_MIXER_INTERRUPT_STATUS);
|
||||||
|
uint8_t status = inportb(baseAddress + BLASTER_MIXER_IN_PORT);
|
||||||
|
|
||||||
if(status & BLASTER_16BIT_INTERRUPT) {
|
if(status & BLASTER_16BIT_INTERRUPT) {
|
||||||
uint8_t* dst = (uint8_t*)(sampleBuffer)
|
uint8_t* dst = (uint8_t*)(sampleBuffer)
|
||||||
+ writePage * SAMPLE_BUFFER_SIZE / 2;
|
+ writePage * SAMPLE_BUFFER_SIZE / 2;
|
||||||
|
|
||||||
memcpy(dst, getSamples(), SAMPLE_BUFFER_SIZE / 2);
|
memcpy(dst, getSamples(), SAMPLE_BUFFER_SIZE / 2);
|
||||||
|
|
||||||
writePage = 1 - writePage;
|
writePage = 1 - writePage;
|
||||||
inportb(baseAddress + BLASTER_INTERRUPT_ACKNOWLEDGE_16BIT);
|
inportb(baseAddress + BLASTER_INTERRUPT_ACKNOWLEDGE_16BIT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(irq >= 8) {
|
if(irq >= 8) {
|
||||||
@@ -134,7 +142,7 @@ static void soundblasterISR() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void setBlasterISR() {
|
static void setBlasterISR(void) {
|
||||||
// Map IRQ to interrupt number on the CPU
|
// Map IRQ to interrupt number on the CPU
|
||||||
uint16_t interruptVector = irq + irq + (irq < 8)
|
uint16_t interruptVector = irq + irq + (irq < 8)
|
||||||
? PIC_IRQ07_MAP
|
? PIC_IRQ07_MAP
|
||||||
@@ -156,6 +164,8 @@ static void setBlasterISR() {
|
|||||||
uint8_t irqmask = inportb(PIC2_DATA);
|
uint8_t irqmask = inportb(PIC2_DATA);
|
||||||
outportb(PIC2_DATA, irqmask & ~(1<<(irq-8)));
|
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;
|
static int maxRetries = 10;
|
||||||
int selectors[maxRetries];
|
int selectors[maxRetries];
|
||||||
int current;
|
int current;
|
||||||
@@ -211,11 +221,16 @@ static int allocSampleBuffer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void turnSpeakerOn() {
|
static void turnSpeakerOn(void) {
|
||||||
writeDSP(BLASTER_SPEAKER_ON_CMD);
|
writeDSP(BLASTER_SPEAKER_ON_CMD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void turnSpeakerOff(void) {
|
||||||
|
writeDSP(BLASTER_SPEAKER_OFF_CMD);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dmaSetupTransfer(int channel,
|
static void dmaSetupTransfer(int channel,
|
||||||
uint8_t direction,
|
uint8_t direction,
|
||||||
bool autoReload,
|
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 offset = (uint32_t)sampleBuffer;
|
||||||
|
|
||||||
uint32_t samples = SAMPLE_BUFFER_SIZE / sizeof(int16_t);
|
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