Merge branch 'master' into dev
This commit is contained in:
		
						commit
						49fa0295e3
					
				|  | @ -0,0 +1,81 @@ | |||
| #include <MIDI.h> | ||||
| #include "noteList.h" | ||||
| #include "pitches.h" | ||||
| 
 | ||||
| #ifdef ARDUINO_SAM_DUE // Due has no tone function (yet), overriden to prevent build errors.
 | ||||
| #define tone(...) | ||||
| #define noTone(...) | ||||
| #endif | ||||
| 
 | ||||
| // This example shows how to make a simple synth out of an Arduino, using the
 | ||||
| // tone() function. It also outputs a gate signal for controlling external
 | ||||
| // analog synth components (like envelopes).
 | ||||
| 
 | ||||
| static const unsigned sGatePin     = 13; | ||||
| static const unsigned sAudioOutPin = 10; | ||||
| static const unsigned sMaxNumNotes = 16; | ||||
| MidiNoteList<sMaxNumNotes> midiNotes; | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| void handleGateChanged(bool inGateActive) | ||||
| { | ||||
|     digitalWrite(sGatePin, inGateActive ? HIGH : LOW); | ||||
| } | ||||
| 
 | ||||
| void pulseGate() | ||||
| { | ||||
|     handleGateChanged(false); | ||||
|     delay(1); | ||||
|     handleGateChanged(true); | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| void handleNotesChanged() | ||||
| { | ||||
|     if (midiNotes.empty()) | ||||
|     { | ||||
|         handleGateChanged(false); | ||||
|         noTone(sAudioOutPin); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         byte currentNote = 0; | ||||
|         if (midiNotes.getTail(currentNote)) | ||||
|         { | ||||
|             tone(sAudioOutPin, sNotePitches[currentNote]); | ||||
|             pulseGate(); // Retrigger envelopes. Remove for legato effect.
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| void handleNoteOn(byte inChannel, byte inNote, byte inVelocity) | ||||
| { | ||||
|     midiNotes.add(MidiNote(inNote, inVelocity)); | ||||
|     handleNotesChanged(); | ||||
| } | ||||
| 
 | ||||
| void handleNoteOff(byte inChannel, byte inNote, byte inVelocity) | ||||
| { | ||||
|     midiNotes.remove(inNote); | ||||
|     handleNotesChanged(); | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| void setup() | ||||
| {   | ||||
|     pinMode(sGatePin,     OUTPUT); | ||||
|     pinMode(sAudioOutPin, OUTPUT); | ||||
|     MIDI.setHandleNoteOn(handleNoteOn); | ||||
|     MIDI.setHandleNoteOff(handleNoteOff); | ||||
|     MIDI.begin(); | ||||
| } | ||||
| 
 | ||||
| void loop() | ||||
| { | ||||
|     MIDI.read(); | ||||
| } | ||||
|  | @ -0,0 +1,21 @@ | |||
| /*!
 | ||||
|  *  \file       synth-core_NoteList.h | ||||
|  *  \author     Francois Best | ||||
|  *  \date       24/05/2013 | ||||
|  *  \license    GPL v3.0 - Copyright Forty Seven Effects 2013 | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU 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 General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include "noteList.h" | ||||
|  | @ -0,0 +1,317 @@ | |||
| /*!
 | ||||
|  *  \file       synth-core_NoteList.h | ||||
|  *  \author     Francois Best | ||||
|  *  \date       24/05/2013 | ||||
|  *  \license    GPL v3.0 - Copyright Forty Seven Effects 2013 | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU 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 General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <inttypes.h> | ||||
| 
 | ||||
| typedef uint8_t byte; | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| struct MidiNote | ||||
| { | ||||
|     inline MidiNote(); | ||||
|     inline MidiNote(byte inPitch, byte inVelocity); | ||||
|     inline MidiNote(const MidiNote& inOther); | ||||
|     inline MidiNote& operator= (const MidiNote& inOther); | ||||
| 
 | ||||
|     byte pitch; | ||||
|     byte velocity; | ||||
| }; | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| template<byte Size> | ||||
| class MidiNoteList | ||||
| { | ||||
| private: | ||||
|     struct Cell | ||||
|     { | ||||
|         inline Cell(); | ||||
|         inline Cell(const Cell& inOther); | ||||
|         inline Cell& operator= (const Cell& inOther); | ||||
| 
 | ||||
|         MidiNote note; | ||||
|         bool active; | ||||
|         Cell* next; | ||||
|         Cell* prev; | ||||
|     }; | ||||
| 
 | ||||
| public: | ||||
|     inline  MidiNoteList(); | ||||
|     inline ~MidiNoteList(); | ||||
| 
 | ||||
| public: | ||||
|     inline void add(const MidiNote& inNote); | ||||
|     inline void remove(byte inPitch); | ||||
| 
 | ||||
| public: | ||||
|     inline bool get(byte inIndex, byte& outPitch) const; | ||||
|     inline bool getTail(byte& outPitch) const; | ||||
| 
 | ||||
| public: | ||||
|     inline bool empty() const; | ||||
|     inline byte size() const; | ||||
| 
 | ||||
| private: | ||||
|     inline Cell* getFirstEmptyCell(); | ||||
|     inline void print() const; | ||||
| 
 | ||||
| private: | ||||
|     Cell mArray[Size]; | ||||
|     Cell* mHead; | ||||
|     Cell* mTail; | ||||
|     byte mSize; | ||||
| }; | ||||
| 
 | ||||
| // ########################################################################## //
 | ||||
| // Inline implementation
 | ||||
| 
 | ||||
| inline MidiNote::MidiNote() | ||||
|     : pitch(0) | ||||
|     , velocity(0) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| inline MidiNote::MidiNote(byte inPitch, byte inVelocity) | ||||
|     : pitch(inPitch) | ||||
|     , velocity(inVelocity) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| inline MidiNote::MidiNote(const MidiNote& inOther) | ||||
|     : pitch(inOther.pitch) | ||||
|     , velocity(inOther.velocity) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| inline MidiNote& MidiNote::operator= (const MidiNote& inOther) | ||||
| { | ||||
|     pitch = inOther.pitch; | ||||
|     velocity = inOther.velocity; | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| // ########################################################################## //
 | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline MidiNoteList<Size>::Cell::Cell() | ||||
|     : note() | ||||
|     , active(false) | ||||
|     , next(0) | ||||
|     , prev(0) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline MidiNoteList<Size>::Cell::Cell(const Cell& inOther) | ||||
|     : note(inOther.note) | ||||
|     , active(inOther.active) | ||||
|     , next(inOther.next) | ||||
|     , prev(inOther.prev) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline typename MidiNoteList<Size>::Cell& MidiNoteList<Size>::Cell::operator= (const Cell& inOther) | ||||
| { | ||||
|     note = inOther.note; | ||||
|     active = inOther.active; | ||||
|     next = inOther.next; | ||||
|     prev = inOther.prev; | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| // ########################################################################## //
 | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline MidiNoteList<Size>::MidiNoteList() | ||||
| { | ||||
|     // Check that size is a power of two
 | ||||
|     //AVR_STATIC_ASSERT(Size != 0 && !(Size & (Size - 1)));
 | ||||
| } | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline MidiNoteList<Size>::~MidiNoteList() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline void MidiNoteList<Size>::add(const MidiNote& inNote) | ||||
| { | ||||
|     if (mHead == 0) | ||||
|     { | ||||
|         mArray[0].note   = inNote; | ||||
|         mArray[0].active = true; | ||||
|         mArray[0].next   = 0; | ||||
|         mArray[0].prev   = 0; | ||||
|         mHead = mArray; | ||||
|         mTail = mArray; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Find the first inactive cell, and use it as tail.
 | ||||
|         Cell* const oldTail = mTail; | ||||
|         Cell* const newTail = getFirstEmptyCell(); | ||||
| 
 | ||||
|         newTail->active = true; | ||||
|         newTail->note = inNote; | ||||
| 
 | ||||
|         oldTail->next = newTail; | ||||
|         newTail->prev = oldTail; | ||||
|         newTail->next = 0; | ||||
|         mTail = newTail; | ||||
|     } | ||||
|     mSize++; | ||||
|     print(); | ||||
| } | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline void MidiNoteList<Size>::remove(byte inPitch) | ||||
| { | ||||
|     if (mHead != 0) | ||||
|     { | ||||
|         for (Cell* it = mHead; it != 0; it = it->next) | ||||
|         { | ||||
|             if (it->note.pitch == inPitch) | ||||
|             { | ||||
|                 Cell* const prev = it->prev; | ||||
|                 Cell* const next = it->next; | ||||
| 
 | ||||
|                 it->active = false; | ||||
|                 it->next = 0; | ||||
|                 it->prev = 0; | ||||
| 
 | ||||
|                 // Reconnect both ends
 | ||||
|                 if (it == mHead) | ||||
|                 { | ||||
|                     //AVR_ASSERT(prev == 0);
 | ||||
|                     mHead = next; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     //AVR_ASSERT(prev != 0);
 | ||||
|                     prev->next = next; | ||||
|                 } | ||||
| 
 | ||||
|                 if (it == mTail) | ||||
|                 { | ||||
|                     //AVR_ASSERT(next == 0);
 | ||||
|                     mTail = prev; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     //AVR_ASSERT(next != 0);
 | ||||
|                     next->prev = prev; | ||||
|                 } | ||||
| 
 | ||||
|                 mSize--; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     print(); | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline bool MidiNoteList<Size>::get(byte inIndex, byte& outPitch) const | ||||
| { | ||||
|     if (mTail) | ||||
|     { | ||||
|         const Cell* it = mTail; | ||||
|         for (byte i = 0; i < inIndex; ++i) | ||||
|         { | ||||
|             if (it->prev) | ||||
|             { | ||||
|                 it = it->prev; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         print(); | ||||
|         //AVR_LOG("Index " << inIndex << ": " << it->note.pitch);
 | ||||
| 
 | ||||
|         outPitch = it->note.pitch; | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline bool MidiNoteList<Size>::getTail(byte& outPitch) const | ||||
| { | ||||
|     if (mTail) | ||||
|     { | ||||
|         outPitch = mTail->note.pitch; | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline bool MidiNoteList<Size>::empty() const | ||||
| { | ||||
|     return mSize == 0; | ||||
| } | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline byte MidiNoteList<Size>::size() const | ||||
| { | ||||
|     return mSize; | ||||
| } | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline typename MidiNoteList<Size>::Cell* MidiNoteList<Size>::getFirstEmptyCell() | ||||
| { | ||||
|     for (byte i = 0; i < Size; ++i) | ||||
|     { | ||||
|         if (mArray[i].active == false) | ||||
|         { | ||||
|             return mArray + i; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| template<byte Size> | ||||
| inline void MidiNoteList<Size>::print() const | ||||
| { | ||||
| //#ifndef NDEBUG
 | ||||
| //    AVR_DBG("Note List: [ ");
 | ||||
| //    if (mHead)
 | ||||
| //    {
 | ||||
| //        for (const Cell* it = mHead; it != 0; it = it->next)
 | ||||
| //        {
 | ||||
| //            AVR_DBG(it->note.pitch);
 | ||||
| //            if (it->next)
 | ||||
| //                AVR_DBG(" -> ");
 | ||||
| //        }
 | ||||
| //    }
 | ||||
| //    AVR_LOG(" ]");
 | ||||
| //#endif
 | ||||
| } | ||||
|  | @ -0,0 +1,108 @@ | |||
| /*************************************************
 | ||||
|  * Public Constants | ||||
|  *************************************************/ | ||||
| #include <inttypes.h> | ||||
| 
 | ||||
| #define NOTE_B0  31 | ||||
| #define NOTE_C1  33 | ||||
| #define NOTE_CS1 35 | ||||
| #define NOTE_D1  37 | ||||
| #define NOTE_DS1 39 | ||||
| #define NOTE_E1  41 | ||||
| #define NOTE_F1  44 | ||||
| #define NOTE_FS1 46 | ||||
| #define NOTE_G1  49 | ||||
| #define NOTE_GS1 52 | ||||
| #define NOTE_A1  55 | ||||
| #define NOTE_AS1 58 | ||||
| #define NOTE_B1  62 | ||||
| #define NOTE_C2  65 | ||||
| #define NOTE_CS2 69 | ||||
| #define NOTE_D2  73 | ||||
| #define NOTE_DS2 78 | ||||
| #define NOTE_E2  82 | ||||
| #define NOTE_F2  87 | ||||
| #define NOTE_FS2 93 | ||||
| #define NOTE_G2  98 | ||||
| #define NOTE_GS2 104 | ||||
| #define NOTE_A2  110 | ||||
| #define NOTE_AS2 117 | ||||
| #define NOTE_B2  123 | ||||
| #define NOTE_C3  131 | ||||
| #define NOTE_CS3 139 | ||||
| #define NOTE_D3  147 | ||||
| #define NOTE_DS3 156 | ||||
| #define NOTE_E3  165 | ||||
| #define NOTE_F3  175 | ||||
| #define NOTE_FS3 185 | ||||
| #define NOTE_G3  196 | ||||
| #define NOTE_GS3 208 | ||||
| #define NOTE_A3  220 | ||||
| #define NOTE_AS3 233 | ||||
| #define NOTE_B3  247 | ||||
| #define NOTE_C4  262 | ||||
| #define NOTE_CS4 277 | ||||
| #define NOTE_D4  294 | ||||
| #define NOTE_DS4 311 | ||||
| #define NOTE_E4  330 | ||||
| #define NOTE_F4  349 | ||||
| #define NOTE_FS4 370 | ||||
| #define NOTE_G4  392 | ||||
| #define NOTE_GS4 415 | ||||
| #define NOTE_A4  440 | ||||
| #define NOTE_AS4 466 | ||||
| #define NOTE_B4  494 | ||||
| #define NOTE_C5  523 | ||||
| #define NOTE_CS5 554 | ||||
| #define NOTE_D5  587 | ||||
| #define NOTE_DS5 622 | ||||
| #define NOTE_E5  659 | ||||
| #define NOTE_F5  698 | ||||
| #define NOTE_FS5 740 | ||||
| #define NOTE_G5  784 | ||||
| #define NOTE_GS5 831 | ||||
| #define NOTE_A5  880 | ||||
| #define NOTE_AS5 932 | ||||
| #define NOTE_B5  988 | ||||
| #define NOTE_C6  1047 | ||||
| #define NOTE_CS6 1109 | ||||
| #define NOTE_D6  1175 | ||||
| #define NOTE_DS6 1245 | ||||
| #define NOTE_E6  1319 | ||||
| #define NOTE_F6  1397 | ||||
| #define NOTE_FS6 1480 | ||||
| #define NOTE_G6  1568 | ||||
| #define NOTE_GS6 1661 | ||||
| #define NOTE_A6  1760 | ||||
| #define NOTE_AS6 1865 | ||||
| #define NOTE_B6  1976 | ||||
| #define NOTE_C7  2093 | ||||
| #define NOTE_CS7 2217 | ||||
| #define NOTE_D7  2349 | ||||
| #define NOTE_DS7 2489 | ||||
| #define NOTE_E7  2637 | ||||
| #define NOTE_F7  2794 | ||||
| #define NOTE_FS7 2960 | ||||
| #define NOTE_G7  3136 | ||||
| #define NOTE_GS7 3322 | ||||
| #define NOTE_A7  3520 | ||||
| #define NOTE_AS7 3729 | ||||
| #define NOTE_B7  3951 | ||||
| #define NOTE_C8  4186 | ||||
| #define NOTE_CS8 4435 | ||||
| #define NOTE_D8  4699 | ||||
| #define NOTE_DS8 4978 | ||||
| 
 | ||||
| static const uint16_t sNotePitches[] = { | ||||
|     NOTE_B0, NOTE_C1, NOTE_CS1, NOTE_D1, NOTE_DS1, NOTE_E1, NOTE_F1, NOTE_FS1, | ||||
|     NOTE_G1, NOTE_GS1, NOTE_A1, NOTE_AS1, NOTE_B1, NOTE_C2, NOTE_CS2, NOTE_D2, | ||||
|     NOTE_DS2, NOTE_E2, NOTE_F2, NOTE_FS2, NOTE_G2, NOTE_GS2, NOTE_A2, NOTE_AS2, | ||||
|     NOTE_B2, NOTE_C3, NOTE_CS3, NOTE_D3, NOTE_DS3, NOTE_E3, NOTE_F3, NOTE_FS3, | ||||
|     NOTE_G3, NOTE_GS3, NOTE_A3, NOTE_AS3, NOTE_B3, NOTE_C4, NOTE_CS4, NOTE_D4, | ||||
|     NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, | ||||
|     NOTE_B4, NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, | ||||
|     NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5, NOTE_C6, NOTE_CS6, NOTE_D6, | ||||
|     NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, | ||||
|     NOTE_B6, NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, | ||||
|     NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7, NOTE_C8, NOTE_CS8, NOTE_D8, NOTE_DS8, | ||||
| }; | ||||
		Loading…
	
		Reference in New Issue
	
	 Francois Best
						Francois Best