MCB1700_Welcome/audio.c

153 lines
4.3 KiB
C

/*! @file audio.c
@brief play sound
@author Lukas Fürderer
@version V1.0
@date 15.11.2020
This file contains the main app function and init.
*/
#include "audio.h"
#include "Board_DAC.h"
#include "Board_GLCD.h"
#include "LPC17xx.h"
#include "melody.h"
#include "Welcome.h"
#define FREQ(x) ((x & 0xffff0000) >> 16)
#define WAVES(x) (x & 0xffff)
struct AudioState
{
bool highState;
uint16_t u16RemainingWaves;
uint32_t u32EndBreak;
const uint32_t *cpu32NextAction;
uint32_t u32StackPointer;
const uint32_t *cpu32Stack[10];
const char *cpcExpectedText;
};
volatile static struct AudioState sAudioState;
bool bPerformAudioStep()
{
bool bSuccess = true;
sAudioState.highState = !sAudioState.highState;
if (sAudioState.highState)
{
if (sAudioState.u16RemainingWaves > 0)
{
DAC_SetValue((u32Volume << 6));
}
else
{
if (FREQ(*sAudioState.cpu32NextAction) == 0)
{
// GOTO
sAudioState.highState = false;
sAudioState.cpu32NextAction = cppu32JumpLabels[*sAudioState.cpu32NextAction];
bSuccess = false;
}
else if (FREQ(*sAudioState.cpu32NextAction) == 1)
{
// CALL
sAudioState.highState = false;
sAudioState.cpu32Stack[sAudioState.u32StackPointer] = sAudioState.cpu32NextAction + 1;
sAudioState.cpu32NextAction = cppu32JumpLabels[WAVES(*sAudioState.cpu32NextAction)];
sAudioState.u32StackPointer++;
bSuccess = false;
}
else if (FREQ(*sAudioState.cpu32NextAction) == 2)
{
// RETURN
sAudioState.highState = false;
sAudioState.u32StackPointer--;
sAudioState.cpu32NextAction = sAudioState.cpu32Stack[sAudioState.u32StackPointer];
bSuccess = false;
}
else if (FREQ(*sAudioState.cpu32NextAction) == 3)
{
// PAUSE
sAudioState.highState = false;
LPC_TIM0->MR0 = WAVES(*sAudioState.cpu32NextAction) << 12;
sAudioState.cpu32NextAction++;
}
else if (FREQ(*sAudioState.cpu32NextAction) == 4)
{
// TEXT
sAudioState.highState = false;
sAudioState.cpcExpectedText = cpcTexts[WAVES(*sAudioState.cpu32NextAction)];
sAudioState.cpu32NextAction++;
bSuccess = false;
}
else
{
DAC_SetValue(512);
uint32_t u32Frequency = FREQ(*sAudioState.cpu32NextAction);
LPC_TIM0->MR0 = u32Frequency * 2;
uint32_t u32Waves = WAVES(*sAudioState.cpu32NextAction);
sAudioState.u16RemainingWaves = u32Waves * 9 / 10 - 1;
sAudioState.u32EndBreak = u32Waves * u32Frequency * 2 / 5;
sAudioState.cpu32NextAction++;
}
}
}
else
{
DAC_SetValue(0);
sAudioState.u16RemainingWaves--;
if (sAudioState.u16RemainingWaves == 0)
{
LPC_TIM0->MR0 = sAudioState.u32EndBreak;
}
}
return bSuccess;
}
void vUpdateLyrics()
{
static const char *cpcCurrentText = 0;
if (cpcCurrentText == 0)
{
cpcCurrentText = cpcTexts[0];
}
const char *cpcExpectedText = sAudioState.cpcExpectedText;
if (cpcCurrentText != cpcExpectedText)
{
GLCD_DrawString(0, 213, cpcExpectedText);
cpcCurrentText = cpcExpectedText;
}
}
void TIMER0_IRQHandler()
{
LPC_TIM0->IR = 0x1; // acknowledge interrupt
while (!bPerformAudioStep())
{
}
}
// Initializes the interrupt-driven audio output
void vStartAudio()
{
sAudioState.highState = false;
sAudioState.u16RemainingWaves = 0;
sAudioState.cpu32NextAction = cpu32EntryPoint;
sAudioState.u32StackPointer = 0;
sAudioState.cpcExpectedText = cpcTexts[0];
// Init timerinterrupt 0 (20 ms)
LPC_SC->PCONP |= (1 << 2); // turn on
LPC_SC->PCLKSEL0 |= (1 << 2); // select clock
LPC_TIM0->MR0 = 100000 * 2 - 1;
LPC_TIM0->MCR = 0x3;
NVIC_SetPriority(TIMER0_IRQn, 1U); // priority
NVIC_EnableIRQ(TIMER0_IRQn);
LPC_TIM0->TCR = 1; // start music
}