153 lines
4.3 KiB
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
|
|
}
|