Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions video/agon.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#define PACKET_MOUSE 0x09 // Mouse data

#define AUDIO_CHANNELS 3 // Default number of audio channels
#define AUDIO_DEFAULT_SAMPLE_RATE 16384 // Default sample rate
#define MAX_AUDIO_CHANNELS 32 // Maximum number of audio channels
#define PLAY_SOUND_PRIORITY 3 // Sound driver task priority with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest

Expand All @@ -84,6 +85,9 @@
#define AUDIO_CMD_ENABLE 8 // Enables a channel
#define AUDIO_CMD_DISABLE 9 // Disables (destroys) a channel
#define AUDIO_CMD_RESET 10 // Reset audio channel
#define AUDIO_CMD_SEEK 11 // Seek to a position in a sample
#define AUDIO_CMD_DURATION 12 // Set the duration of a channel
#define AUDIO_CMD_SAMPLERATE 13 // Set the samplerate for channel or underlying audio system

#define AUDIO_WAVE_DEFAULT 0 // Default waveform (Square wave)
#define AUDIO_WAVE_SQUARE 0 // Square wave
Expand All @@ -97,11 +101,22 @@

#define AUDIO_SAMPLE_LOAD 0 // Send a sample to the VDP
#define AUDIO_SAMPLE_CLEAR 1 // Clear/delete a sample
#define AUDIO_SAMPLE_FROM_BUFFER 2 // Load a sample from a buffer
#define AUDIO_SAMPLE_FROM_BUFFER 2 // Load a sample from a buffer
#define AUDIO_SAMPLE_SET_FREQUENCY 3 // Set the base frequency of a sample
#define AUDIO_SAMPLE_BUFFER_SET_FREQUENCY 4 // Set the base frequency of a sample (using buffer ID)
#define AUDIO_SAMPLE_SET_REPEAT_START 5 // Set the repeat start point of a sample
#define AUDIO_SAMPLE_BUFFER_SET_REPEAT_START 6 // Set the repeat start point of a sample (using buffer ID)
#define AUDIO_SAMPLE_SET_REPEAT_LENGTH 7 // Set the repeat length of a sample
#define AUDIO_SAMPLE_BUFFER_SET_REPEAT_LENGTH 8 // Set the repeat length of a sample (using buffer ID)
#define AUDIO_SAMPLE_DEBUG_INFO 0x10 // Get debug info about a sample

#define AUDIO_DEFAULT_FREQUENCY 523 // Default sample frequency (C5, or C above middle C)

#define AUDIO_FORMAT_8BIT_SIGNED 0 // 8-bit signed sample
#define AUDIO_FORMAT_8BIT_UNSIGNED 1 // 8-bit unsigned sample
#define AUDIO_FORMAT_DATA_MASK 7 // data bit mask for format
#define AUDIO_FORMAT_WITH_RATE 8 // OR this with the format to indicate a sample rate follows
#define AUDIO_FORMAT_TUNEABLE 16 // OR this with the format to indicate sample can be tuned (frequency adjustable)

#define AUDIO_ENVELOPE_NONE 0 // No envelope
#define AUDIO_ENVELOPE_ADSR 1 // Simple ADSR volume envelope
Expand All @@ -118,12 +133,14 @@
#define AUDIO_STATUS_HAS_VOLUME_ENVELOPE 0x08 // Channel has a volume envelope set
#define AUDIO_STATUS_HAS_FREQUENCY_ENVELOPE 0x10 // Channel has a frequency envelope set

#define AUDIO_STATE_IDLE 0 // Channel is idle/silent
#define AUDIO_STATE_PENDING 1 // Channel is pending (note will be played next loop call)
#define AUDIO_STATE_PLAYING 2 // Channel is playing a note (passive)
#define AUDIO_STATE_PLAY_LOOP 3 // Channel is in active note playing loop
#define AUDIO_STATE_RELEASE 4 // Channel is releasing a note
#define AUDIO_STATE_ABORT 5 // Channel is aborting a note
enum AudioState : uint8_t { // Audio channel state
Idle = 0, // currently idle/silent
Pending, // note will be played next loop call
Playing, // playing (passive)
PlayLoop, // active playing loop (used when an envelope is active)
Release, // in "release" phase
Abort // aborting a note
};

// Mouse commands
#define MOUSE_ENABLE 0 // Enable mouse
Expand Down
68 changes: 47 additions & 21 deletions video/agon_audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,27 @@
#include "types.h"

// audio channels and their associated tasks
std::unordered_map<uint8_t, std::shared_ptr<audio_channel>> audio_channels;
std::unordered_map<uint8_t, std::shared_ptr<AudioChannel>> audioChannels;
std::vector<TaskHandle_t, psram_allocator<TaskHandle_t>> audioHandlers;

std::unordered_map<uint16_t, std::shared_ptr<audio_sample>> samples; // Storage for the sample data
std::unordered_map<uint16_t, std::shared_ptr<AudioSample>> samples; // Storage for the sample data

