Platform library for RETRO
Diff: Sound.h
- Revision:
- 0:6f26c31d8573
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sound.h Sun Mar 01 05:29:45 2015 +0000 @@ -0,0 +1,224 @@ +/* + * (C) Copyright 2015 Valentin Ivanov. All rights reserved. + * + * This file is part of the RetroPlatform Library + * + * The RetroPlatform Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + * This library is inspired by Gamebuino Library (http://gamebuino.com) + * from Aurélien Rodot. + */ +#ifndef SOUND_H +#define SOUND_H + +#include <mbed.h> + +//commands +#define CMD_VOLUME 0 +#define CMD_INSTRUMENT 1 +#define CMD_SLIDE 2 +#define CMD_ARPEGGIO 3 +#define CMD_TREMOLO 4 + + +#define NUM_CHANNELS 3 //number of sound channels (no more than 4) + +#define VOLUME_GLOBAL_MAX 1 + +//7=instrument volume 9=note volume +#define VOLUME_CHANNEL_MAX 255/NUM_CHANNELS/VOLUME_GLOBAL_MAX/7/9 + +#define boolean bool + +//A set of sequences +typedef struct { + uint16_t *Data; + uint8_t Cursor; + bool IsPlaying; +} Track; + +//A sequence of commands and notes +typedef struct { + uint16_t *Data; + bool Looping; + uint16_t Cursor; + bool IsPlaying; +} Sequence; + +//A note of selected pitch, duration and volume +typedef struct { + uint8_t Pitch; + uint8_t Duration; + int8_t Volume; + bool IsPlaying; +} Note; + +typedef struct { + int8_t Counter; + int8_t volumeSlideStepDuration; + int8_t volumeSlideStepSize; + uint8_t arpeggioStepDuration; + int8_t arpeggioStepSize; + uint8_t tremoloStepDuration; + int8_t tremoloStepSize; + +} Command; + +typedef struct { + uint16_t **SequenceSet; + uint16_t **InstrumentSet; + + uint8_t Volume; + uint8_t Count; + bool State; + uint8_t HalfPeriod; + uint8_t OutputVolume; + uint8_t Output; + bool Noise; + + + + int8_t SequencePitch; +} AudioChannel; + +typedef struct { + uint16_t *Data; + uint8_t Length; + uint8_t Looping; + uint16_t Cursor; + uint8_t NextChange; +} Instrument; + +class Sound { + + Ticker timer; + PwmOut speaker; + + Track tracks[NUM_CHANNELS]; + Sequence sequences[NUM_CHANNELS]; + Command commands[NUM_CHANNELS]; + Instrument instruments[NUM_CHANNELS]; + +public: + Sound(); + void initialize(); + + void update() + { + updateTracks(); + updateSequences(); + updateNotes(); + } + + void playTrack(const uint16_t* track, uint8_t channel); + void updateTrack(uint8_t channel); + void stopTrack(uint8_t channel); + void stopTracks() { + for(uint8_t channel=0; channel<NUM_CHANNELS; channel++) + stopTrack(channel); + } + void updateTracks() { + for(uint8_t channel=0; channel<NUM_CHANNELS; channel++) + updateTrack(channel); + } + + void changeSequenceSet(const uint16_t* const* patterns, uint8_t channel); + + bool isTrackPlaying(uint8_t channel) + { + return tracks[channel].IsPlaying; + } + + void playSequence(const uint16_t* pattern, uint8_t channel); + void changeInstrumentSet(const uint16_t* const* instruments, uint8_t channel); + void updateSequence(uint8_t channel); + void stopSequence(uint8_t channel); + void stopSequences() { + for(uint8_t channel=0; channel<NUM_CHANNELS; channel++) + stopSequence(channel); + } + void updateSequences() { + for(uint8_t channel=0; channel<NUM_CHANNELS; channel++) + updateSequence(channel); + } + + + void playNote(uint8_t pitch, uint8_t duration, uint8_t channel); + void updateNote(uint8_t i); + void stopNote(uint8_t channel); + void updateNotes() { + for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) + updateNote(channel); + } + void stopNotes() { + for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) + stopNote(channel); + } + + void command(uint8_t cmd, uint8_t X, int8_t Y, uint8_t channel); + + uint8_t outputPitch[NUM_CHANNELS]; + int8_t outputVolume[NUM_CHANNELS]; + + void setVolume(int8_t volume); + uint8_t getVolume(); + void setVolume(int8_t volume, uint8_t channel); + uint8_t getVolume(uint8_t channel); + + + uint8_t prescaler; + + void setChannelHalfPeriod(uint8_t channel, uint8_t halfPeriod); + + + uint8_t globalVolume; + uint8_t volumeMax; + +#if (NUM_CHANNELS > 0) + //tracks data + uint16_t **patternSet[NUM_CHANNELS]; + int8_t patternPitch[NUM_CHANNELS]; + + // pattern data + uint16_t **instrumentSet[NUM_CHANNELS]; + + // note data + uint8_t notePitch[NUM_CHANNELS]; + uint8_t noteDuration[NUM_CHANNELS]; + int8_t noteVolume[NUM_CHANNELS]; + boolean notePlaying[NUM_CHANNELS]; + + + //current step data + int8_t stepVolume[NUM_CHANNELS]; + uint8_t stepPitch[NUM_CHANNELS]; + + uint8_t chanVolumes[NUM_CHANNELS]; + + + uint8_t _chanCount[NUM_CHANNELS]; //counts until the next change of the waveform + boolean _chanState[NUM_CHANNELS]; //if the waveform is currently high or low + uint8_t _chanHalfPeriod[NUM_CHANNELS]; //duration of half the period of the waveform + uint8_t _chanOutputVolume[NUM_CHANNELS]; //amplitude of the outputted waveform + uint8_t _chanOutput[NUM_CHANNELS]; //current value of the outputted waveform + boolean _chanNoise[NUM_CHANNELS]; //if a random value should be added to the waveform to generate noise + +#endif + void updateOutput(); + +private: + void generateOutput(); +}; + +#endif /* SOUND_H */ \ No newline at end of file