Platform library for RETRO
Sound.h@0:6f26c31d8573, 2015-03-01 (annotated)
- Committer:
- Architect
- Date:
- Sun Mar 01 05:29:45 2015 +0000
- Revision:
- 0:6f26c31d8573
RetroPlatform Library for RETRO gaming system
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Architect | 0:6f26c31d8573 | 1 | /* |
Architect | 0:6f26c31d8573 | 2 | * (C) Copyright 2015 Valentin Ivanov. All rights reserved. |
Architect | 0:6f26c31d8573 | 3 | * |
Architect | 0:6f26c31d8573 | 4 | * This file is part of the RetroPlatform Library |
Architect | 0:6f26c31d8573 | 5 | * |
Architect | 0:6f26c31d8573 | 6 | * The RetroPlatform Library is free software: you can redistribute it and/or modify |
Architect | 0:6f26c31d8573 | 7 | * it under the terms of the GNU Lesser General Public License as published by |
Architect | 0:6f26c31d8573 | 8 | * the Free Software Foundation, either version 3 of the License, or |
Architect | 0:6f26c31d8573 | 9 | * (at your option) any later version. |
Architect | 0:6f26c31d8573 | 10 | * |
Architect | 0:6f26c31d8573 | 11 | * This program is distributed in the hope that it will be useful, |
Architect | 0:6f26c31d8573 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
Architect | 0:6f26c31d8573 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
Architect | 0:6f26c31d8573 | 14 | * GNU Lesser General Public License for more details. |
Architect | 0:6f26c31d8573 | 15 | * |
Architect | 0:6f26c31d8573 | 16 | * You should have received a copy of the GNU Lesser General Public License |
Architect | 0:6f26c31d8573 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/> |
Architect | 0:6f26c31d8573 | 18 | * |
Architect | 0:6f26c31d8573 | 19 | * This library is inspired by Gamebuino Library (http://gamebuino.com) |
Architect | 0:6f26c31d8573 | 20 | * from Aurélien Rodot. |
Architect | 0:6f26c31d8573 | 21 | */ |
Architect | 0:6f26c31d8573 | 22 | #ifndef SOUND_H |
Architect | 0:6f26c31d8573 | 23 | #define SOUND_H |
Architect | 0:6f26c31d8573 | 24 | |
Architect | 0:6f26c31d8573 | 25 | #include <mbed.h> |
Architect | 0:6f26c31d8573 | 26 | |
Architect | 0:6f26c31d8573 | 27 | //commands |
Architect | 0:6f26c31d8573 | 28 | #define CMD_VOLUME 0 |
Architect | 0:6f26c31d8573 | 29 | #define CMD_INSTRUMENT 1 |
Architect | 0:6f26c31d8573 | 30 | #define CMD_SLIDE 2 |
Architect | 0:6f26c31d8573 | 31 | #define CMD_ARPEGGIO 3 |
Architect | 0:6f26c31d8573 | 32 | #define CMD_TREMOLO 4 |
Architect | 0:6f26c31d8573 | 33 | |
Architect | 0:6f26c31d8573 | 34 | |
Architect | 0:6f26c31d8573 | 35 | #define NUM_CHANNELS 3 //number of sound channels (no more than 4) |
Architect | 0:6f26c31d8573 | 36 | |
Architect | 0:6f26c31d8573 | 37 | #define VOLUME_GLOBAL_MAX 1 |
Architect | 0:6f26c31d8573 | 38 | |
Architect | 0:6f26c31d8573 | 39 | //7=instrument volume 9=note volume |
Architect | 0:6f26c31d8573 | 40 | #define VOLUME_CHANNEL_MAX 255/NUM_CHANNELS/VOLUME_GLOBAL_MAX/7/9 |
Architect | 0:6f26c31d8573 | 41 | |
Architect | 0:6f26c31d8573 | 42 | #define boolean bool |
Architect | 0:6f26c31d8573 | 43 | |
Architect | 0:6f26c31d8573 | 44 | //A set of sequences |
Architect | 0:6f26c31d8573 | 45 | typedef struct { |
Architect | 0:6f26c31d8573 | 46 | uint16_t *Data; |
Architect | 0:6f26c31d8573 | 47 | uint8_t Cursor; |
Architect | 0:6f26c31d8573 | 48 | bool IsPlaying; |
Architect | 0:6f26c31d8573 | 49 | } Track; |
Architect | 0:6f26c31d8573 | 50 | |
Architect | 0:6f26c31d8573 | 51 | //A sequence of commands and notes |
Architect | 0:6f26c31d8573 | 52 | typedef struct { |
Architect | 0:6f26c31d8573 | 53 | uint16_t *Data; |
Architect | 0:6f26c31d8573 | 54 | bool Looping; |
Architect | 0:6f26c31d8573 | 55 | uint16_t Cursor; |
Architect | 0:6f26c31d8573 | 56 | bool IsPlaying; |
Architect | 0:6f26c31d8573 | 57 | } Sequence; |
Architect | 0:6f26c31d8573 | 58 | |
Architect | 0:6f26c31d8573 | 59 | //A note of selected pitch, duration and volume |
Architect | 0:6f26c31d8573 | 60 | typedef struct { |
Architect | 0:6f26c31d8573 | 61 | uint8_t Pitch; |
Architect | 0:6f26c31d8573 | 62 | uint8_t Duration; |
Architect | 0:6f26c31d8573 | 63 | int8_t Volume; |
Architect | 0:6f26c31d8573 | 64 | bool IsPlaying; |
Architect | 0:6f26c31d8573 | 65 | } Note; |
Architect | 0:6f26c31d8573 | 66 | |
Architect | 0:6f26c31d8573 | 67 | typedef struct { |
Architect | 0:6f26c31d8573 | 68 | int8_t Counter; |
Architect | 0:6f26c31d8573 | 69 | int8_t volumeSlideStepDuration; |
Architect | 0:6f26c31d8573 | 70 | int8_t volumeSlideStepSize; |
Architect | 0:6f26c31d8573 | 71 | uint8_t arpeggioStepDuration; |
Architect | 0:6f26c31d8573 | 72 | int8_t arpeggioStepSize; |
Architect | 0:6f26c31d8573 | 73 | uint8_t tremoloStepDuration; |
Architect | 0:6f26c31d8573 | 74 | int8_t tremoloStepSize; |
Architect | 0:6f26c31d8573 | 75 | |
Architect | 0:6f26c31d8573 | 76 | } Command; |
Architect | 0:6f26c31d8573 | 77 | |
Architect | 0:6f26c31d8573 | 78 | typedef struct { |
Architect | 0:6f26c31d8573 | 79 | uint16_t **SequenceSet; |
Architect | 0:6f26c31d8573 | 80 | uint16_t **InstrumentSet; |
Architect | 0:6f26c31d8573 | 81 | |
Architect | 0:6f26c31d8573 | 82 | uint8_t Volume; |
Architect | 0:6f26c31d8573 | 83 | uint8_t Count; |
Architect | 0:6f26c31d8573 | 84 | bool State; |
Architect | 0:6f26c31d8573 | 85 | uint8_t HalfPeriod; |
Architect | 0:6f26c31d8573 | 86 | uint8_t OutputVolume; |
Architect | 0:6f26c31d8573 | 87 | uint8_t Output; |
Architect | 0:6f26c31d8573 | 88 | bool Noise; |
Architect | 0:6f26c31d8573 | 89 | |
Architect | 0:6f26c31d8573 | 90 | |
Architect | 0:6f26c31d8573 | 91 | |
Architect | 0:6f26c31d8573 | 92 | int8_t SequencePitch; |
Architect | 0:6f26c31d8573 | 93 | } AudioChannel; |
Architect | 0:6f26c31d8573 | 94 | |
Architect | 0:6f26c31d8573 | 95 | typedef struct { |
Architect | 0:6f26c31d8573 | 96 | uint16_t *Data; |
Architect | 0:6f26c31d8573 | 97 | uint8_t Length; |
Architect | 0:6f26c31d8573 | 98 | uint8_t Looping; |
Architect | 0:6f26c31d8573 | 99 | uint16_t Cursor; |
Architect | 0:6f26c31d8573 | 100 | uint8_t NextChange; |
Architect | 0:6f26c31d8573 | 101 | } Instrument; |
Architect | 0:6f26c31d8573 | 102 | |
Architect | 0:6f26c31d8573 | 103 | class Sound { |
Architect | 0:6f26c31d8573 | 104 | |
Architect | 0:6f26c31d8573 | 105 | Ticker timer; |
Architect | 0:6f26c31d8573 | 106 | PwmOut speaker; |
Architect | 0:6f26c31d8573 | 107 | |
Architect | 0:6f26c31d8573 | 108 | Track tracks[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 109 | Sequence sequences[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 110 | Command commands[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 111 | Instrument instruments[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 112 | |
Architect | 0:6f26c31d8573 | 113 | public: |
Architect | 0:6f26c31d8573 | 114 | Sound(); |
Architect | 0:6f26c31d8573 | 115 | void initialize(); |
Architect | 0:6f26c31d8573 | 116 | |
Architect | 0:6f26c31d8573 | 117 | void update() |
Architect | 0:6f26c31d8573 | 118 | { |
Architect | 0:6f26c31d8573 | 119 | updateTracks(); |
Architect | 0:6f26c31d8573 | 120 | updateSequences(); |
Architect | 0:6f26c31d8573 | 121 | updateNotes(); |
Architect | 0:6f26c31d8573 | 122 | } |
Architect | 0:6f26c31d8573 | 123 | |
Architect | 0:6f26c31d8573 | 124 | void playTrack(const uint16_t* track, uint8_t channel); |
Architect | 0:6f26c31d8573 | 125 | void updateTrack(uint8_t channel); |
Architect | 0:6f26c31d8573 | 126 | void stopTrack(uint8_t channel); |
Architect | 0:6f26c31d8573 | 127 | void stopTracks() { |
Architect | 0:6f26c31d8573 | 128 | for(uint8_t channel=0; channel<NUM_CHANNELS; channel++) |
Architect | 0:6f26c31d8573 | 129 | stopTrack(channel); |
Architect | 0:6f26c31d8573 | 130 | } |
Architect | 0:6f26c31d8573 | 131 | void updateTracks() { |
Architect | 0:6f26c31d8573 | 132 | for(uint8_t channel=0; channel<NUM_CHANNELS; channel++) |
Architect | 0:6f26c31d8573 | 133 | updateTrack(channel); |
Architect | 0:6f26c31d8573 | 134 | } |
Architect | 0:6f26c31d8573 | 135 | |
Architect | 0:6f26c31d8573 | 136 | void changeSequenceSet(const uint16_t* const* patterns, uint8_t channel); |
Architect | 0:6f26c31d8573 | 137 | |
Architect | 0:6f26c31d8573 | 138 | bool isTrackPlaying(uint8_t channel) |
Architect | 0:6f26c31d8573 | 139 | { |
Architect | 0:6f26c31d8573 | 140 | return tracks[channel].IsPlaying; |
Architect | 0:6f26c31d8573 | 141 | } |
Architect | 0:6f26c31d8573 | 142 | |
Architect | 0:6f26c31d8573 | 143 | void playSequence(const uint16_t* pattern, uint8_t channel); |
Architect | 0:6f26c31d8573 | 144 | void changeInstrumentSet(const uint16_t* const* instruments, uint8_t channel); |
Architect | 0:6f26c31d8573 | 145 | void updateSequence(uint8_t channel); |
Architect | 0:6f26c31d8573 | 146 | void stopSequence(uint8_t channel); |
Architect | 0:6f26c31d8573 | 147 | void stopSequences() { |
Architect | 0:6f26c31d8573 | 148 | for(uint8_t channel=0; channel<NUM_CHANNELS; channel++) |
Architect | 0:6f26c31d8573 | 149 | stopSequence(channel); |
Architect | 0:6f26c31d8573 | 150 | } |
Architect | 0:6f26c31d8573 | 151 | void updateSequences() { |
Architect | 0:6f26c31d8573 | 152 | for(uint8_t channel=0; channel<NUM_CHANNELS; channel++) |
Architect | 0:6f26c31d8573 | 153 | updateSequence(channel); |
Architect | 0:6f26c31d8573 | 154 | } |
Architect | 0:6f26c31d8573 | 155 | |
Architect | 0:6f26c31d8573 | 156 | |
Architect | 0:6f26c31d8573 | 157 | void playNote(uint8_t pitch, uint8_t duration, uint8_t channel); |
Architect | 0:6f26c31d8573 | 158 | void updateNote(uint8_t i); |
Architect | 0:6f26c31d8573 | 159 | void stopNote(uint8_t channel); |
Architect | 0:6f26c31d8573 | 160 | void updateNotes() { |
Architect | 0:6f26c31d8573 | 161 | for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) |
Architect | 0:6f26c31d8573 | 162 | updateNote(channel); |
Architect | 0:6f26c31d8573 | 163 | } |
Architect | 0:6f26c31d8573 | 164 | void stopNotes() { |
Architect | 0:6f26c31d8573 | 165 | for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) |
Architect | 0:6f26c31d8573 | 166 | stopNote(channel); |
Architect | 0:6f26c31d8573 | 167 | } |
Architect | 0:6f26c31d8573 | 168 | |
Architect | 0:6f26c31d8573 | 169 | void command(uint8_t cmd, uint8_t X, int8_t Y, uint8_t channel); |
Architect | 0:6f26c31d8573 | 170 | |
Architect | 0:6f26c31d8573 | 171 | uint8_t outputPitch[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 172 | int8_t outputVolume[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 173 | |
Architect | 0:6f26c31d8573 | 174 | void setVolume(int8_t volume); |
Architect | 0:6f26c31d8573 | 175 | uint8_t getVolume(); |
Architect | 0:6f26c31d8573 | 176 | void setVolume(int8_t volume, uint8_t channel); |
Architect | 0:6f26c31d8573 | 177 | uint8_t getVolume(uint8_t channel); |
Architect | 0:6f26c31d8573 | 178 | |
Architect | 0:6f26c31d8573 | 179 | |
Architect | 0:6f26c31d8573 | 180 | uint8_t prescaler; |
Architect | 0:6f26c31d8573 | 181 | |
Architect | 0:6f26c31d8573 | 182 | void setChannelHalfPeriod(uint8_t channel, uint8_t halfPeriod); |
Architect | 0:6f26c31d8573 | 183 | |
Architect | 0:6f26c31d8573 | 184 | |
Architect | 0:6f26c31d8573 | 185 | uint8_t globalVolume; |
Architect | 0:6f26c31d8573 | 186 | uint8_t volumeMax; |
Architect | 0:6f26c31d8573 | 187 | |
Architect | 0:6f26c31d8573 | 188 | #if (NUM_CHANNELS > 0) |
Architect | 0:6f26c31d8573 | 189 | //tracks data |
Architect | 0:6f26c31d8573 | 190 | uint16_t **patternSet[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 191 | int8_t patternPitch[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 192 | |
Architect | 0:6f26c31d8573 | 193 | // pattern data |
Architect | 0:6f26c31d8573 | 194 | uint16_t **instrumentSet[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 195 | |
Architect | 0:6f26c31d8573 | 196 | // note data |
Architect | 0:6f26c31d8573 | 197 | uint8_t notePitch[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 198 | uint8_t noteDuration[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 199 | int8_t noteVolume[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 200 | boolean notePlaying[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 201 | |
Architect | 0:6f26c31d8573 | 202 | |
Architect | 0:6f26c31d8573 | 203 | //current step data |
Architect | 0:6f26c31d8573 | 204 | int8_t stepVolume[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 205 | uint8_t stepPitch[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 206 | |
Architect | 0:6f26c31d8573 | 207 | uint8_t chanVolumes[NUM_CHANNELS]; |
Architect | 0:6f26c31d8573 | 208 | |
Architect | 0:6f26c31d8573 | 209 | |
Architect | 0:6f26c31d8573 | 210 | uint8_t _chanCount[NUM_CHANNELS]; //counts until the next change of the waveform |
Architect | 0:6f26c31d8573 | 211 | boolean _chanState[NUM_CHANNELS]; //if the waveform is currently high or low |
Architect | 0:6f26c31d8573 | 212 | uint8_t _chanHalfPeriod[NUM_CHANNELS]; //duration of half the period of the waveform |
Architect | 0:6f26c31d8573 | 213 | uint8_t _chanOutputVolume[NUM_CHANNELS]; //amplitude of the outputted waveform |
Architect | 0:6f26c31d8573 | 214 | uint8_t _chanOutput[NUM_CHANNELS]; //current value of the outputted waveform |
Architect | 0:6f26c31d8573 | 215 | boolean _chanNoise[NUM_CHANNELS]; //if a random value should be added to the waveform to generate noise |
Architect | 0:6f26c31d8573 | 216 | |
Architect | 0:6f26c31d8573 | 217 | #endif |
Architect | 0:6f26c31d8573 | 218 | void updateOutput(); |
Architect | 0:6f26c31d8573 | 219 | |
Architect | 0:6f26c31d8573 | 220 | private: |
Architect | 0:6f26c31d8573 | 221 | void generateOutput(); |
Architect | 0:6f26c31d8573 | 222 | }; |
Architect | 0:6f26c31d8573 | 223 | |
Architect | 0:6f26c31d8573 | 224 | #endif /* SOUND_H */ |