Basic output working
This commit is contained in:
@@ -104,7 +104,7 @@ function love.run()
|
|||||||
love.graphics.clear()
|
love.graphics.clear()
|
||||||
if love.draw then love.draw() end
|
if love.draw then love.draw() end
|
||||||
love.graphics.present()
|
love.graphics.present()
|
||||||
love.mixer.mix()
|
love.sound.mix()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -22,10 +22,10 @@ typedef struct {
|
|||||||
|
|
||||||
/* Each mask should consist of its unique bit and the unique bit of all its
|
/* Each mask should consist of its unique bit and the unique bit of all its
|
||||||
* super classes */
|
* super classes */
|
||||||
#define LUAOBJ_TYPE_IMAGE (1 << 0)
|
#define LUAOBJ_TYPE_IMAGE (1 << 0)
|
||||||
#define LUAOBJ_TYPE_QUAD (1 << 1)
|
#define LUAOBJ_TYPE_QUAD (1 << 1)
|
||||||
#define LUAOBJ_TYPE_FONT (1 << 2)
|
#define LUAOBJ_TYPE_FONT (1 << 2)
|
||||||
#define LUAOBJ_TYPE_SOUND (1 << 3)
|
#define LUAOBJ_TYPE_SOURCE (1 << 3)
|
||||||
|
|
||||||
|
|
||||||
int luaobj_newclass(lua_State *L, const char *name, const char *extends,
|
int luaobj_newclass(lua_State *L, const char *name, const char *extends,
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
/* Init everything */
|
/* Init everything */
|
||||||
atexit(deinit);
|
atexit(deinit);
|
||||||
vga_init();
|
soundblaster_init(mixer_getNextBlock);
|
||||||
|
//vga_init();
|
||||||
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();
|
||||||
|
|||||||
53
src/mixer.c
53
src/mixer.c
@@ -4,45 +4,50 @@
|
|||||||
#include "mixer.h"
|
#include "mixer.h"
|
||||||
#include "soundblaster.h"
|
#include "soundblaster.h"
|
||||||
|
|
||||||
#define MIXER_MAX_SOUNDS 8
|
#define MIXER_MAX_SOURCES 8
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int offset;
|
int offset;
|
||||||
sound_t const *sound;
|
source_t const *source;
|
||||||
} mixed_sound_t;
|
} mixed_sound_t;
|
||||||
|
|
||||||
static mixed_sound_t sounds[MIXER_MAX_SOUNDS];
|
|
||||||
static int activeSounds = 0;
|
static mixed_sound_t sources[MIXER_MAX_SOURCES];
|
||||||
|
static int activeSources = 0;
|
||||||
static int16_t data[SOUNDBLASTER_SAMPLES_PER_BUFFER] = {0};
|
static int16_t data[SOUNDBLASTER_SAMPLES_PER_BUFFER] = {0};
|
||||||
static bool canmix = true;
|
static bool canmix = true;
|
||||||
|
|
||||||
|
|
||||||
void mixer_init(void) {
|
void mixer_init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int16_t const * mixer_getNextBlock(void) {
|
int16_t const * mixer_getNextBlock(void) {
|
||||||
canmix = true;
|
canmix = true;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void mixer_play(sound_t const *sound) {
|
void mixer_play(source_t const *source) {
|
||||||
if(activeSounds == MIXER_MAX_SOUNDS) {
|
if(activeSources == MIXER_MAX_SOURCES) {
|
||||||
// TODO Replace older sound with new one instead?
|
// TODO Replace older source with new one instead?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < activeSounds; ++i) {
|
for(int i = 0; i < activeSources; ++i) {
|
||||||
if(sounds[i].sound == sound) {
|
if(sources[i].source == source) {
|
||||||
sounds[i].offset = 0;
|
sources[i].offset = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sounds[activeSounds].offset = 0;
|
sources[activeSources].offset = 0;
|
||||||
sounds[activeSounds].sound = sound;
|
sources[activeSources].source = source;
|
||||||
++activeSounds;
|
++activeSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int16_t mix(int32_t a, int32_t b) {
|
static inline int16_t mix(int32_t a, int32_t b) {
|
||||||
int32_t res = a + b;
|
int32_t res = a + b;
|
||||||
if(res > INT16_MAX)
|
if(res > INT16_MAX)
|
||||||
@@ -59,30 +64,28 @@ void mixer_mix(void) {
|
|||||||
|
|
||||||
memset(data, 0, SOUNDBLASTER_SAMPLES_PER_BUFFER);
|
memset(data, 0, SOUNDBLASTER_SAMPLES_PER_BUFFER);
|
||||||
|
|
||||||
for(int i = 0; i < activeSounds; ++i) {
|
for(int i = 0; i < activeSources; ++i) {
|
||||||
mixed_sound_t *snd = sounds + i;
|
mixed_sound_t *snd = sources + i;
|
||||||
int len = snd->sound->sampleCount;
|
int len = snd->source->sampleCount;
|
||||||
int16_t const* soundBuf = snd->sound->samples;
|
int16_t const* sourceBuf = snd->source->samples;
|
||||||
|
|
||||||
if(len > SOUNDBLASTER_SAMPLES_PER_BUFFER) {
|
if(len > SOUNDBLASTER_SAMPLES_PER_BUFFER) {
|
||||||
len = SOUNDBLASTER_SAMPLES_PER_BUFFER;
|
len = SOUNDBLASTER_SAMPLES_PER_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int offset = 0; offset < len; ++offset) {
|
for(int offset = 0; offset < len; ++offset) {
|
||||||
data[offset] = mix(data[offset], soundBuf[offset]);
|
data[offset] = mix(data[offset], sourceBuf[offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
snd->offset += len;
|
snd->offset += len;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for(int i = activeSounds-1; i >= 0; --i) {
|
for(int i = activeSources-1; i >= 0; --i) {
|
||||||
mixed_sound_t *snd = sounds + i;
|
mixed_sound_t *snd = sources + i;
|
||||||
if(snd->offset == snd->sound->sampleCount) {
|
if(snd->offset == snd->source->sampleCount) {
|
||||||
*snd = sounds[activeSounds-1];
|
*snd = sources[activeSources-1];
|
||||||
--activeSounds;
|
--activeSources;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "sound.h"
|
#include "source.h"
|
||||||
|
|
||||||
|
|
||||||
void mixer_init(void);
|
void mixer_init(void);
|
||||||
void mixer_deinit(void);
|
void mixer_deinit(void);
|
||||||
int16_t const* mixer_getNextBlock(void);
|
int16_t const* mixer_getNextBlock(void);
|
||||||
void mixer_play(sound_t const *sound);
|
void mixer_play(source_t const *source);
|
||||||
void mixer_mix(void);
|
void mixer_mix(void);
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ int luaopen_graphics(lua_State *L);
|
|||||||
int luaopen_timer(lua_State *L);
|
int luaopen_timer(lua_State *L);
|
||||||
int luaopen_keyboard(lua_State *L);
|
int luaopen_keyboard(lua_State *L);
|
||||||
int luaopen_mouse(lua_State *L);
|
int luaopen_mouse(lua_State *L);
|
||||||
int luaopen_mixer(lua_State *L);
|
|
||||||
int luaopen_sound(lua_State *L);
|
int luaopen_sound(lua_State *L);
|
||||||
|
int luaopen_source(lua_State *L);
|
||||||
|
|
||||||
int luaopen_love(lua_State *L) {
|
int luaopen_love(lua_State *L) {
|
||||||
int i;
|
int i;
|
||||||
@@ -38,6 +38,7 @@ int luaopen_love(lua_State *L) {
|
|||||||
luaopen_image,
|
luaopen_image,
|
||||||
luaopen_quad,
|
luaopen_quad,
|
||||||
luaopen_font,
|
luaopen_font,
|
||||||
|
luaopen_source,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
for (i = 0; classes[i]; i++) {
|
for (i = 0; classes[i]; i++) {
|
||||||
@@ -61,8 +62,7 @@ int luaopen_love(lua_State *L) {
|
|||||||
{ "timer", luaopen_timer },
|
{ "timer", luaopen_timer },
|
||||||
{ "keyboard", luaopen_keyboard },
|
{ "keyboard", luaopen_keyboard },
|
||||||
{ "mouse", luaopen_mouse },
|
{ "mouse", luaopen_mouse },
|
||||||
{ "mixer", luaopen_mixer },
|
{ "sound", luaopen_sound },
|
||||||
{ "sound", luaopen_mixer },
|
|
||||||
{ 0 },
|
{ 0 },
|
||||||
};
|
};
|
||||||
for (i = 0; mods[i].name; i++) {
|
for (i = 0; mods[i].name; i++) {
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "mixer.h"
|
|
||||||
#include "luaobj.h"
|
|
||||||
|
|
||||||
|
|
||||||
int l_mixer_mix(lua_State *L) {
|
|
||||||
mixer_mix();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int luaopen_mixer(lua_State *L) {
|
|
||||||
luaL_Reg reg[] = {
|
|
||||||
{ "mix", l_mixer_mix },
|
|
||||||
{ 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
luaL_newlib(L, reg);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -1,47 +1,23 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "luaobj.h"
|
|
||||||
#include "sound.h"
|
|
||||||
#include "mixer.h"
|
#include "mixer.h"
|
||||||
|
#include "luaobj.h"
|
||||||
|
|
||||||
|
|
||||||
#define CLASS_TYPE LUAOBJ_TYPE_SOUND
|
int l_sound_mix(lua_State *L) {
|
||||||
#define CLASS_NAME "Sound"
|
mixer_mix();
|
||||||
|
|
||||||
|
|
||||||
int l_sound_new(lua_State *L) {
|
|
||||||
const char *filename = luaL_checkstring(L, 1);
|
|
||||||
|
|
||||||
sound_t *self = luaobj_newudata(L, sizeof(*self));
|
|
||||||
luaobj_setclass(L, CLASS_TYPE, CLASS_NAME);
|
|
||||||
const char *err = sound_init(self, filename);
|
|
||||||
if (err) luaL_error(L, err);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l_sound_gc(lua_State *L) {
|
|
||||||
sound_t *self = luaobj_checkudata(L, 1, CLASS_TYPE);
|
|
||||||
sound_deinit(self);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int l_sound_play(lua_State *L) {
|
|
||||||
sound_t *self = luaobj_checkudata(L, 1, CLASS_TYPE);
|
|
||||||
mixer_play(self);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int l_source_new(lua_State *L);
|
||||||
|
|
||||||
int luaopen_sound(lua_State *L) {
|
int luaopen_sound(lua_State *L) {
|
||||||
luaL_Reg reg[] = {
|
luaL_Reg reg[] = {
|
||||||
{ "new", l_sound_new },
|
{ "mix", l_sound_mix },
|
||||||
{ "__gc", l_sound_gc },
|
{ "newSource", l_source_new },
|
||||||
{ "play", l_sound_play },
|
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
luaobj_newclass(L, CLASS_NAME, NULL, l_sound_new, reg);
|
luaL_newlib(L, reg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
47
src/modules/l_source.c
Normal file
47
src/modules/l_source.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "luaobj.h"
|
||||||
|
#include "source.h"
|
||||||
|
#include "mixer.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define CLASS_TYPE LUAOBJ_TYPE_SOURCE
|
||||||
|
#define CLASS_NAME "Source"
|
||||||
|
|
||||||
|
|
||||||
|
int l_source_new(lua_State *L) {
|
||||||
|
const char *filename = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
source_t *self = luaobj_newudata(L, sizeof(*self));
|
||||||
|
luaobj_setclass(L, CLASS_TYPE, CLASS_NAME);
|
||||||
|
const char *err = source_init(self, filename);
|
||||||
|
if (err) luaL_error(L, err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int l_source_gc(lua_State *L) {
|
||||||
|
source_t *self = luaobj_checkudata(L, 1, CLASS_TYPE);
|
||||||
|
source_deinit(self);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int l_source_play(lua_State *L) {
|
||||||
|
source_t *self = luaobj_checkudata(L, 1, CLASS_TYPE);
|
||||||
|
mixer_play(self);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaopen_source(lua_State *L) {
|
||||||
|
luaL_Reg reg[] = {
|
||||||
|
{ "new", l_source_new },
|
||||||
|
{ "__gc", l_source_gc },
|
||||||
|
{ "play", l_source_play },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
luaobj_newclass(L, CLASS_NAME, NULL, l_source_new, reg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
51
src/sound.c
51
src/sound.c
@@ -1,51 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "sound.h"
|
|
||||||
#include "lib/dmt/dmt.h"
|
|
||||||
#define STB_VORBIS_HEADER_ONLY 1
|
|
||||||
#include "lib/stb/stb_vorbis.c"
|
|
||||||
|
|
||||||
|
|
||||||
int sound_initSilence(sound_t *self, int samples) {
|
|
||||||
self->sampleCount = samples;
|
|
||||||
self->samples = (int16_t*)dmt_malloc(samples * sizeof(int16_t));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char const* sound_init(sound_t *self, char const* filename) {
|
|
||||||
short *buffer;
|
|
||||||
int channels;
|
|
||||||
int samplingRate;
|
|
||||||
char const* err = NULL;
|
|
||||||
|
|
||||||
int len = stb_vorbis_decode_filename(filename, &channels, &samplingRate, &buffer);
|
|
||||||
if(len == -1) {
|
|
||||||
return "could not decode Vorbis file";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(channels != 1) {
|
|
||||||
err = "only single channel audio files supported";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(samplingRate != 22050) {
|
|
||||||
err = "only 22050Hz audio files suported";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bufSize = len * sizeof(int16_t);
|
|
||||||
self->samples = (int16_t*)dmt_malloc(bufSize);
|
|
||||||
memcpy(self->samples, buffer, bufSize);
|
|
||||||
|
|
||||||
fail:
|
|
||||||
free(buffer);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void sound_deinit(sound_t *self) {
|
|
||||||
dmt_free(self->samples);
|
|
||||||
}
|
|
||||||
|
|
||||||
19
src/sound.h
19
src/sound.h
@@ -1,19 +0,0 @@
|
|||||||
#ifndef SOUND_H
|
|
||||||
#define SOUND_H
|
|
||||||
|
|
||||||
|
|
||||||
#define SOUND_ERROR_DECODE 1
|
|
||||||
#define SOUND_ERROR_CHANNEL_COUNT 2
|
|
||||||
#define SOUND_ERROR_SAMPLING_RATE 3
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int sampleCount;
|
|
||||||
int16_t *samples;
|
|
||||||
} sound_t;
|
|
||||||
|
|
||||||
int sound_initSilence(sound_t *self, int samples);
|
|
||||||
char const* sound_init(sound_t *self, char const* filename);
|
|
||||||
void sound_deinit(sound_t *self);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -16,6 +16,7 @@ static int sampleBufferSelector;
|
|||||||
static uint16_t baseAddress;
|
static uint16_t baseAddress;
|
||||||
static uint16_t irq;
|
static uint16_t irq;
|
||||||
static uint16_t dmaChannel;
|
static uint16_t dmaChannel;
|
||||||
|
int isrcount = 0;
|
||||||
|
|
||||||
#define SAMPLE_BUFFER_SIZE (SOUNDBLASTER_SAMPLES_PER_BUFFER * sizeof(uint16_t) * 2)
|
#define SAMPLE_BUFFER_SIZE (SOUNDBLASTER_SAMPLES_PER_BUFFER * sizeof(uint16_t) * 2)
|
||||||
|
|
||||||
@@ -89,6 +90,7 @@ int writePage = 0;
|
|||||||
|
|
||||||
static soundblaster_getSampleProc getSamples;
|
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) {}
|
||||||
@@ -97,34 +99,41 @@ static void writeDSP(uint8_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t readDSP() {
|
||||||
|
uint8_t status;
|
||||||
|
while(((status = inportb(baseAddress + BLASTER_READ_BUFFER_STATUS_PORT))
|
||||||
|
& BLASTER_READ_BUFFER_STATUS_AVAIL) == 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return inportb(baseAddress + BLASTER_READ_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int resetBlaster(void) {
|
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);
|
||||||
outportb(baseAddress + BLASTER_RESET_PORT, 0);
|
outportb(baseAddress + BLASTER_RESET_PORT, 0);
|
||||||
uint8_t status;
|
|
||||||
|
|
||||||
while(((status = inportb(baseAddress + BLASTER_READ_BUFFER_STATUS_PORT))
|
if(readDSP() == BLASTER_READY_BYTE) {
|
||||||
& BLASTER_READ_BUFFER_STATUS_AVAIL) == 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
if(inportb(baseAddress + BLASTER_READ_PORT) == BLASTER_READY_BYTE)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return SOUNDBLASTER_RESET_ERROR;
|
return SOUNDBLASTER_RESET_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void soundblasterISR(void) {
|
static void soundblasterISR(void) {
|
||||||
if(stopDma == 1) {
|
outportb(baseAddress + BLASTER_MIXER_OUT_PORT,
|
||||||
writeDSP(BLASTER_EXIT_AUTO_DMA);
|
BLASTER_MIXER_INTERRUPT_STATUS);
|
||||||
stopDma = 2;
|
uint8_t status = inportb(baseAddress + BLASTER_MIXER_IN_PORT);
|
||||||
} 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) {
|
isrcount++;
|
||||||
|
if(status & BLASTER_16BIT_INTERRUPT) {
|
||||||
|
if(stopDma == 1) {
|
||||||
|
writeDSP(BLASTER_EXIT_AUTO_DMA);
|
||||||
|
stopDma = 2;
|
||||||
|
} else {
|
||||||
uint8_t* dst = (uint8_t*)(sampleBuffer)
|
uint8_t* dst = (uint8_t*)(sampleBuffer)
|
||||||
+ writePage * SAMPLE_BUFFER_SIZE / 2;
|
+ writePage * SAMPLE_BUFFER_SIZE / 2;
|
||||||
|
|
||||||
@@ -175,12 +184,19 @@ static int parseBlasterSettings(void) {
|
|||||||
return SOUNDBLASTER_ENV_NOT_SET;
|
return SOUNDBLASTER_ENV_NOT_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = sscanf(blasterEnv, "A%hu I%hu D%hu", &baseAddress, &irq, &dmaChannel);
|
int res = sscanf(blasterEnv, "A%hx I%hu", &baseAddress, &irq);
|
||||||
|
if(res < 2) {
|
||||||
if(res < 3) {
|
|
||||||
return SOUNDBLASTER_ENV_INVALID;
|
return SOUNDBLASTER_ENV_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "H" field may be preceeded by any number of other fields, so let's just search it
|
||||||
|
char const *dmaLoc = strchr(blasterEnv, 'H');
|
||||||
|
if(dmaLoc == NULL) {
|
||||||
|
return SOUNDBLASTER_ENV_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmaChannel = atoi(dmaLoc+1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,13 +257,17 @@ static void dmaSetupTransfer(int channel,
|
|||||||
|
|
||||||
uint8_t modeByte = direction
|
uint8_t modeByte = direction
|
||||||
| mode
|
| mode
|
||||||
| (uint8_t)autoReload << 4
|
| ((uint8_t)autoReload << 4)
|
||||||
| (uint8_t)down << 5
|
| ((uint8_t)down << 5)
|
||||||
| (channel & 0x03);
|
| (channel & 0x03);
|
||||||
|
|
||||||
uint8_t maskEnable = (channel & 0x03) | 0x04;
|
uint8_t maskEnable = (channel & 0x03) | 0x04;
|
||||||
|
|
||||||
uint32_t offset = startAddress;
|
uint32_t offset = startAddress;
|
||||||
|
|
||||||
|
// Special handling of 16 bit DMA channels:
|
||||||
|
// The DMA controller needs offset and count to be half the actual value and
|
||||||
|
// internally doubles it again
|
||||||
if(channel > 3) {
|
if(channel > 3) {
|
||||||
offset >>= 1;
|
offset >>= 1;
|
||||||
count >>= 1;
|
count >>= 1;
|
||||||
@@ -268,7 +288,7 @@ static void dmaSetupTransfer(int channel,
|
|||||||
|
|
||||||
|
|
||||||
static void startDMAOutput(void) {
|
static void startDMAOutput(void) {
|
||||||
uint32_t offset = (uint32_t)sampleBuffer;
|
uint32_t offset = ((uint32_t)sampleBuffer) - __djgpp_conventional_base;
|
||||||
|
|
||||||
uint32_t samples = SAMPLE_BUFFER_SIZE / sizeof(int16_t);
|
uint32_t samples = SAMPLE_BUFFER_SIZE / sizeof(int16_t);
|
||||||
|
|
||||||
@@ -295,24 +315,28 @@ int soundblaster_init(soundblaster_getSampleProc getsamplesproc) {
|
|||||||
|
|
||||||
int err = parseBlasterSettings();
|
int err = parseBlasterSettings();
|
||||||
if(err != 0) {
|
if(err != 0) {
|
||||||
|
fprintf(stderr, "BLASTER environment variable not set or invalid\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = resetBlaster();
|
err = resetBlaster();
|
||||||
if(err != 0) {
|
if(err != 0) {
|
||||||
|
fprintf(stderr, "Could not reset Soundblaster\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = allocSampleBuffer();
|
err = allocSampleBuffer();
|
||||||
if(err != 0) {
|
if(err != 0) {
|
||||||
|
fprintf(stderr, "Could not allocate sample buffer in conventional memory\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSamples = getsamplesproc;
|
||||||
|
|
||||||
setBlasterISR();
|
setBlasterISR();
|
||||||
turnSpeakerOn();
|
turnSpeakerOn();
|
||||||
startDMAOutput();
|
startDMAOutput();
|
||||||
|
|
||||||
getSamples = getsamplesproc;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
src/source.c
Normal file
24
src/source.c
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "source.h"
|
||||||
|
#include "lib/dmt/dmt.h"
|
||||||
|
#include "wavefile.h"
|
||||||
|
|
||||||
|
|
||||||
|
int source_initSilence(source_t *self, int samples) {
|
||||||
|
self->sampleCount = samples;
|
||||||
|
self->samples = (int16_t*)dmt_malloc(samples * sizeof(int16_t));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char const* source_init(source_t *self, char const* filename) {
|
||||||
|
return wavefile_load(self, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void source_deinit(source_t *self) {
|
||||||
|
dmt_free(self->samples);
|
||||||
|
}
|
||||||
|
|
||||||
16
src/source.h
Normal file
16
src/source.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef SOURCE_H
|
||||||
|
#define SOURCE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int sampleCount;
|
||||||
|
int16_t *samples;
|
||||||
|
} source_t;
|
||||||
|
|
||||||
|
int source_initSilence(source_t *self, int samples);
|
||||||
|
char const* source_init(source_t *self, char const* filename);
|
||||||
|
void source_deinit(source_t *self);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
90
src/wavefile.c
Normal file
90
src/wavefile.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "wavefile.h"
|
||||||
|
#include "source.h"
|
||||||
|
#include "lib/dmt/dmt.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t chunkId;
|
||||||
|
uint32_t chunkSize;
|
||||||
|
uint32_t format;
|
||||||
|
uint32_t subchunk1Id;
|
||||||
|
uint32_t subchunk1Size;
|
||||||
|
uint16_t audioFormat;
|
||||||
|
uint16_t numChannels;
|
||||||
|
uint32_t sampleRate;
|
||||||
|
uint32_t byteRate;
|
||||||
|
uint16_t blockAlign;
|
||||||
|
uint16_t bitsPerSample;
|
||||||
|
uint32_t subchunk2Id;
|
||||||
|
uint32_t subchunk2Size;
|
||||||
|
} waveheader_t;
|
||||||
|
|
||||||
|
#define RIFF_CHUNK_ID 0x46464952
|
||||||
|
#define WAVE_FORMAT 0x45564157
|
||||||
|
#define FORMAT_CHUNK_ID 0x20746d66
|
||||||
|
#define DATA_CHUNK_ID 0x61746164
|
||||||
|
#define FORMAT_CHUNK_SIZE 16
|
||||||
|
#define AUDIO_FORMAT_PCM 1
|
||||||
|
|
||||||
|
|
||||||
|
char const* wavefile_load(source_t *source, char const *filename) {
|
||||||
|
int fileSize;
|
||||||
|
char const *err = 0;
|
||||||
|
uint8_t *waveData = filesystem_read(filename, &fileSize);
|
||||||
|
|
||||||
|
waveheader_t const* header = (waveheader_t const*)waveData;
|
||||||
|
|
||||||
|
if(header->chunkId != RIFF_CHUNK_ID
|
||||||
|
|| header->format != WAVE_FORMAT
|
||||||
|
|| header->subchunk1Id != FORMAT_CHUNK_ID
|
||||||
|
|| header->subchunk2Id != DATA_CHUNK_ID) {
|
||||||
|
err = "Invalid WAV header";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header->subchunk1Size != FORMAT_CHUNK_SIZE
|
||||||
|
|| header->audioFormat != AUDIO_FORMAT_PCM) {
|
||||||
|
err = "Invalid Audio Format (only PCM supported)";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header->numChannels != 1) {
|
||||||
|
err = "Invalid Audio Format (only 1 channel supported)";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header->sampleRate != 22050) {
|
||||||
|
err = "Invalid Audio Format (only 22050Hz supported)";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header->bitsPerSample != 16) {
|
||||||
|
err = "Invalid Audio Format (only 16 Bit supported)";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header->byteRate != header->sampleRate * header->numChannels * header->bitsPerSample / 8) {
|
||||||
|
err = "Byte rate doesn't match header info";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(header->blockAlign != header->numChannels * header->bitsPerSample / 8) {
|
||||||
|
err = "Block alignment doesn't match header info";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fileSize < sizeof(waveheader_t) + header->subchunk2Size) {
|
||||||
|
err = "Short read while reading samples";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
source->sampleCount = header->subchunk2Size / 2;
|
||||||
|
source->samples = (int16_t*)dmt_malloc(header->subchunk2Size);
|
||||||
|
|
||||||
|
memcpy(source->samples, ((uint8_t*)waveData) + sizeof(waveheader_t), header->subchunk2Size);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
filesystem_free(waveData);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
5
src/wavefile.h
Normal file
5
src/wavefile.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "source.h"
|
||||||
|
|
||||||
|
char const* wavefile_load(source_t *source, char const *filename);
|
||||||
Reference in New Issue
Block a user