fabgl::SoundGenerator SoundGenerator; // The audio class
std::unique_ptr<fabgl::SoundGenerator> soundGenerator; // audio handling sub-system

// Audio channel driver task
//
void audio_driver(void * parameters) {
void audioDriver(void * parameters) {
uint8_t channel = *(uint8_t *)parameters;

audio_channels[channel] = make_shared_psram<audio_channel>(channel);
audioChannels[channel] = make_shared_psram<AudioChannel>(channel);
while (true) {
audio_channels[channel]->loop();
audioChannels[channel]->loop();
vTaskDelay(1);
}
}

void init_audio_channel(uint8_t channel) {
xTaskCreatePinnedToCore(audio_driver, "audio_driver",
void initAudioChannel(uint8_t channel) {
xTaskCreatePinnedToCore(audioDriver, "audioDriver",
4096, // This stack size can be checked & adjusted by reading the Stack Highwater
&channel, // Parameters
PLAY_SOUND_PRIORITY, // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
Expand All @@ -59,35 +59,61 @@ void audioTaskKill(uint8_t channel) {
if (audioHandlers[channel]) {
vTaskDelete(audioHandlers[channel]);
audioHandlers[channel] = nullptr;
audio_channels.erase(channel);
audioChannels.erase(channel);
debug_log("audioTaskKill: channel %d killed\n\r", channel);
} else {
debug_log("audioTaskKill: channel %d not found\n\r", channel);
}
}

// Change the sample rate
//
void setSampleRate(uint16_t sampleRate) {
// make a new sound generator and re-attach all our active channels
if (sampleRate == 65535) {
sampleRate = AUDIO_DEFAULT_SAMPLE_RATE;
}
// detach the old sound generator
if (soundGenerator) {
soundGenerator->play(false);
for (auto channelPair : audioChannels) {
auto channel = channelPair.second;
channel->detachSoundGenerator();
}
}
// delete the old sound generator
soundGenerator = nullptr;
soundGenerator = std::unique_ptr<fabgl::SoundGenerator>(new fabgl::SoundGenerator(sampleRate));
for (auto channelPair : audioChannels) {
auto channel = channelPair.second;
channel->attachSoundGenerator();
}
soundGenerator->play(true);
}

// Initialise the sound driver
//
void init_audio() {
void initAudio() {
// make new sound generator
setSampleRate(AUDIO_DEFAULT_SAMPLE_RATE);
audioHandlers.reserve(MAX_AUDIO_CHANNELS);
debug_log("init_audio: we have reserved %d channels\n\r", audioHandlers.capacity());
debug_log("initAudio: we have reserved %d channels\n\r", audioHandlers.capacity());
for (uint8_t i = 0; i < AUDIO_CHANNELS; i++) {
init_audio_channel(i);
initAudioChannel(i);
}
SoundGenerator.play(true);
}

// Channel enabled?
//
bool channelEnabled(uint8_t channel) {
return channel < MAX_AUDIO_CHANNELS && audio_channels[channel];
return channel < MAX_AUDIO_CHANNELS && audioChannels[channel];
}

// Play a note
//
uint8_t play_note(uint8_t channel, uint8_t volume, uint16_t frequency, uint16_t duration) {
uint8_t playNote(uint8_t channel, uint8_t volume, uint16_t frequency, uint16_t duration) {
if (channelEnabled(channel)) {
return audio_channels[channel]->play_note(volume, frequency, duration);
return audioChannels[channel]->playNote(volume, frequency, duration);
}
return 1;
}
Expand All @@ -96,7 +122,7 @@ uint8_t play_note(uint8_t channel, uint8_t volume, uint16_t frequency, uint16_t
//
uint8_t getChannelStatus(uint8_t channel) {
if (channelEnabled(channel)) {
return audio_channels[channel]->getStatus();
return audioChannels[channel]->getStatus();
}
return -1;
}
Expand All @@ -105,23 +131,23 @@ uint8_t getChannelStatus(uint8_t channel) {
//
void setVolume(uint8_t channel, uint8_t volume) {
if (channelEnabled(channel)) {
audio_channels[channel]->setVolume(volume);
audioChannels[channel]->setVolume(volume);
}
}

// Set channel frequency
//
void setFrequency(uint8_t channel, uint16_t frequency) {
if (channelEnabled(channel)) {
audio_channels[channel]->setFrequency(frequency);
audioChannels[channel]->setFrequency(frequency);
}
}

// Set channel waveform
//
void setWaveform(uint8_t channel, int8_t waveformType, uint16_t sampleId) {
if (channelEnabled(channel)) {
auto channelRef = audio_channels[channel];
auto channelRef = audioChannels[channel];
channelRef->setWaveform(waveformType, channelRef, sampleId);
}
}
Expand All @@ -134,7 +160,7 @@ uint8_t clearSample(uint16_t sampleId) {
debug_log("clearSample: sample %d not found\n\r", sampleId);
return 0;
}
samples.erase(sampleId);
samples[sampleId] = nullptr;
debug_log("reset sample\n\r");
return 1;
}
Expand Down
Loading