// // Created by Wouter Groeneveld on 07/08/18. // #ifndef GBA_SPRITE_ENGINE_SOUND_H #define GBA_SPRITE_ENGINE_SOUND_H #include #include #include #include #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 const void* data; 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 reset(); 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 std::unique_ptr channelAControl(); static std::unique_ptr channelBControl(); static std::unique_ptr soundControl(SoundChannel channel) { return channel == ChannelA ? channelAControl() : channelBControl(); }; }; #endif //GBA_SPRITE_ENGINE_SOUND_H