ソースを参照

upd tuning fork

MX 9 ヶ月 前
コミット
ee60c312fb
8 ファイル変更646 行追加272 行削除
  1. 4 4
      application.fam
  2. 2 0
      constants.h
  3. BIN
      img/tuning_fork.gif
  4. 50 0
      instruments.h
  5. 63 63
      notes.h
  6. 272 57
      tuning_fork.c
  7. 230 148
      tunings.h
  8. 25 0
      types.h

+ 4 - 4
application.fam

@@ -3,7 +3,7 @@ App(
     name="Tuning Fork",
     apptype=FlipperAppType.EXTERNAL,
     entry_point="tuning_fork_app",
-    cdefines=["APP_TUNING_FORM"],
+    cdefines=["APP_TUNING_FORK"],
     requires=[
         "gui",
     ],
@@ -11,8 +11,8 @@ App(
     fap_category="Media",
     stack_size=2 * 1024,
     order=20,
-    fap_author="@besya & (Fixes by @Willy-JL)",
+    fap_author="@besya",
     fap_weburl="https://github.com/besya/flipperzero-tuning-fork",
-    fap_version="1.2",
-    fap_description="Tuning fork for tuning musical instruments",
+    fap_version="2.1",
+    fap_description="Tuning fork for tuning musical instruments and more",
 )

+ 2 - 0
constants.h

@@ -0,0 +1,2 @@
+#define MAX_LABEL_LENGTH     20
+#define MAX_NOTES_PER_TUNING 20

BIN
img/tuning_fork.gif


+ 50 - 0
instruments.h

@@ -0,0 +1,50 @@
+#include "tunings.h"
+
+const TUNING Guitar6Tunings[] = {
+    Guitar6Standard,
+    Guitar6DropD,
+    Guitar6DADGAD,
+    Guitar6D,
+    Guitar6CGCFGCSharp,
+    Guitar6DropC,
+    Guitar6CGCFGC};
+
+const TUNING Guitar7Tunings[] = {Guitar7Standard, Guitar7DropA, Guitar7A};
+const VARIATION GuitarVariations[] = {
+    {"6 strings", (TUNING*)Guitar6Tunings, 7},
+    {"7 strings", (TUNING*)Guitar7Tunings, 3}};
+
+const TUNING Bass4Tunings[] =
+    {Bass4Standard, Bass4Tenor, Bass4DropD, Bass4D, Bass4DropCSharp, Bass4DropC};
+const TUNING Bass5Tunings[] = {Bass5Standard, Bass5Tenor, Bass5DropA};
+const VARIATION BassVariations[] = {
+    {"4 strings", (TUNING*)Bass4Tunings, 6},
+    {"5 strings", (TUNING*)Bass5Tunings, 3}};
+
+const TUNING Ukulele4Tunings[] = {Ukulele4Standard};
+const VARIATION UkuleleVariations[] = {{"4 strings", (TUNING*)Ukulele4Tunings, 1}};
+
+const TUNING Banjo5Tunings[] = {Banjo5Standard};
+const VARIATION BanjoVariations[] = {{"5 strings", (TUNING*)Banjo5Tunings, 1}};
+
+const TUNING CigarBox3Tunings[] = {CigarBox3OpenG, CigarBox3OpenD, CigarBox3OpenA};
+const TUNING CigarBox4Tunings[] = {CigarBox4OpenG};
+const VARIATION CigarBoxVariations[] = {
+    {"3 strings", (TUNING*)CigarBox3Tunings, 3},
+    {"4 strings", (TUNING*)CigarBox4Tunings, 1}};
+
+const TUNING ForkTunings[] = {ForkCommon, ForkSarti, ForkMid19Century, Fork18Century, ForkVerdi};
+const TUNING OtherTunings[] = {ScientificPitch};
+const VARIATION MiscellaneousVariations[] = {
+    {"Forks", (TUNING*)ForkTunings, 5},
+    {"Other", (TUNING*)OtherTunings, 1}};
+
+const INSTRUMENT Instruments[] = {
+    {"Guitar", (VARIATION*)GuitarVariations, 2},
+    {"Bass", (VARIATION*)BassVariations, 2},
+    {"Ukulele", (VARIATION*)UkuleleVariations, 1},
+    {"Banjo", (VARIATION*)BanjoVariations, 1},
+    {"Cigar Box", (VARIATION*)CigarBoxVariations, 2},
+    {"Miscellaneous", (VARIATION*)MiscellaneousVariations, 2}};
+
+#define INSTRUMENTS_COUNT 6

+ 63 - 63
notes.h

@@ -1,158 +1,158 @@
 #ifndef NOTES
 #define NOTES
 
-#define C0 16.35f
+#define C0  16.35f
 #define Cs0 17.32f
 #define Db0 17.32f
-#define D0 18.35f
+#define D0  18.35f
 #define Ds0 19.45f
 #define Eb0 19.45f
-#define E0 20.60f
-#define F0 21.83f
+#define E0  20.60f
+#define F0  21.83f
 #define Fs0 23.12f
 #define Gb0 23.12f
-#define G0 24.50f
+#define G0  24.50f
 #define Gs0 25.96f
 #define Ab0 25.96f
-#define A0 27.50f
+#define A0  27.50f
 #define As0 29.14f
 #define Bb0 29.14f
-#define B0 30.868f
-#define C1 32.70f
+#define B0  30.868f
+#define C1  32.70f
 #define Cs1 34.65f
 #define Db1 34.65f
-#define D1 36.71f
+#define D1  36.71f
 #define Ds1 38.89f
 #define Eb1 38.89f
-#define E1 41.203f
-#define F1 43.65f
+#define E1  41.203f
+#define F1  43.65f
 #define Fs1 46.25f
 #define Gb1 46.25f
-#define G1 49.00f
+#define G1  49.00f
 #define Gs1 51.91f
 #define Ab1 51.91f
-#define A1 55.00f
+#define A1  55.00f
 #define As1 58.27f
 #define Bb1 58.27f
-#define B1 61.74f
-#define C2 65.41f
+#define B1  61.74f
+#define C2  65.41f
 #define Cs2 69.30f
 #define Db2 69.30f
-#define D2 73.416f
+#define D2  73.416f
 #define Ds2 77.78f
 #define Eb2 77.78f
-#define E2 82.41f
-#define F2 87.31f
+#define E2  82.41f
+#define F2  87.31f
 #define Fs2 92.50f
 #define Gb2 92.50f
-#define G2 97.999f
+#define G2  97.999f
 #define Gs2 103.83f
 #define Ab2 103.83f
-#define A2 110.00f
+#define A2  110.00f
 #define As2 116.54f
 #define Bb2 116.54f
-#define B2 123.47f
-#define C3 130.813f
+#define B2  123.47f
+#define C3  130.813f
 #define Cs3 138.59f
 #define Db3 138.59f
-#define D3 146.83f
+#define D3  146.83f
 #define Ds3 155.56f
 #define Eb3 155.56f
-#define E3 164.81f
-#define F3 174.61f
+#define E3  164.81f
+#define F3  174.61f
 #define Fs3 185.00f
 #define Gb3 185.00f
-#define G3 196.00f
+#define G3  196.00f
 #define Gs3 207.65f
 #define Ab3 207.65f
-#define A3 220.00f
+#define A3  220.00f
 #define As3 233.08f
 #define Bb3 233.08f
-#define B3 246.94f
-#define C4 261.63f
+#define B3  246.94f
+#define C4  261.63f
 #define Cs4 277.18f
 #define Db4 277.18f
-#define D4 293.66f
+#define D4  293.66f
 #define Ds4 311.13f
 #define Eb4 311.13f
-#define E4 329.63f
-#define F4 349.23f
+#define E4  329.63f
+#define F4  349.23f
 #define Fs4 369.99f
 #define Gb4 369.99f
-#define G4 392.00f
+#define G4  392.00f
 #define Gs4 415.30f
 #define Ab4 415.30f
-#define A4 440.00f
+#define A4  440.00f
 #define As4 466.16f
 #define Bb4 466.16f
-#define B4 493.88f
-#define C5 523.25f
+#define B4  493.88f
+#define C5  523.25f
 #define Cs5 554.37f
 #define Db5 554.37f
-#define D5 587.33f
+#define D5  587.33f
 #define Ds5 622.25f
 #define Eb5 622.25f
-#define E5 659.25f
-#define F5 698.46f
+#define E5  659.25f
+#define F5  698.46f
 #define Fs5 739.99f
 #define Gb5 739.99f
-#define G5 783.99f
+#define G5  783.99f
 #define Gs5 830.61f
 #define Ab5 830.61f
-#define A5 880.00f
+#define A5  880.00f
 #define As5 932.33f
 #define Bb5 932.33f
-#define B5 987.77f
-#define C6 1046.50f
+#define B5  987.77f
+#define C6  1046.50f
 #define Cs6 1108.73f
 #define Db6 1108.73f
-#define D6 1174.66f
+#define D6  1174.66f
 #define Ds6 1244.51f
 #define Eb6 1244.51f
-#define E6 1318.51f
-#define F6 1396.91f
+#define E6  1318.51f
+#define F6  1396.91f
 #define Fs6 1479.98f
 #define Gb6 1479.98f
-#define G6 1567.98f
+#define G6  1567.98f
 #define Gs6 1661.22f
 #define Ab6 1661.22f
-#define A6 1760.00f
+#define A6  1760.00f
 #define As6 1864.66f
 #define Bb6 1864.66f
-#define B6 1975.53f
-#define C7 2093.00f
+#define B6  1975.53f
+#define C7  2093.00f
 #define Cs7 2217.46f
 #define Db7 2217.46f
-#define D7 2349.32f
+#define D7  2349.32f
 #define Ds7 2489.02f
 #define Eb7 2489.02f
-#define E7 2637.02f
-#define F7 2793.83f
+#define E7  2637.02f
+#define F7  2793.83f
 #define Fs7 2959.96f
 #define Gb7 2959.96f
-#define G7 3135.96f
+#define G7  3135.96f
 #define Gs7 3322.44f
 #define Ab7 3322.44f
-#define A7 3520.00f
+#define A7  3520.00f
 #define As7 3729.31f
 #define Bb7 3729.31f
-#define B7 3951.07f
-#define C8 4186.01f
+#define B7  3951.07f
+#define C8  4186.01f
 #define Cs8 4434.92f
 #define Db8 4434.92f
-#define D8 4698.63f
+#define D8  4698.63f
 #define Ds8 4978.03f
 #define Eb8 4978.03f
-#define E8 5274.04f
-#define F8 5587.65f
+#define E8  5274.04f
+#define F8  5587.65f
 #define Fs8 5919.91f
 #define Gb8 5919.91f
-#define G8 6271.93f
+#define G8  6271.93f
 #define Gs8 6644.88f
 #define Ab8 6644.88f
-#define A8 7040.00f
+#define A8  7040.00f
 #define As8 7458.62f
 #define Bb8 7458.62f
-#define B8 7902.13f
+#define B8  7902.13f
 
 #endif //NOTES

+ 272 - 57
tuning_fork.c

@@ -1,18 +1,23 @@
 #include <furi.h>
 #include <furi_hal.h>
 #include <input/input.h>
-#include <string.h>
 #include <stdlib.h>
+#include <string.h>
 
-#include <gui/gui.h>
-#include <gui/elements.h>
 #include <gui/canvas.h>
+#include <gui/elements.h>
+#include <gui/gui.h>
 
 #include <notification/notification.h>
 #include <notification/notification_messages.h>
 
-#include "notes.h"
 #include "tunings.h"
+#include "instruments.h"
+
+#define VOLUME_STEP             0.1f
+#define DEFAULT_VOLUME          1.0f
+#define QUEUE_SIZE              8
+#define SPEAKER_ACQUIRE_TIMEOUT 1000
 
 typedef enum {
     EventTypeTick,
@@ -24,18 +29,38 @@ typedef struct {
     InputEvent input;
 } PluginEvent;
 
-enum Page { Tunings, Notes };
+enum Page {
+    InstrumentsPage,
+    VariationsPage,
+    TuningsPage,
+    NotesPage
+};
 
 typedef struct {
     FuriMutex* mutex;
     bool playing;
     enum Page page;
-    int current_tuning_note_index;
-    int current_tuning_index;
     float volume;
+
+    int current_instrument_index;
+    int current_variation_index;
+    int current_tuning_index;
+    int current_tuning_note_index;
+
+    INSTRUMENT instrument;
+    VARIATION variation;
     TUNING tuning;
 } TuningForkState;
 
+// Getters
+static INSTRUMENT current_instrument(TuningForkState* tuningForkState) {
+    return tuningForkState->instrument;
+}
+
+static VARIATION current_variation(TuningForkState* tuningForkState) {
+    return tuningForkState->variation;
+}
+
 static TUNING current_tuning(TuningForkState* tuningForkState) {
     return tuningForkState->tuning;
 }
@@ -48,25 +73,99 @@ static float current_tuning_note_freq(TuningForkState* tuningForkState) {
     return current_tuning_note(tuningForkState).frequency;
 }
 
-static void current_tuning_note_label(TuningForkState* tuningForkState, char* outNoteLabel) {
-    for(int i = 0; i < 20; ++i) {
-        outNoteLabel[i] = current_tuning_note(tuningForkState).label[i];
+// String helper
+static void safe_string_copy(char* dest, const char* src, size_t size) {
+    if(dest && src) {
+        strncpy(dest, src, size - 1);
+        dest[size - 1] = '\0';
+    }
+}
+
+// Labels
+static void current_instrument_label(TuningForkState* tuningForkState, char* outCategoryLabel) {
+    if(outCategoryLabel) {
+        safe_string_copy(
+            outCategoryLabel, current_instrument(tuningForkState).label, MAX_LABEL_LENGTH);
+    }
+}
+
+static void current_variation_label(TuningForkState* tuningForkState, char* outCategoryLabel) {
+    if(outCategoryLabel) {
+        safe_string_copy(
+            outCategoryLabel, current_variation(tuningForkState).label, MAX_LABEL_LENGTH);
     }
 }
 
 static void current_tuning_label(TuningForkState* tuningForkState, char* outTuningLabel) {
-    for(int i = 0; i < 20; ++i) {
-        outTuningLabel[i] = current_tuning(tuningForkState).label[i];
+    if(outTuningLabel) {
+        safe_string_copy(outTuningLabel, current_tuning(tuningForkState).label, MAX_LABEL_LENGTH);
+    }
+}
+
+static void current_tuning_note_label(TuningForkState* tuningForkState, char* outNoteLabel) {
+    if(outNoteLabel) {
+        safe_string_copy(
+            outNoteLabel, current_tuning_note(tuningForkState).label, MAX_LABEL_LENGTH);
     }
 }
 
+// Update references
 static void updateTuning(TuningForkState* tuning_fork_state) {
-    tuning_fork_state->tuning = TuningList[tuning_fork_state->current_tuning_index];
+    tuning_fork_state->instrument = Instruments[tuning_fork_state->current_instrument_index];
+    tuning_fork_state->variation =
+        tuning_fork_state->instrument.variations[tuning_fork_state->current_variation_index];
+    tuning_fork_state->tuning =
+        tuning_fork_state->variation.tunings[tuning_fork_state->current_tuning_index];
     tuning_fork_state->current_tuning_note_index = 0;
 }
 
+// Instruments navigation
+static void next_instrument(TuningForkState* tuning_fork_state) {
+    if(tuning_fork_state->current_instrument_index == INSTRUMENTS_COUNT - 1) {
+        tuning_fork_state->current_instrument_index = 0;
+    } else {
+        tuning_fork_state->current_instrument_index += 1;
+    }
+    tuning_fork_state->current_variation_index = 0;
+    tuning_fork_state->current_tuning_index = 0;
+    updateTuning(tuning_fork_state);
+}
+
+static void prev_instrument(TuningForkState* tuning_fork_state) {
+    if(tuning_fork_state->current_instrument_index == 0) {
+        tuning_fork_state->current_instrument_index = INSTRUMENTS_COUNT - 1;
+    } else {
+        tuning_fork_state->current_instrument_index -= 1;
+    }
+    tuning_fork_state->current_variation_index = 0;
+    tuning_fork_state->current_tuning_index = 0;
+    updateTuning(tuning_fork_state);
+}
+
+// Variations navigation
+static void next_variation(TuningForkState* tuning_fork_state) {
+    if(tuning_fork_state->current_variation_index ==
+       tuning_fork_state->instrument.variations_count - 1) {
+        tuning_fork_state->current_variation_index = 0;
+    } else {
+        tuning_fork_state->current_variation_index += 1;
+    }
+    updateTuning(tuning_fork_state);
+}
+
+static void prev_variation(TuningForkState* tuning_fork_state) {
+    if(tuning_fork_state->current_variation_index == 0) {
+        tuning_fork_state->current_variation_index =
+            tuning_fork_state->instrument.variations_count - 1;
+    } else {
+        tuning_fork_state->current_variation_index -= 1;
+    }
+    updateTuning(tuning_fork_state);
+}
+
+// Tunings navigation
 static void next_tuning(TuningForkState* tuning_fork_state) {
-    if(tuning_fork_state->current_tuning_index == TUNINGS_COUNT - 1) {
+    if(tuning_fork_state->current_tuning_index == tuning_fork_state->variation.tunings_count - 1) {
         tuning_fork_state->current_tuning_index = 0;
     } else {
         tuning_fork_state->current_tuning_index += 1;
@@ -75,17 +174,18 @@ static void next_tuning(TuningForkState* tuning_fork_state) {
 }
 
 static void prev_tuning(TuningForkState* tuning_fork_state) {
-    if(tuning_fork_state->current_tuning_index - 1 < 0) {
-        tuning_fork_state->current_tuning_index = TUNINGS_COUNT - 1;
+    if(tuning_fork_state->current_tuning_index == 0) {
+        tuning_fork_state->current_tuning_index = tuning_fork_state->variation.tunings_count - 1;
     } else {
         tuning_fork_state->current_tuning_index -= 1;
     }
     updateTuning(tuning_fork_state);
 }
 
+// Notes navigation
 static void next_note(TuningForkState* tuning_fork_state) {
     if(tuning_fork_state->current_tuning_note_index ==
-       current_tuning(tuning_fork_state).notes_length - 1) {
+       current_tuning(tuning_fork_state).notes_count - 1) {
         tuning_fork_state->current_tuning_note_index = 0;
     } else {
         tuning_fork_state->current_tuning_note_index += 1;
@@ -95,24 +195,26 @@ static void next_note(TuningForkState* tuning_fork_state) {
 static void prev_note(TuningForkState* tuning_fork_state) {
     if(tuning_fork_state->current_tuning_note_index == 0) {
         tuning_fork_state->current_tuning_note_index =
-            current_tuning(tuning_fork_state).notes_length - 1;
+            current_tuning(tuning_fork_state).notes_count - 1;
     } else {
         tuning_fork_state->current_tuning_note_index -= 1;
     }
 }
 
+// Volume adjustments
 static void increase_volume(TuningForkState* tuning_fork_state) {
-    if(tuning_fork_state->volume < 1.0f) {
-        tuning_fork_state->volume += 0.1f;
+    if(tuning_fork_state->volume <= (1.0f - VOLUME_STEP)) {
+        tuning_fork_state->volume += VOLUME_STEP;
     }
 }
 
 static void decrease_volume(TuningForkState* tuning_fork_state) {
-    if(tuning_fork_state->volume > 0.0f) {
-        tuning_fork_state->volume -= 0.1f;
+    if(tuning_fork_state->volume >= VOLUME_STEP) {
+        tuning_fork_state->volume -= VOLUME_STEP;
     }
 }
 
+// Player
 static void play(TuningForkState* tuning_fork_state) {
     if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
         furi_hal_speaker_start(
@@ -132,6 +234,7 @@ static void replay(TuningForkState* tuning_fork_state) {
     play(tuning_fork_state);
 }
 
+// Renderer
 static void render_callback(Canvas* const canvas, void* ctx) {
     furi_assert(ctx);
     TuningForkState* tuning_fork_state = ctx;
@@ -140,29 +243,85 @@ static void render_callback(Canvas* const canvas, void* ctx) {
     FuriString* tempStr = furi_string_alloc();
 
     canvas_draw_frame(canvas, 0, 0, 128, 64);
-
     canvas_set_font(canvas, FontPrimary);
 
-    if(tuning_fork_state->page == Tunings) {
-        char tuningLabel[20];
+    if(tuning_fork_state->page == InstrumentsPage) {
+        char instrumentLabel[MAX_LABEL_LENGTH];
+        current_instrument_label(tuning_fork_state, instrumentLabel);
+        furi_string_printf(tempStr, "< %s >", instrumentLabel);
+        canvas_draw_str_aligned(
+            canvas, 64, 28, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
+    } else if(tuning_fork_state->page == VariationsPage) {
+        char instrumentLabel[MAX_LABEL_LENGTH];
+        char variationLabel[MAX_LABEL_LENGTH];
+
+        current_instrument_label(tuning_fork_state, instrumentLabel);
+        current_variation_label(tuning_fork_state, variationLabel);
+
+        furi_string_printf(tempStr, "%s", instrumentLabel);
+        canvas_draw_str_aligned(canvas, 4, 4, AlignLeft, AlignTop, furi_string_get_cstr(tempStr));
+
+        furi_string_reset(tempStr);
+
+        furi_string_printf(tempStr, "< %s >", variationLabel);
+        canvas_draw_str_aligned(
+            canvas, 64, 28, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
+
+    } else if(tuning_fork_state->page == TuningsPage) {
+        char instrumentLabel[MAX_LABEL_LENGTH];
+        char variationLabel[MAX_LABEL_LENGTH];
+        char tuningLabel[MAX_LABEL_LENGTH];
+
+        current_instrument_label(tuning_fork_state, instrumentLabel);
+        current_variation_label(tuning_fork_state, variationLabel);
         current_tuning_label(tuning_fork_state, tuningLabel);
+
+        furi_string_printf(tempStr, "%s", instrumentLabel);
+        canvas_draw_str_aligned(canvas, 4, 4, AlignLeft, AlignTop, furi_string_get_cstr(tempStr));
+
+        furi_string_reset(tempStr);
+
+        furi_string_printf(tempStr, "%s", variationLabel);
+        canvas_draw_str_aligned(
+            canvas, 124, 4, AlignRight, AlignTop, furi_string_get_cstr(tempStr));
+
+        furi_string_reset(tempStr);
+
         furi_string_printf(tempStr, "< %s >", tuningLabel);
         canvas_draw_str_aligned(
             canvas, 64, 28, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
-        furi_string_reset(tempStr);
+
     } else {
-        char tuningLabel[20];
+        char instrumentLabel[MAX_LABEL_LENGTH];
+        char variationLabel[MAX_LABEL_LENGTH];
+        char tuningLabel[MAX_LABEL_LENGTH];
+
+        current_instrument_label(tuning_fork_state, instrumentLabel);
+        current_variation_label(tuning_fork_state, variationLabel);
         current_tuning_label(tuning_fork_state, tuningLabel);
+
+        furi_string_printf(tempStr, "%s", instrumentLabel);
+        canvas_draw_str_aligned(canvas, 4, 4, AlignLeft, AlignTop, furi_string_get_cstr(tempStr));
+
+        furi_string_reset(tempStr);
+
+        furi_string_printf(tempStr, "%s", variationLabel);
+        canvas_draw_str_aligned(
+            canvas, 124, 4, AlignRight, AlignTop, furi_string_get_cstr(tempStr));
+
+        furi_string_reset(tempStr);
+
         furi_string_printf(tempStr, "%s", tuningLabel);
         canvas_draw_str_aligned(
-            canvas, 64, 8, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
+            canvas, 64, 20, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
+
         furi_string_reset(tempStr);
 
-        char tuningNoteLabel[20];
+        char tuningNoteLabel[MAX_LABEL_LENGTH];
         current_tuning_note_label(tuning_fork_state, tuningNoteLabel);
         furi_string_printf(tempStr, "< %s >", tuningNoteLabel);
         canvas_draw_str_aligned(
-            canvas, 64, 24, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
+            canvas, 64, 32, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
         furi_string_reset(tempStr);
     }
 
@@ -170,17 +329,18 @@ static void render_callback(Canvas* const canvas, void* ctx) {
     elements_button_left(canvas, "Prev");
     elements_button_right(canvas, "Next");
 
-    if(tuning_fork_state->page == Notes) {
+    if(tuning_fork_state->page == NotesPage) {
         if(tuning_fork_state->playing) {
-            elements_button_center(canvas, "Stop ");
+            elements_button_center(canvas, "Stop");
         } else {
             elements_button_center(canvas, "Play");
         }
     } else {
         elements_button_center(canvas, "Select");
     }
-    if(tuning_fork_state->page == Notes) {
-        elements_progress_bar(canvas, 8, 36, 112, tuning_fork_state->volume);
+
+    if(tuning_fork_state->page == NotesPage) {
+        elements_progress_bar(canvas, 8, 40, 112, tuning_fork_state->volume);
     }
 
     furi_string_free(tempStr);
@@ -196,24 +356,39 @@ static void input_callback(InputEvent* input_event, void* ctx) {
 }
 
 static void tuning_fork_state_init(TuningForkState* const tuning_fork_state) {
-    tuning_fork_state->playing = false;
-    tuning_fork_state->page = Tunings;
-    tuning_fork_state->volume = 1.0f;
-    tuning_fork_state->tuning = GuitarStandard6;
-    tuning_fork_state->current_tuning_index = 2;
-    tuning_fork_state->current_tuning_note_index = 0;
+    if(tuning_fork_state) {
+        tuning_fork_state->playing = false;
+        tuning_fork_state->page = InstrumentsPage;
+        tuning_fork_state->volume = DEFAULT_VOLUME;
+        tuning_fork_state->current_instrument_index = 0;
+        tuning_fork_state->current_variation_index = 0;
+        tuning_fork_state->current_tuning_index = 0;
+        tuning_fork_state->current_tuning_note_index = 0;
+        updateTuning(tuning_fork_state);
+    }
 }
 
 int32_t tuning_fork_app() {
-    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
+    FuriMessageQueue* event_queue = furi_message_queue_alloc(QUEUE_SIZE, sizeof(PluginEvent));
+    if(!event_queue) {
+        FURI_LOG_E("TuningFork", "Cannot create message queue\r\n");
+        return 255;
+    }
 
     TuningForkState* tuning_fork_state = malloc(sizeof(TuningForkState));
+    if(!tuning_fork_state) {
+        FURI_LOG_E("TuningFork", "Cannot allocate state\r\n");
+        furi_message_queue_free(event_queue);
+        return 255;
+    }
+
     tuning_fork_state_init(tuning_fork_state);
 
     tuning_fork_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
     if(!tuning_fork_state->mutex) {
         FURI_LOG_E("TuningFork", "cannot create mutex\r\n");
         free(tuning_fork_state);
+        furi_message_queue_free(event_queue);
         return 255;
     }
 
@@ -237,7 +412,7 @@ int32_t tuning_fork_app() {
                     // push events
                     switch(event.input.key) {
                     case InputKeyUp:
-                        if(tuning_fork_state->page == Notes) {
+                        if(tuning_fork_state->page == NotesPage) {
                             increase_volume(tuning_fork_state);
                             if(tuning_fork_state->playing) {
                                 replay(tuning_fork_state);
@@ -245,7 +420,7 @@ int32_t tuning_fork_app() {
                         }
                         break;
                     case InputKeyDown:
-                        if(tuning_fork_state->page == Notes) {
+                        if(tuning_fork_state->page == NotesPage) {
                             decrease_volume(tuning_fork_state);
                             if(tuning_fork_state->playing) {
                                 replay(tuning_fork_state);
@@ -253,7 +428,11 @@ int32_t tuning_fork_app() {
                         }
                         break;
                     case InputKeyRight:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
+                            next_instrument(tuning_fork_state);
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            next_variation(tuning_fork_state);
+                        } else if(tuning_fork_state->page == TuningsPage) {
                             next_tuning(tuning_fork_state);
                         } else {
                             next_note(tuning_fork_state);
@@ -263,7 +442,11 @@ int32_t tuning_fork_app() {
                         }
                         break;
                     case InputKeyLeft:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
+                            prev_instrument(tuning_fork_state);
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            prev_variation(tuning_fork_state);
+                        } else if(tuning_fork_state->page == TuningsPage) {
                             prev_tuning(tuning_fork_state);
                         } else {
                             prev_note(tuning_fork_state);
@@ -273,8 +456,12 @@ int32_t tuning_fork_app() {
                         }
                         break;
                     case InputKeyOk:
-                        if(tuning_fork_state->page == Tunings) {
-                            tuning_fork_state->page = Notes;
+                        if(tuning_fork_state->page == InstrumentsPage) {
+                            tuning_fork_state->page = VariationsPage;
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            tuning_fork_state->page = TuningsPage;
+                        } else if(tuning_fork_state->page == TuningsPage) {
+                            tuning_fork_state->page = NotesPage;
                         } else {
                             tuning_fork_state->playing = !tuning_fork_state->playing;
                             if(tuning_fork_state->playing) {
@@ -285,13 +472,17 @@ int32_t tuning_fork_app() {
                         }
                         break;
                     case InputKeyBack:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
                             processing = false;
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            tuning_fork_state->page = InstrumentsPage;
+                        } else if(tuning_fork_state->page == TuningsPage) {
+                            tuning_fork_state->page = VariationsPage;
                         } else {
                             tuning_fork_state->playing = false;
                             tuning_fork_state->current_tuning_note_index = 0;
                             stop();
-                            tuning_fork_state->page = Tunings;
+                            tuning_fork_state->page = TuningsPage;
                         }
                         break;
                     default:
@@ -305,7 +496,11 @@ int32_t tuning_fork_app() {
                     case InputKeyDown:
                         break;
                     case InputKeyRight:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
+                            next_instrument(tuning_fork_state);
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            next_variation(tuning_fork_state);
+                        } else if(tuning_fork_state->page == TuningsPage) {
                             next_tuning(tuning_fork_state);
                         } else {
                             next_note(tuning_fork_state);
@@ -316,7 +511,11 @@ int32_t tuning_fork_app() {
 
                         break;
                     case InputKeyLeft:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
+                            prev_instrument(tuning_fork_state);
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            prev_variation(tuning_fork_state);
+                        } else if(tuning_fork_state->page == TuningsPage) {
                             prev_tuning(tuning_fork_state);
                         } else {
                             prev_note(tuning_fork_state);
@@ -329,12 +528,16 @@ int32_t tuning_fork_app() {
                     case InputKeyOk:
                         break;
                     case InputKeyBack:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
                             processing = false;
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            tuning_fork_state->page = InstrumentsPage;
+                        } else if(tuning_fork_state->page == TuningsPage) {
+                            tuning_fork_state->page = VariationsPage;
                         } else {
                             tuning_fork_state->playing = false;
                             stop();
-                            tuning_fork_state->page = Tunings;
+                            tuning_fork_state->page = TuningsPage;
                             tuning_fork_state->current_tuning_note_index = 0;
                         }
                         break;
@@ -349,7 +552,11 @@ int32_t tuning_fork_app() {
                     case InputKeyDown:
                         break;
                     case InputKeyRight:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
+                            next_instrument(tuning_fork_state);
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            next_variation(tuning_fork_state);
+                        } else if(tuning_fork_state->page == TuningsPage) {
                             next_tuning(tuning_fork_state);
                         } else {
                             next_note(tuning_fork_state);
@@ -360,7 +567,11 @@ int32_t tuning_fork_app() {
 
                         break;
                     case InputKeyLeft:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
+                            prev_instrument(tuning_fork_state);
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            prev_variation(tuning_fork_state);
+                        } else if(tuning_fork_state->page == TuningsPage) {
                             prev_tuning(tuning_fork_state);
                         } else {
                             prev_note(tuning_fork_state);
@@ -373,12 +584,16 @@ int32_t tuning_fork_app() {
                     case InputKeyOk:
                         break;
                     case InputKeyBack:
-                        if(tuning_fork_state->page == Tunings) {
+                        if(tuning_fork_state->page == InstrumentsPage) {
                             processing = false;
+                        } else if(tuning_fork_state->page == VariationsPage) {
+                            tuning_fork_state->page = InstrumentsPage;
+                        } else if(tuning_fork_state->page == TuningsPage) {
+                            tuning_fork_state->page = VariationsPage;
                         } else {
                             tuning_fork_state->playing = false;
                             stop();
-                            tuning_fork_state->page = Tunings;
+                            tuning_fork_state->page = TuningsPage;
                             tuning_fork_state->current_tuning_note_index = 0;
                         }
                         break;

+ 230 - 148
tunings.h

@@ -1,34 +1,232 @@
-#include "notes.h"
+#ifndef TUNINGS_H
+#define TUNINGS_H
 
-#ifndef TUNINGS
-#define TUNINGS
-
-typedef struct {
-    char label[20];
-    float frequency;
-} NOTE;
-
-typedef struct {
-    char label[20];
-    int notes_length;
-    NOTE notes[20];
-} TUNING;
-
-const TUNING TuningForks = {
-    "Tuning forks",
-    6,
-    {
-        {"Common A4 (440)", 440.00f},
-        {"Sarti's A4 (436)", 436.00f},
-        {"1858 A4 (435)", 435.00f},
-        {"Verdi's A4 (432)", 432.00f},
-        {"1750-1820 A4 (423.5)", 423.50f},
-        {"Verdi's C4 (256.00)", 256.00f},
-    }};
+#include <stdint.h>
+#include "constants.h"
+#include "types.h"
+#include "notes.h"
 
+// GUITAR
+// 6 strings
+const TUNING Guitar6Standard = {
+    "Standard",
+    {{"String 1 (E4)", E4},
+     {"String 2 (B3)", B3},
+     {"String 3 (G3)", G3},
+     {"String 4 (D3)", D3},
+     {"String 5 (A2)", A2},
+     {"String 6 (E2)", E2}},
+    6};
+
+const TUNING Guitar6DropD = {
+    "Drop D",
+    {{"String 1 (E4)", E4},
+     {"String 2 (B3)", B3},
+     {"String 3 (G3)", G3},
+     {"String 4 (D3)", D3},
+     {"String 5 (A2)", A2},
+     {"String 6 (D2)", D2}},
+    6};
+
+const TUNING Guitar6DADGAD = {
+    "DADGAD (Dsus4)",
+    {{"String 1 (D4)", D4},
+     {"String 2 (A3)", A3},
+     {"String 3 (G3)", G3},
+     {"String 4 (D3)", D3},
+     {"String 5 (A2)", A2},
+     {"String 6 (D2)", D2}},
+    6};
+
+const TUNING Guitar6D = {
+    "Standard D",
+    {{"String 1 (D4)", D4},
+     {"String 2 (A3)", A3},
+     {"String 3 (F3)", F3},
+     {"String 4 (C3)", C3},
+     {"String 5 (G2)", G2},
+     {"String 6 (D2)", D2}},
+    6};
+
+const TUNING Guitar6CGCFGCSharp = {
+    "C#G#C#F#G#C#(C#sus4)",
+    {{"String 1 (C#4)", Cs4},
+     {"String 2 (G#3)", Gs3},
+     {"String 3 (F#3)", Fs3},
+     {"String 4 (C#3)", Cs3},
+     {"String 5 (G#2)", Gs2},
+     {"String 6 (C#2)", Cs2}},
+    6};
+
+const TUNING Guitar6DropC = {
+    "Drop C",
+    {{"String 1 (D4)", D4},
+     {"String 2 (A3)", A3},
+     {"String 3 (F3)", F3},
+     {"String 4 (C3)", C3},
+     {"String 5 (G2)", G2},
+     {"String 6 (C2)", C2}},
+    6};
+
+const TUNING Guitar6CGCFGC = {
+    "CGCFGC (Csus4)",
+    {{"String 1 (C4)", C4},
+     {"String 2 (G3)", G3},
+     {"String 3 (F3)", F3},
+     {"String 4 (C3)", C3},
+     {"String 5 (G2)", G2},
+     {"String 6 (C2)", C2}},
+    6};
+
+// 7 strings
+const TUNING Guitar7Standard = {
+    "Standard",
+    {{"String 1 (E4)", E4},
+     {"String 2 (B3)", B3},
+     {"String 3 (G3)", G3},
+     {"String 4 (D3)", D3},
+     {"String 5 (A2)", A2},
+     {"String 6 (E2)", E2},
+     {"String 7 (B1)", B1}},
+    7};
+
+const TUNING Guitar7DropA = {
+    "Drop A",
+    {{"String 1 (E4)", E4},
+     {"String 2 (B3)", B3},
+     {"String 3 (G3)", G3},
+     {"String 4 (D3)", D3},
+     {"String 5 (A2)", A2},
+     {"String 6 (E2)", E2},
+     {"String 7 (A1)", A1}},
+    7};
+
+const TUNING Guitar7A = {
+    "Standard A",
+    {{"String 1 (D4)", D4},
+     {"String 2 (A3)", A3},
+     {"String 3 (F3)", F3},
+     {"String 4 (C3)", C3},
+     {"String 5 (G2)", G2},
+     {"String 6 (D2)", D2},
+     {"String 7 (A1)", A1}},
+    7};
+
+// BASS
+// 4 strings
+const TUNING Bass4Standard = {
+    "Standard",
+    {{"String 1 (G2)", G2}, {"String 2 (D2)", D2}, {"String 3 (A1)", A1}, {"String 4 (E1)", E1}},
+    4};
+
+const TUNING Bass4Tenor = {
+    "Tenor",
+    {{"String 1 (C3)", C3}, {"String 2 (G2)", G2}, {"String 3 (D2)", D2}, {"String 4 (A1)", A1}},
+    4};
+
+const TUNING Bass4DropD = {
+    "Drop D",
+    {{"String 1 (G2)", G2}, {"String 2 (D2)", D2}, {"String 3 (A1)", A1}, {"String 4 (D1)", D1}},
+    4};
+
+const TUNING Bass4D = {
+    "Standard D",
+    {{"String 1 (F2)", F2}, {"String 2 (C2)", C2}, {"String 3 (G1)", G1}, {"String 4 (D1)", D1}},
+    4};
+
+const TUNING Bass4DropCSharp = {
+    "Drop C#",
+    {{"String 1 (F#2)", Fs2},
+     {"String 2 (C#2)", Cs2},
+     {"String 3 (G#1)", Gs1},
+     {"String 4 (C#1)", Cs1}},
+    4};
+
+const TUNING Bass4DropC = {
+    "Drop C",
+    {{"String 1 (F2)", F2}, {"String 2 (C2)", C2}, {"String 3 (G1)", G1}, {"String 4 (C1)", C1}},
+    4};
+
+// 5 strings
+const TUNING Bass5Standard = {
+    "Standard",
+    {{"String 1 (G2)", G2},
+     {"String 2 (D2)", D2},
+     {"String 3 (A1)", A1},
+     {"String 4 (E1)", E1},
+     {"String 5 (B0)", B0}},
+    5};
+
+const TUNING Bass5Tenor = {
+    "Tenor",
+    {{"String 1 (C3)", C3},
+     {"String 2 (G2)", G2},
+     {"String 3 (D2)", D2},
+     {"String 4 (A1)", A1},
+     {"String 5 (E1)", E1}},
+    5};
+
+const TUNING Bass5DropA = {
+    "Drop A",
+    {{"String 1 (G2)", G2},
+     {"String 2 (D2)", D2},
+     {"String 3 (A1)", A1},
+     {"String 4 (E1)", E1},
+     {"String 5 (A0)", A0}},
+    5};
+
+// UKULELE
+// 4 strings
+const TUNING Ukulele4Standard = {
+    "Standard",
+    {{"String 1 (A4)", A4}, {"String 2 (E4)", E4}, {"String 3 (C4)", C4}, {"String 4 (G4)", G4}},
+    4};
+
+// BANJO
+// 5 strings
+const TUNING Banjo5Standard = {
+    "Standard",
+    {{"String 1 (D4)", D4},
+     {"String 2 (B3)", B3},
+     {"String 3 (G3)", G3},
+     {"String 4 (D3)", D3},
+     {"String 5 (G4)", G4}},
+    5};
+
+// CIGAR BOX
+// 3 strings
+const TUNING CigarBox3OpenG = {
+    "Open G",
+    {{"String 1 (G3)", G3}, {"String 2 (D3)", D3}, {"String 3 (G2)", G2}},
+    3};
+
+const TUNING CigarBox3OpenD = {
+    "Open D",
+    {{"String 1 (Fs4)", Fs4}, {"String 2 (A3)", A3}, {"String 3 (D3)", D3}},
+    3};
+
+const TUNING CigarBox3OpenA = {
+    "Open A",
+    {{"String 1 (A4)", A4}, {"String 2 (E4)", E4}, {"String 3 (A3)", A3}},
+    3};
+
+// 4 strings
+const TUNING CigarBox4OpenG = {
+    "Open G",
+    {{"String 1 (D4)", D4}, {"String 2 (B3)", B3}, {"String 3 (G3)", G3}, {"String 4 (D3)", D3}},
+    4};
+
+// MISCELLANEOUS
+// Fork Tunings
+const TUNING ForkCommon = {"Common", {{"A4 (440Hz)", 440.00f}}, 1};
+const TUNING ForkSarti = {"Sarti's", {{"A4 (436Hz)", 436.00f}}, 1};
+const TUNING ForkMid19Century = {"1858", {{"A4 (435Hz)", 435.00f}}, 1};
+const TUNING Fork18Century = {"1750-1820", {{"A4 (423.5Hz)", 423.50f}}, 1};
+const TUNING ForkVerdi = {"Verdi's", {{"C4 (256Hz)", 256.00f}}, 1};
+
+// Other Tunings
 const TUNING ScientificPitch = {
-    "Scientific pitch",
-    12,
+    "Scientific Pitch",
     {{"C0 (16Hz)", 16.0f},
      {"C1 (32Hz)", 32.0f},
      {"C2 (64Hz)", 64.0f},
@@ -40,123 +238,7 @@ const TUNING ScientificPitch = {
      {"C8 (4096Hz)", 4096.0f},
      {"C9 (8192Hz)", 8192.0f},
      {"C10 (16384Hz)", 16384.0f},
-     {"C11 (32768Hz)", 32768.0f}}};
-
-const TUNING GuitarStandard6 = {
-    "Guitar Standard 6",
-    6,
-    {{"String 1", E4},
-     {"String 2", B3},
-     {"String 3", G3},
-     {"String 4", D3},
-     {"String 5", A2},
-     {"String 6", E2}}};
-
-const TUNING GuitarDropD6 = {
-    "Guitar Drop D 6",
-    6,
-    {{"String 1", E4},
-     {"String 2", B3},
-     {"String 3", G3},
-     {"String 4", D3},
-     {"String 5", A2},
-     {"String 6", D2}}};
-
-const TUNING GuitarD6 = {
-    "Guitar D 6",
-    6,
-    {{"String 1", D4},
-     {"String 2", A3},
-     {"String 3", F3},
-     {"String 4", C3},
-     {"String 5", G2},
-     {"String 6", D2}}};
-
-const TUNING GuitarDropC6 = {
-    "Guitar Drop C 6",
-    6,
-    {{"String 1", D4},
-     {"String 2", A3},
-     {"String 3", F3},
-     {"String 4", C3},
-     {"String 5", G2},
-     {"String 6", C2}}};
-
-const TUNING GuitarStandard7 = {
-    "Guitar Standard 7",
-    7,
-    {{"String 1", E4},
-     {"String 2", B3},
-     {"String 3", G3},
-     {"String 4", D3},
-     {"String 5", A2},
-     {"String 6", E2},
-     {"String 7", B1}}};
-
-const TUNING BassStandard4 = {
-    "Bass Standard 4",
-    4,
-    {{"String 1", G2}, {"String 2", D2}, {"String 3", A1}, {"String 4", E1}}};
-
-const TUNING BassStandardTenor4 = {
-    "Bass Stand Tenor 4",
-    4,
-    {{"String 1", C3}, {"String 2", G2}, {"String 3", D2}, {"String 4", A1}}};
-
-const TUNING BassStandard5 = {
-    "Bass Standard 5",
-    5,
-    {{"String 1", G2}, {"String 2", D2}, {"String 3", A1}, {"String 4", E1}, {"String 5", B0}}};
-
-const TUNING BassStandardTenor5 = {
-    "Bass Stand Tenor 5",
-    5,
-    {{"String 1", C3}, {"String 2", G2}, {"String 3", D2}, {"String 4", A1}, {"String 5", E1}}};
-
-const TUNING BassDropD4 = {
-    "Bass Drop D 4",
-    4,
-    {{"String 1", G2}, {"String 2", D2}, {"String 3", A1}, {"String 4", D1}}};
-
-const TUNING BassD4 = {
-    "Bass D 4",
-    4,
-    {{"String 1", F2}, {"String 2", C2}, {"String 3", G1}, {"String 4", D1}}};
-
-const TUNING BassDropA5 = {
-    "Bass Drop A 5",
-    5,
-    {{"String 1", G2}, {"String 2", D2}, {"String 3", A1}, {"String 4", E1}, {"String 5", A0}}};
-
-const TUNING UkuleleStandard4 = {
-    "Ukulele Standard 4", 4, {
-    {"String 1", A4},
-    {"String 2", E4},
-    {"String 3", C4},
-    {"String 4", G4}
-  }
-};
-
-#define TUNINGS_COUNT 15
-
-TUNING TuningList[TUNINGS_COUNT] = {
-    ScientificPitch,
-    TuningForks,
-
-    GuitarStandard6,
-    GuitarDropD6,
-    GuitarD6,
-    GuitarDropC6,
-    GuitarStandard7,
-
-    BassStandard4,
-    BassStandardTenor4,
-    BassStandard5,
-    BassStandardTenor5,
-    BassDropD4,
-    BassD4,
-    BassDropA5,
-    UkuleleStandard4
-};
-
-#endif //TUNINGS
+     {"C11 (32768Hz)", 32768.0f}},
+    12};
+
+#endif //TUNINGS_H

+ 25 - 0
types.h

@@ -0,0 +1,25 @@
+#include <stdint.h>
+#include "constants.h"
+
+typedef struct {
+    char label[MAX_LABEL_LENGTH];
+    float frequency;
+} NOTE;
+
+typedef struct {
+    char label[MAX_LABEL_LENGTH];
+    NOTE notes[MAX_NOTES_PER_TUNING];
+    uint8_t notes_count;
+} TUNING;
+
+typedef struct {
+    char label[MAX_LABEL_LENGTH];
+    TUNING* tunings;
+    uint8_t tunings_count;
+} VARIATION;
+
+typedef struct {
+    char label[MAX_LABEL_LENGTH];
+    VARIATION* variations;
+    uint8_t variations_count;
+} INSTRUMENT;