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
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Changes for 2.7.0

* New feature: Built-in octave shift support via `anyrtttl::setOctaveShift()`. Shifts all note frequencies up or down by N octaves before calling `tone()`. Useful for passive buzzers with a higher resonant frequency sweet spot.
* New feature: example `OctaveShift` demonstrating octave shift usage.


Changes for 2.6.0

* Fixed issue #33 - Incorrect dotted note reading.
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ AnyRtttl is a feature rich arduino library for playing [RTTTL](http://www.end2en
* Supports highly compressed RTTTL binary format. See [Play16Bits](examples\Play16Bits\Play16Bits.ino) or [Play10Bits](examples\Play10Bits\Play10Bits.ino) examples.
* Supports names longer than the 10 character limit.
* Supports dotted notes in format `[<duration>]<note>[<octave>][.]` (Nokia's specification) or the alternate format `[<duration>]<note>[.][<octave>]` (Nokia's Simpsons example).
* Built-in octave shift to move all note frequencies up or down, ideal for passive buzzers. See [OctaveShift](examples/OctaveShift/OctaveShift.ino) example.


## Status ##
Expand Down Expand Up @@ -313,6 +314,32 @@ void setup()



## Octave Shift ##

Passive buzzers often have a resonant frequency sweet spot well above the standard RTTTL note range (typically 200-800Hz). The octave shift feature lets you shift all note frequencies up or down by N octaves without modifying the RTTTL data or writing a custom `tone()` wrapper.

Use `anyrtttl::setOctaveShift(N)` to shift all notes up by N octaves (or down if N is negative). The default value is 0 (no shift). This applies to the global context used by the legacy APIs.

For multi-context usage, use `anyrtttl::setOctaveShift(context, N)` to set the shift on a specific context.

```cpp
void setup() {
pinMode(BUZZER_PIN, OUTPUT);

// Shift all notes up by 2 octaves (frequency * 4)
// Great for passive buzzers that sound best above 2000Hz
anyrtttl::setOctaveShift(2);
}

void loop() {
anyrtttl::blocking::play(BUZZER_PIN, melody);
}
```

See [OctaveShift](examples/OctaveShift/OctaveShift.ino) example for a complete demo.



## Binary RTTTL / Compatibility with custom RTTTL formats ##

AnyRtttl can be configured for playing your custom format. AnyRtttl can use a custom function for decoding such a custom format. This allows the library to be compatible with any custom RTTTL formats that can be decoded as legacy RTTTL.
Expand Down Expand Up @@ -431,6 +458,7 @@ More AnyRtttl examples are also available:
* [NonBlockingProgramMemoryRtttl](examples/NonBlockingProgramMemoryRtttl/NonBlockingProgramMemoryRtttl.ino)
* [NonBlockingRtttl](examples/NonBlockingRtttl/NonBlockingRtttl.ino)
* [NonBlockingStopBeforeEnd](examples/NonBlockingStopBeforeEnd/NonBlockingStopBeforeEnd.ino)
* [OctaveShift](examples/OctaveShift/OctaveShift.ino)
* [Play10Bits](examples/Play10Bits/Play10Bits.ino)
* [Play16Bits](examples/Play16Bits/Play16Bits.ino)
* [PlaySerialRtttl](examples/PlaySerialRtttl/PlaySerialRtttl.ino)
Expand Down
47 changes: 47 additions & 0 deletions examples/OctaveShift/OctaveShift.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// ---------------------------------------------------------------------------
// OctaveShift example for AnyRtttl
//
// Demonstrates the octave shift feature. Plays a melody at normal pitch,
// then plays it again shifted up by 2 octaves — useful for passive buzzers
// whose sweet spot is at higher frequencies (2500Hz+).
// ---------------------------------------------------------------------------

#include <anyrtttl.h>
#include <binrtttl.h>
#include <pitches.h>

// Define the BUZZER_PIN for current board
#if defined(ESP32)
#define BUZZER_PIN 25
#elif defined(ESP8266)
#define BUZZER_PIN 2
#else
#define BUZZER_PIN 9
#endif

const char * mario = "mario:d=4,o=5,b=100:16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,8g,8p";

void setup() {
pinMode(BUZZER_PIN, OUTPUT);

Serial.begin(115200);
Serial.println();

// --- Play at normal pitch (default octaveShift = 0) ---
Serial.println("Playing at normal pitch...");
anyrtttl::blocking::play(BUZZER_PIN, mario);

delay(1000);

// --- Shift up 2 octaves for passive buzzer ---
Serial.println("Playing shifted up 2 octaves...");
anyrtttl::setOctaveShift(2);
anyrtttl::blocking::play(BUZZER_PIN, mario);

// Reset shift back to normal
anyrtttl::setOctaveShift(0);
}

void loop() {
// nothing to do
}
13 changes: 12 additions & 1 deletion src/anyrtttl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ void setMillisFunction(MillisFuncPtr iFunc) {
_millis = iFunc;
}

void setOctaveShift(int8_t iOctaveShift) {
gGlobalContext.octaveShift = iOctaveShift;
}

char readCharMem(const char * iBuffer) {
char output = *iBuffer;
return output;
Expand Down Expand Up @@ -195,8 +199,10 @@ void begin(rtttl_context_t & c, byte iPin, const char * iBuffer, GetCharFuncPtr
return;
}

// init context
// init context, preserving octaveShift set by user
int8_t savedOctaveShift = c.octaveShift;
initContext(c);
c.octaveShift = savedOctaveShift;

//init values
c.pin = iPin;
Expand Down Expand Up @@ -422,6 +428,10 @@ void nextNote(rtttl_context_t & c)
#endif

uint16_t frequency = gNotes[(c.scale - 4) * NOTES_PER_OCTAVE + c.noteOffset];
if (c.octaveShift > 0)
frequency <<= c.octaveShift;
else if (c.octaveShift < 0)
frequency >>= (-c.octaveShift);
_tone(c.pin, frequency, c.duration);

c.nextNoteMs = _millis() + (c.duration+1);
Expand Down Expand Up @@ -552,6 +562,7 @@ void initContext(rtttl_context_t & c) {
c.nextNoteMs = 0;
c.playing = false;
c.noteOffset = 0;
c.octaveShift = 0;
}

}; //anyrtttl namespace
21 changes: 21 additions & 0 deletions src/anyrtttl.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ typedef struct rtttl_context_t {
unsigned long nextNoteMs; // timestamp in milliseconds of end of note (start of next).
bool playing;
byte noteOffset;
int8_t octaveShift; // shift all note frequencies up (positive) or down (negative) by N octaves.
} rtttl_context_t;

/****************************************************************************
Expand Down Expand Up @@ -109,6 +110,26 @@ void setNoToneFunction(NoToneFuncPtr iFunc);
****************************************************************************/
void setMillisFunction(MillisFuncPtr iFunc);

/****************************************************************************
* Description:
* Sets the octave shift applied to all note frequencies.
* A positive value shifts notes up (e.g. 2 shifts up by 2 octaves),
* a negative value shifts notes down. Default is 0 (no shift).
* This sets the shift on the global context used by legacy APIs.
* Parameters:
* iOctaveShift: Number of octaves to shift. Positive = up, negative = down.
****************************************************************************/
void setOctaveShift(int8_t iOctaveShift);

/****************************************************************************
* Description:
* Sets the octave shift on a specific context.
* Parameters:
* c: The context to modify.
* iOctaveShift: Number of octaves to shift. Positive = up, negative = down.
****************************************************************************/
inline void setOctaveShift(rtttl_context_t & c, int8_t iOctaveShift) { c.octaveShift = iOctaveShift; }

/****************************************************************************
* Description:
* Read the first byte of a buffer stored in RAM.
Expand Down