fixes to sound engine
This commit is contained in:
parent
a9c8f4e5ef
commit
88c62bcab5
|
@ -2,7 +2,7 @@ SET(CMAKE_C_COMPILER arm-none-eabi-gcc)
|
|||
SET(CMAKE_CXX_COMPILER arm-none-eabi-g++)
|
||||
|
||||
set_property(SOURCE engine/gba/sin_lut.s PROPERTY LANGUAGE C)
|
||||
add_executable(${PROJECT_NAME}.elf main.cpp engine/sprites/sprite_manager.cpp engine/sprites/sprite_manager.h engine/gba/tonc_memmap.h engine/gba/tonc_core.h engine/gba/tonc_memdef.h engine/gba/tonc_types.h engine/sprites/sprite.cpp engine/sprites/sprite.h kul.h engine/palette/palette_manager.cpp engine/palette/palette_manager.h engine/palette/combined_palette.cpp engine/palette/combined_palette.h engine/allocator.cpp engine/allocator.h engine/gba/tonc_oam.h engine/gba/tonc_math.h engine/gba/sin_lut.s engine/Scene.cpp engine/Scene.h engine/sprites/sprite_builder.cpp engine/sprites/sprite_builder.h engine/sprites/affine_sprite.cpp engine/sprites/affine_sprite.h flying_stuff_scene.cpp flying_stuff_scene.h engine/gba_engine.cpp engine/gba_engine.h engine/background/text_stream.cpp engine/background/text_stream.h engine/background/background.cpp engine/background/background.h engine/background/text.h sample_start_scene.cpp sample_start_scene.h engine/effects/fade_out_scene.cpp engine/effects/fade_out_scene.h engine/gba/tonc_core_stub.h engine/effects/scene_effect.h lama.h sample_sound.h)
|
||||
add_executable(${PROJECT_NAME}.elf main.cpp engine/sprites/sprite_manager.cpp engine/sprites/sprite_manager.h engine/gba/tonc_memmap.h engine/gba/tonc_core.h engine/gba/tonc_memdef.h engine/gba/tonc_types.h engine/sprites/sprite.cpp engine/sprites/sprite.h kul.h engine/palette/palette_manager.cpp engine/palette/palette_manager.h engine/palette/combined_palette.cpp engine/palette/combined_palette.h engine/allocator.cpp engine/allocator.h engine/gba/tonc_oam.h engine/gba/tonc_math.h engine/gba/sin_lut.s engine/Scene.cpp engine/Scene.h engine/sprites/sprite_builder.cpp engine/sprites/sprite_builder.h engine/sprites/affine_sprite.cpp engine/sprites/affine_sprite.h flying_stuff_scene.cpp flying_stuff_scene.h engine/gba_engine.cpp engine/gba_engine.h engine/background/text_stream.cpp engine/background/text_stream.h engine/background/background.cpp engine/background/background.h engine/background/text.h sample_start_scene.cpp sample_start_scene.h engine/effects/fade_out_scene.cpp engine/effects/fade_out_scene.h engine/gba/tonc_core_stub.h engine/effects/scene_effect.h lama.h sample_sound.h engine/sound.h engine/sound.cpp)
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
|
||||
COMMAND ${CMAKE_OBJCOPY} -v -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.gba
|
||||
|
|
|
@ -7,90 +7,80 @@
|
|||
#include "gba_engine.h"
|
||||
#include "allocator.h"
|
||||
|
||||
int x = 0;
|
||||
SoundControl* GBAEngine::activeChannelA;
|
||||
SoundControl* GBAEngine::activeChannelB;
|
||||
|
||||
void GBAEngine::vsync() {
|
||||
while (REG_VCOUNT >= 160);
|
||||
while (REG_VCOUNT < 160);
|
||||
}
|
||||
|
||||
void GBAEngine::onVBlank() {
|
||||
REG_IME = 0;
|
||||
stopOnVBlank();
|
||||
|
||||
unsigned short tempInterruptState = REG_IF;
|
||||
|
||||
if((REG_IF & INTERRUPT_VBLANK) == INTERRUPT_VBLANK) {
|
||||
// if vblanks_remaning is zero: stop
|
||||
//*sound_control &= ~(SOUND_B_RIGHT_CHANNEL | SOUND_B_LEFT_CHANNEL | SOUND_B_FIFO_RESET);
|
||||
//*dma2_control = 0;
|
||||
// else counter--
|
||||
// OR: to restart sound (channelA)
|
||||
if(GBAEngine::activeChannelA && GBAEngine::activeChannelA->done()) {
|
||||
|
||||
|
||||
x++;
|
||||
}
|
||||
|
||||
//TextStream::instance() << x;
|
||||
REG_IF = tempInterruptState;
|
||||
REG_IME = 1;
|
||||
}
|
||||
|
||||
void GBAEngine::update() {
|
||||
vsync();
|
||||
|
||||
if(sceneToTransitionTo) {
|
||||
currentEffectForTransition->update();
|
||||
|
||||
if(currentEffectForTransition->isDone()) {
|
||||
setScene(sceneToTransitionTo);
|
||||
}
|
||||
if(GBAEngine::activeChannelB) {
|
||||
if(GBAEngine::activeChannelB->done()) {
|
||||
GBAEngine::activeChannelB->disable();
|
||||
delete GBAEngine::activeChannelB;
|
||||
} else {
|
||||
GBAEngine::activeChannelB->step();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spriteManager.render();
|
||||
u16 keys = readKeys();
|
||||
this->currentScene->tick(keys);
|
||||
}
|
||||
|
||||
void GBAEngine::transitionIntoScene(Scene *scene, SceneEffect* effect) {
|
||||
sceneToTransitionTo = scene;
|
||||
currentEffectForTransition = effect;
|
||||
currentEffectForTransition->setSceneToAffect(this->currentScene);
|
||||
REG_IF = tempInterruptState;
|
||||
startOnVBlank();
|
||||
}
|
||||
|
||||
u16 GBAEngine::readKeys() {
|
||||
return ~REG_KEYS & KEY_ANY;
|
||||
}
|
||||
|
||||
SoundControl GBAEngine::channelAControl() {
|
||||
return {
|
||||
®_DMA1CNT,
|
||||
®_DMA1SAD,
|
||||
®_DMA1DAD,
|
||||
®_FIFOA,
|
||||
SDS_AR | SDS_AL | SDS_ARESET
|
||||
};
|
||||
void GBAEngine::dequeueAllSounds() {
|
||||
stopOnVBlank();
|
||||
|
||||
if(GBAEngine::activeChannelA) {
|
||||
GBAEngine::activeChannelA->disable();
|
||||
} if(GBAEngine::activeChannelB) {
|
||||
GBAEngine::activeChannelB->disable();
|
||||
}
|
||||
}
|
||||
|
||||
SoundControl GBAEngine::channelBControl() {
|
||||
return {
|
||||
®_DMA2CNT,
|
||||
®_DMA2SAD,
|
||||
®_DMA2DAD,
|
||||
®_FIFOB,
|
||||
SDS_BR | SDS_BL | SDS_BRESET
|
||||
};
|
||||
}
|
||||
void GBAEngine::enqueueSound(const s8 *data, int totalSamples, int sampleRate, SoundChannel channel) {
|
||||
SoundControl* control;
|
||||
stopOnVBlank();
|
||||
|
||||
if(channel == ChannelA) { // repeating bg music can be restarted
|
||||
if(GBAEngine::activeChannelA) delete GBAEngine::activeChannelA;
|
||||
control = SoundControl::channelAControl();
|
||||
GBAEngine::activeChannelA = control;
|
||||
} else { // sound still playing, don't stop that
|
||||
if(GBAEngine::activeChannelB) {
|
||||
if(!GBAEngine::activeChannelB->done()) return;
|
||||
delete GBAEngine::activeChannelB;
|
||||
}
|
||||
control = SoundControl::channelBControl();
|
||||
GBAEngine::activeChannelB = control;
|
||||
}
|
||||
|
||||
void GBAEngine::queueSound(const s8 *data, int totalSamples, int sampleRate, SoundControl control) {
|
||||
REG_TM0CNT = 0;
|
||||
*(control.DMAControl) = 0; // reset previous sound
|
||||
control->disable();
|
||||
|
||||
REG_SNDDSCNT |= control.ControlFlags; // output to both sides, reset fifo
|
||||
REG_SNDDSCNT |= control->getControlFlags(); // output to both sides, reset fifo
|
||||
REG_SNDSTAT = SSTAT_ENABLE; // enable all sound
|
||||
|
||||
*(control.DMASourceAddress) = (u32) data; // WARNING - these are pointers to the address!
|
||||
*(control.DMADestinationAddress) = (u32) control.FiFoBuffer;
|
||||
*(control.DMAControl) = DMA_DST_FIXED | DMA_REPEAT | DMA_32 | DMA_SYNC_TO_TIMER | DMA_ENABLE;
|
||||
|
||||
u16 ticksPerSample = CLOCK / sampleRate; // divide the clock (ticks/second) by the sample rate (samples/second)
|
||||
|
||||
REG_TM0D = OVERFLOW_16_BIT_VALUE - ticksPerSample;
|
||||
// channel_a_vblanks_remaining = total_samples * ticks_per_sample * (1.0 / CYCLES_PER_BLANK);
|
||||
control->accept(data, totalSamples, ticksPerSample);
|
||||
startOnVBlank();
|
||||
control->enable();
|
||||
|
||||
REG_TM0D = OVERFLOW_16_BIT_VALUE - ticksPerSample;
|
||||
REG_TM0CNT = TM_ENABLE | TM_FREQ_1; // enable timer - dma auto-syncs to this thanks to DMA_SYNC_TO_TIMER
|
||||
}
|
||||
|
||||
|
@ -98,16 +88,38 @@ GBAEngine::GBAEngine() {
|
|||
// setup screen control flags
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_OBJ | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_BG3;
|
||||
|
||||
// setup interrupt control flags for vblank IRQing
|
||||
// setup interrupt control flags for vblank IRQing (started only when sound played)
|
||||
REG_DISPSTAT |= DISPLAY_INTERRUPT_VBLANK_ENABLE;
|
||||
REG_IE |= INTERRUPT_VBLANK;
|
||||
*IRQ_CALLBACK = (u32) &GBAEngine::onVBlank;
|
||||
//REG_IME = 1;
|
||||
|
||||
REG_SNDDSCNT = 0;
|
||||
Allocator::free();
|
||||
}
|
||||
|
||||
void GBAEngine::update() {
|
||||
if(sceneToTransitionTo) {
|
||||
dequeueAllSounds();
|
||||
currentEffectForTransition->update();
|
||||
|
||||
if(currentEffectForTransition->isDone()) {
|
||||
setScene(sceneToTransitionTo);
|
||||
}
|
||||
}
|
||||
|
||||
u16 keys = readKeys();
|
||||
this->currentScene->tick(keys);
|
||||
|
||||
vsync();
|
||||
spriteManager.render();
|
||||
}
|
||||
|
||||
void GBAEngine::transitionIntoScene(Scene *scene, SceneEffect* effect) {
|
||||
sceneToTransitionTo = scene;
|
||||
currentEffectForTransition = effect;
|
||||
currentEffectForTransition->setSceneToAffect(this->currentScene);
|
||||
}
|
||||
|
||||
void GBAEngine::cleanupPreviousScene() {
|
||||
delete currentScene;
|
||||
sceneToTransitionTo = nullptr;
|
||||
|
|
|
@ -11,27 +11,7 @@
|
|||
#include <engine/gba/tonc_memdef.h>
|
||||
#include <engine/effects/scene_effect.h>
|
||||
#include "Scene.h"
|
||||
|
||||
#define CLOCK 16777216
|
||||
#define CYCLES_PER_BLANK 280806
|
||||
#define OVERFLOW_16_BIT_VALUE 65536
|
||||
#define DISPLAY_INTERRUPT_VBLANK_ENABLE 0x08
|
||||
#define INTERRUPT_VBLANK 0x1
|
||||
#define DMA_SYNC_TO_TIMER 0x30000000
|
||||
|
||||
#define IRQ_CALLBACK ((volatile unsigned int*) 0x3007FFC)
|
||||
|
||||
enum SoundChannel {
|
||||
ChannelA, ChannelB
|
||||
};
|
||||
|
||||
struct SoundControl {
|
||||
vu32* DMAControl; // ex. ®_DMA1CNT
|
||||
vu32* DMASourceAddress; // ex. ®_DMA1SAD
|
||||
vu32* DMADestinationAddress; // ex. ®_DMA1DAD
|
||||
vu32* FiFoBuffer; // ex. ®_FIFOA
|
||||
u16 ControlFlags;
|
||||
};
|
||||
#include "sound.h"
|
||||
|
||||
class GBAEngine {
|
||||
private:
|
||||
|
@ -42,18 +22,15 @@ private:
|
|||
|
||||
SpriteManager spriteManager;
|
||||
|
||||
void vsync() {
|
||||
while (REG_VCOUNT >= 160);
|
||||
while (REG_VCOUNT < 160);
|
||||
}
|
||||
SoundControl channelAControl();
|
||||
SoundControl channelBControl();
|
||||
SoundControl soundControl(SoundChannel channel) {
|
||||
return channel == ChannelA ? channelAControl() : channelBControl();
|
||||
};
|
||||
static SoundControl* activeChannelA;
|
||||
static SoundControl* activeChannelB;
|
||||
|
||||
void vsync();
|
||||
void cleanupPreviousScene();
|
||||
void queueSound(const s8* data, int totalSamples, int sampleRate, SoundControl control);
|
||||
void enqueueSound(const s8 *data, int totalSamples, int sampleRate, SoundChannel channel);
|
||||
|
||||
static void startOnVBlank() { REG_IME = 1; }
|
||||
static void stopOnVBlank() { REG_IME = 0; }
|
||||
static void onVBlank();
|
||||
|
||||
public:
|
||||
|
@ -62,11 +39,12 @@ public:
|
|||
void setScene(Scene* scene);
|
||||
void transitionIntoScene(Scene* scene, SceneEffect* effect);
|
||||
|
||||
void queueMusic(const s8* data, int totalSamples) {
|
||||
queueSound(data, totalSamples, 16000, soundControl(ChannelA));
|
||||
void dequeueAllSounds();
|
||||
void enqueueMusic(const s8 *data, int totalSamples) {
|
||||
enqueueSound(data, totalSamples, 16000, ChannelA);
|
||||
}
|
||||
void queueSound(const s8* data, int totalSamples) {
|
||||
queueSound(data, totalSamples, 16000, soundControl(ChannelB));
|
||||
void enqueueSound(const s8 *data, int totalSamples) {
|
||||
enqueueSound(data, totalSamples, 16000, ChannelB);
|
||||
}
|
||||
|
||||
u16 readKeys();
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 07/08/18.
|
||||
//
|
||||
|
||||
#include <engine/gba/tonc_memmap.h>
|
||||
#include "sound.h"
|
||||
|
||||
void SoundControl::accept(const void *data, int totalSamples, int ticksPerSample) {
|
||||
*DMASourceAddress = (u32) data;
|
||||
*DMADestinationAddress = (u32) FiFoBuffer;
|
||||
vblanksTotal = vblanksRemaning = totalSamples * ticksPerSample * (1.0 / CYCLES_PER_BLANK);
|
||||
};
|
||||
|
||||
SoundControl* SoundControl::channelAControl() {
|
||||
return new SoundControl{
|
||||
®_DMA1CNT,
|
||||
®_DMA1SAD,
|
||||
®_DMA1DAD,
|
||||
®_FIFOA,
|
||||
SDS_AR | SDS_AL | SDS_ARESET
|
||||
};
|
||||
}
|
||||
|
||||
SoundControl* SoundControl::channelBControl() {
|
||||
return new SoundControl{
|
||||
®_DMA2CNT,
|
||||
®_DMA2SAD,
|
||||
®_DMA2DAD,
|
||||
®_FIFOB,
|
||||
SDS_BR | SDS_BL | SDS_BRESET
|
||||
};
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 07/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SOUND_H
|
||||
#define GBA_SPRITE_ENGINE_SOUND_H
|
||||
|
||||
#include <engine/gba/tonc_types.h>
|
||||
#include <engine/gba/tonc_memdef.h>
|
||||
#include <memory>
|
||||
#include <engine/gba/tonc_memmap.h>
|
||||
|
||||
#define CLOCK 16777216
|
||||
#define CYCLES_PER_BLANK 280806
|
||||
#define OVERFLOW_16_BIT_VALUE 65536
|
||||
#define DISPLAY_INTERRUPT_VBLANK_ENABLE 0x08
|
||||
#define INTERRUPT_VBLANK 0x1
|
||||
#define DMA_SYNC_TO_TIMER 0x30000000
|
||||
|
||||
#define IRQ_CALLBACK ((volatile unsigned int*) 0x3007FFC)
|
||||
|
||||
enum SoundChannel {
|
||||
ChannelA, ChannelB
|
||||
};
|
||||
|
||||
class SoundControl {
|
||||
private:
|
||||
vu32* DMAControl; // ex. ®_DMA1CNT
|
||||
vu32* DMASourceAddress; // ex. ®_DMA1SAD
|
||||
vu32* DMADestinationAddress; // ex. ®_DMA1DAD
|
||||
vu32* FiFoBuffer; // ex. ®_FIFOA
|
||||
u16 controlFlags;
|
||||
u32 vblanksRemaning; // updated each vblank, counts down to 0
|
||||
u32 vblanksTotal; // calculated once when enqueueing
|
||||
|
||||
public:
|
||||
SoundControl(vu32* dma, vu32* src, vu32* dest, vu32* fifo, u16 flags)
|
||||
: DMAControl(dma), DMASourceAddress(src), DMADestinationAddress(dest), FiFoBuffer(fifo), controlFlags(flags), vblanksRemaning(0), vblanksTotal(0) {}
|
||||
|
||||
u16 getControlFlags() { return controlFlags; }
|
||||
u32 getVBlanksRemaning() { return vblanksRemaning; }
|
||||
void step() { vblanksRemaning--; }
|
||||
bool done() { return vblanksRemaning <= 0; }
|
||||
u32 getVBlanksTotal() { return vblanksTotal; }
|
||||
|
||||
void disable() {
|
||||
*(DMAControl) = 0;
|
||||
vblanksRemaning = 0;
|
||||
REG_SNDDSCNT &= ~(controlFlags);
|
||||
};
|
||||
void enable() {
|
||||
*DMAControl = DMA_DST_FIXED | DMA_REPEAT | DMA_32 | DMA_SYNC_TO_TIMER | DMA_ENABLE;
|
||||
};
|
||||
void accept(const void* data, int totalSamples, int ticksPerSample);
|
||||
|
||||
static SoundControl* channelAControl();
|
||||
static SoundControl* channelBControl();
|
||||
|
||||
static SoundControl* soundControl(SoundChannel channel) {
|
||||
return channel == ChannelA ? channelAControl() : channelBControl();
|
||||
};
|
||||
};
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_SOUND_H
|
|
@ -5,9 +5,7 @@
|
|||
#include <engine/palette/palette_manager.h>
|
||||
#include <engine/allocator.h>
|
||||
|
||||
#include "sample_sound.h"
|
||||
#include "sample_start_scene.h"
|
||||
#include "flying_stuff_scene.h"
|
||||
|
||||
/**
|
||||
* shared palette extracted from grit
|
||||
|
@ -21,8 +19,6 @@ int main() {
|
|||
startScene->setEngineForSceneSwitching(engine);
|
||||
engine->setScene(startScene);
|
||||
|
||||
engine->queueSound(zelda_secret_16K_mono, zelda_secret_16K_mono_bytes);
|
||||
|
||||
while (true) {
|
||||
engine->update();
|
||||
engine->delay(1000);
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include "sample_start_scene.h"
|
||||
#include "flying_stuff_scene.h"
|
||||
|
||||
#include "kul.h"
|
||||
#include "lama.h"
|
||||
#include "sample_sound.h"
|
||||
|
||||
std::vector<Background *> SampleStartScene::backgrounds() {
|
||||
return {};
|
||||
|
@ -34,6 +34,7 @@ void SampleStartScene::load() {
|
|||
.buildPtr();
|
||||
|
||||
TextStream::instance().setText("PRESS START", 3, 8);
|
||||
engine->enqueueSound(zelda_secret_16K_mono, zelda_secret_16K_mono_bytes);
|
||||
}
|
||||
|
||||
void SampleStartScene::tick(u16 keys) {
|
||||
|
|
Loading…
Reference in New Issue