Playing unique blade array audio idents on live array switching

Ok, I’ve been wrestling with this all weekend, and I can only conclude that somehow I’m not accessing the system sound player correctly. Just wondering if any coding wizards might be able to spot where I’m going wrong.

The Challenge
I’ve set up array switching which works great, and currently plays the bladein.wav file on every switch. What I want is the system to play unique array idents from the common folder with every switch, so switching to Array 1 plays array1.wav, Array 2 plays array2.wav etc. I know I can fudge the functionality with prefont folders and various unique bladein.wav files, but that makes SD card management a bit clunky - a series of unique array.wav files all stored together in common is much tidier.

Of course this is a departure from the way ProffieOS normally handles sounds, because normally the system will randomly select, say, one clsh.wav from any number of clsh.wav files available. But in this instance, I want each numbered arrayX.wav to be locked to its associated numbered array.

So to get started, I borrowed this piece of code which I know works to play a ‘click’ wav file with every button press:

    void PlaySound(const char* sound) {
      RefPtr<BufferedWavPlayer> player = GetFreeWavPlayer();
       if (player) {
         if (!player->PlayInCurrentDir(sound)) player->Play(sound);
       }
    }            
    bool Event2(enum BUTTON button, EVENT event, uint32_t modifiers) override {      
      switch (EVENTID(button, event, modifiers)) {
        case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_ON):
        case EVENTID(BUTTON_POWER, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_OFF):
        case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_ON):
        case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ANY_BUTTON | MODE_OFF):
          SaberBase::RequestMotion();
          PlaySound("press.wav");
            return false;
        case EVENTID(BUTTON_POWER, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
        case EVENTID(BUTTON_POWER, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_OFF):
        case EVENTID(BUTTON_AUX, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_ON):
        case EVENTID(BUTTON_AUX, EVENT_RELEASED, MODE_ANY_BUTTON | MODE_OFF):
          PlaySound("release.wav");
          if (SaberBase::Lockup()) {
            SaberBase::DoEndLockup();
            SaberBase::SetLockup(SaberBase::LOCKUP_NONE);
          return true;
        } else {
          return false;
        }
        case EVENTID(BUTTON_AUX, EVENT_PRESSED, MODE_ON):
        case EVENTID(BUTTON_AUX2, EVENT_PRESSED, MODE_ON):
          if (accel_.x < -0.15) {
            pointing_down_ = true;
          } else {
            pointing_down_ = false;
          }
          return true;

And I peeled out the irrelevant bits and stitched it into this code which handles the array switching so this it would hopefully access the system player and play each respective arrayX.wav with every array switch:

#ifdef SABERSENSE_ARRAY_SELECTOR
  #ifndef SABERSENSE_NUM_ARRAYS    // No default number of arrays - must be defined in config.
    #error "SABERSENSE_NUM_ARRAYS must be defined in the config file."
  #endif

  // Function to play the corresponding sound.
  void PlaySound(const char* sound) {
    RefPtr<BufferedWavPlayer> player = GetFreeWavPlayer();
    if (player) {
      if (!player->PlayInCurrentDir(sound)) {
        player->Play(sound); // Fallback if not found in the current directory.
      }
    }
  }

  struct SabersenseArraySelector {
    static int return_value; // Tracks the current array index.
    static const int sabersense_num_arrays = SABERSENSE_NUM_ARRAYS;
    
    float id() { 
      return return_value; 
    }
    
    static void playArraySound(int arrayIndex) {
      // Determine the sound file based on the array index.
      const char* soundFile = nullptr;
      
      switch (arrayIndex) {
        case 0:
          soundFile = "array1.wav";
          break;
        case 1:
          soundFile = "array2.wav";
          break;
        case 2:
          soundFile = "array3.wav";
          break;
        case 3:
          soundFile = "array4.wav";
          break;
        case 4:
          soundFile = "array5.wav";
          break;
        case 5:
          soundFile = "array6.wav";
          break;
        case 6:
          soundFile = "array7.wav";
          break;
        case 7:
          soundFile = "array8.wav";
          break;
        case 8:
          soundFile = "array9.wav";
          break;
        default:
          return; // No sound for invalid array index.
      }

      // Play the corresponding sound file using the PlaySound function.
      PlaySound(soundFile); // Calls your custom PlaySound function.
    }
    
    static void cycle() {
      return_value = (return_value + 1) % sabersense_num_arrays;
      playArraySound(return_value); // Play the sound corresponding to the current array.
    }
  };

  int SabersenseArraySelector::return_value = 0; // Start with the first array (index 0).

  #undef BLADE_ID_CLASS_INTERNAL
  #define BLADE_ID_CLASS_INTERNAL SabersenseArraySelector
  #undef BLADE_ID_CLASS
  #define BLADE_ID_CLASS SabersenseArraySelector

#endif

With the event handled like this:

  // BladeID and manual blade array selector.
    case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
#ifdef SABERSENSE_ARRAY_SELECTOR
      // Cycles through blade arrays regardless of BladeID status.
      SabersenseArraySelector::cycle();
      FindBladeAgain();
      SaberBase::DoBladeDetect(true);
      return true;
#else
      // Runs BladeID manually to actually check BladeID status.
      // Won't change arrays unless status tells it to (i.e. Data/Neg resistance changes).
      FindBladeAgain();
      SaberBase::DoBladeDetect(true);
      return true;
#endif

Now by rights, I make it that it should play both bladein.wav and the new array.wav files with every switch. (I know that’s a conflict, but one step at a time). But although it all compiles and loads up successfully, and it does the array switch correctly, it doesn’t play the array.wav files, only the bladein files.

I’ve tried all sorts of different combos, but I just can’t nail it.

As such, any thoughts welcome.
Thanks in advance. :slight_smile:

Done some debugging and it seems the array file is playing:

16:40:12.020 -> EVENT: Power-SavedShortclick#3 millis=55287
16:40:12.020 -> Playing sound: array2.wav
16:40:12.020 -> Playing array2.wav, channels: 1 rate: 44100 bits: 16
16:40:12.020 -> ID: 1.00

And I know the player works because my clicker buttons play correctly:

16:43:20.493 -> EVENT: Power-Pressed#1 millis=80604
16:43:20.493 -> EVENT: Power-Pressed millis=80604
16:43:20.493 -> Playing press.wav, channels: 1 rate: 44100 bits: 16
16:43:20.565 -> Unmounting SD Card.
16:43:20.565 -> EVENT: Power-Released#1 millis=80676
16:43:20.565 -> EVENT: Power-Released millis=80676
16:43:20.565 -> Playing release.wav, channels: 1 rate: 44100 bits: 16

I’ve checked the array wav files - they exist both in the same folder as the play/release effects and also on the top level of the SD card just in case. Specs are right (44.1kHz, 16 bit mono) and if I rename them to bladein.wav or some other sound file that plays correctly, they work.

So why can I not hear them when the system plays them as array idents?

I’m stumped! :confused:

Just tried removing the
SaberBase::DoBladeDetect(true);
line from the event handler in case playing the bladein.wav was causing conflicts. No change other than the bladein.wav not playing and the switch happening silently. :confused:

I think the problem is that the sound system is murdered when you switch presets.
All playing sound is stopped, all sound players are freed, font folders are re-scanned and then everything is started up again, but possibly in a very different state depending on what files are found.

You need to play your sound after switching to the new array rather than before.

:partying_face: :sparkler:

Yyeesss!
Thanks Prof! That set me on the right path and I’ve managed to get it going!
Very happy! :smiley: :pray:

The only tiny fly in the ointment is that if I have my blade plug charging preset (the BlackPower one) as a single preset on an array, then it won’t play the effect, even though the path and the file are all there. I’m guessing that’s because BlackPower shuts down everything, including amplifiers, apart from LED pads, so that current draws don’t confuse the external charging setup. I don’t know if that’s fixable or not, but I have a hunch it would be quite involved! As such, that’s one limitation I think I can live with. :slight_smile:

Thanks again. :slight_smile:

I don’t think the BlackPower style should have any effect on audio at all.

Hmmmm…
I’ve done some more digging this morning, and Prof, you’re right - the BlackPower thing was a red herring.
It turns out the system will only play idents for the first three arrays. The code is set to handle a maximum of eight, and all the wav files are present and correct on the SD card and properly referenced in the folder path on the presets. The system is performing the array switch correctly, but not playing the audio file on any arrays above 3.
But the code doesn’t appear to impose any such limitation, so I can’t understand why it’s happening. Since this whole feature is new, I can’t imagine there’s anything in the wider OS that would impose this restriction.
Or is there…?
Once again I’m stumped. But here’s the code that’s making it happen in case anyone can spot any gremlins:

#ifdef SABERSENSE_ARRAY_SELECTOR
  #ifndef SABERSENSE_NUM_ARRAYS    // No default number of arrays - must be defined in config.
    #error "SABERSENSE_NUM_ARRAYS must be defined in the config file."
  #endif

  // Function to play the corresponding sound.
  void PlaySound(const char* sound) {
    RefPtr<BufferedWavPlayer> player = GetFreeWavPlayer();
    if (player) {
      if (!player->PlayInCurrentDir(sound)) {
        player->Play(sound);
      }
    }
  }

struct SabersenseArraySelector {
    static int return_value;  // Tracks the current array index.
    static const int sabersense_num_arrays = SABERSENSE_NUM_ARRAYS;
    static bool shouldPlaySound;  // Flag to control if sound should be played.
    static unsigned long lastSwitchTime;  // Track time of the last array switch.
    static const unsigned long soundDelay = 200;  // Delay in ms before playing sound after switch.
    static bool isSwitchingInProgress;  // Flag to indicate if array switch is in progress.

    float id() { 
      return return_value; 
    }

    // Forward cycle through arrays...
    static void cycleForward() {
      isSwitchingInProgress = true;  // Mark that the switch is in progress.
      return_value = (return_value + 1) % sabersense_num_arrays;
      shouldPlaySound = true;
      lastSwitchTime = millis();
      isSwitchingInProgress = false;  // Mark that the switch is complete.
    }

    // Backward cycle through arrays.
    static void cycleBackward() {
      isSwitchingInProgress = true;  // Mark that the switch is in progress
      return_value = (return_value - 1 + sabersense_num_arrays) % sabersense_num_arrays; // Ensures wrap.
      shouldPlaySound = true;
      lastSwitchTime = millis();
      isSwitchingInProgress = false;  // Mark that the switch is complete.
    }

    // Function to play corresponding sound file based on array index.
    static void playArraySound(int arrayIndex) {
      const char* soundFile = nullptr;
      switch (arrayIndex) {
        //  Maximum of eight arrays possible.
        case 0: soundFile = "array1.wav"; break;
        case 1: soundFile = "array2.wav"; break;
        case 2: soundFile = "array3.wav"; break;
        case 3: soundFile = "array4.wav"; break;
        case 4: soundFile = "array5.wav"; break;
        case 5: soundFile = "array6.wav"; break;
        case 6: soundFile = "array7.wav"; break;
        case 7: soundFile = "array8.wav"; break;
        default: return;  // No sound for invalid array index.
      }
      PlaySound(soundFile);  // Calls custom PlaySound function.
    }

    // Function to check enough time has passed to play the sound.
    static void checkAndPlaySound() {
      if (shouldPlaySound && !isSwitchingInProgress && (millis() - lastSwitchTime >= soundDelay)) {
        playArraySound(return_value);  // Play sound for the current array.
        shouldPlaySound = false;  // Reset flag after sound is played.
      }
    }

    // Loop function, needs to be called periodically.
    static void loop() {
      checkAndPlaySound();  // Check if sound should be played after switching arrays.
    }
  };

  // Static member initialization
  int SabersenseArraySelector::return_value = 0;  // Start with the first array (index 0).
  bool SabersenseArraySelector::shouldPlaySound = false;  // Flag to control sound playback.
  unsigned long SabersenseArraySelector::lastSwitchTime = 0;  // Track time of array switch.
  bool SabersenseArraySelector::isSwitchingInProgress = false;  // Flag for switch status.

  #undef BLADE_ID_CLASS_INTERNAL
  #define BLADE_ID_CLASS_INTERNAL SabersenseArraySelector
  #undef BLADE_ID_CLASS
  #define BLADE_ID_CLASS SabersenseArraySelector
#endif

With event handling done like this:

  // BladeID and manual blade array selector.
    case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
#ifdef SABERSENSE_ARRAY_SELECTOR
      // Cycles through blade arrays regardless of BladeID status.
      if (fusor.angle1() > 0) {
        //  Cycles forward...
        SabersenseArraySelector::cycleForward();
      } else {
        //  Cycles backward.
        SabersenseArraySelector::cycleBackward(); 
      }
      FindBladeAgain(); 
      SabersenseArraySelector::checkAndPlaySound(); 
      return true;
#else
      // Runs BladeID manually to actually check BladeID status.
      // Won't change arrays unless status tells it to (i.e. Data/Neg resistance changes).
      FindBladeAgain();
      SabersenseArraySelector::checkAndPlaySound();
      return true;
#endif

Debug code below.
It seems it’s scanning the folders but isn’t requesting any array.wav file from array 4 onwards (index 3 - they start at zero).
The question is why not? :confused:

09:38:34.938 -> EVENT: Power-SavedShortclick#3 millis=220103
09:38:34.938 -> ID: 2.00
09:38:34.938 -> blade = 2
09:38:34.938 -> WS2811 Blade with 114 leds.
09:38:34.938 -> Simple Blade
09:38:34.972 -> Style RAM = 540
09:38:34.972 -> Style RAM = 8
09:38:34.972 -> Scanning sound font: PreFont2 done
09:38:34.972 -> Scanning sound font: FontPrem/ANHGrfx1 done
09:38:35.077 -> Scanning sound font: Shared/Luke done
09:38:35.077 -> Scanning sound font: Shared/Function done
09:38:35.144 -> Activating polyphonic font.
09:38:35.182 -> Activating SmoothSwing V2
09:38:35.182 -> Accent Swings Enabled.
09:38:35.182 -> Polyphonic swings: 15
09:38:35.182 -> Monophonic swings: 0
09:38:35.182 -> Accent Slashes NOT Detected: 
09:38:35.182 -> Playing sound file: array3.wav
09:38:35.182 -> Attempting to play sound: array3.wav
09:38:35.182 -> Playing array3.wav, channels: 1 rate: 44100 bits: 16
09:38:35.216 -> Sound played successfully in current directory.
09:38:35.643 -> Battery voltage: 3.45
09:38:36.402 -> Unmounting SD Card.
09:38:36.440 -> Amplifier off.
09:38:40.259 -> EVENT: Power-Pressed#1 millis=225417
09:38:40.259 -> EVENT: Power-Pressed millis=225417
09:38:40.259 -> Playing press.wav, (not found)
09:38:40.295 -> File press.wav not found.
09:38:40.295 -> Unmounting SD Card.
09:38:40.328 -> Amplifier off.
09:38:40.328 -> EVENT: Power-Released#1 millis=225508
09:38:40.328 -> EVENT: Power-Released millis=225508
09:38:40.328 -> Playing release.wav, (not found)
09:38:40.365 -> File release.wav not found.
09:38:40.365 -> EVENT: Power-Shortclick#1 millis=225538
09:38:40.365 -> EVENT: Power-Shortclick millis=225538
09:38:40.400 -> Unmounting SD Card.
09:38:40.400 -> Amplifier off.
09:38:40.474 -> EVENT: Power-Pressed#2 millis=225621
09:38:40.474 -> EVENT: Power-Pressed millis=225621
09:38:40.474 -> Playing press.wav, (not found)
09:38:40.508 -> File press.wav not found.
09:38:40.508 -> Unmounting SD Card.
09:38:40.546 -> Amplifier off.
09:38:40.546 -> EVENT: Power-Released#2 millis=225691
09:38:40.546 -> EVENT: Power-Released millis=225692
09:38:40.546 -> Playing release.wav, (not found)
09:38:40.546 -> File release.wav not found.
09:38:40.546 -> EVENT: Power-Shortclick#2 millis=225723
09:38:40.546 -> EVENT: Power-Shortclick millis=225723
09:38:40.583 -> Unmounting SD Card.
09:38:40.618 -> Amplifier off.
09:38:40.618 -> EVENT: Power-Pressed#3 millis=225796
09:38:40.618 -> EVENT: Power-Pressed millis=225796
09:38:40.618 -> Playing press.wav, (not found)
09:38:40.656 -> File press.wav not found.
09:38:40.690 -> Unmounting SD Card.
09:38:40.690 -> Amplifier off.
09:38:40.723 -> EVENT: Power-Released#3 millis=225890
09:38:40.723 -> EVENT: Power-Released millis=225890
09:38:40.723 -> Playing release.wav, (not found)
09:38:40.761 -> File release.wav not found.
09:38:40.761 -> EVENT: Power-Shortclick#3 millis=225921
09:38:40.761 -> EVENT: Power-Shortclick millis=225921
09:38:40.798 -> Unmounting SD Card.
09:38:40.798 -> Amplifier off.
09:38:40.943 -> EVENT: Power-SavedShortclick#3 millis=226127
09:38:40.976 -> ID: 3.00
09:38:40.976 -> blade = 3
09:38:40.976 -> WS2811 Blade with 10 leds.
09:38:40.976 -> Simple Blade
09:38:40.976 -> Style RAM = 412
09:38:40.976 -> Style RAM = 8
09:38:40.976 -> Scanning sound font: PreFont2 done
09:38:40.976 -> Scanning sound font: Spare2 done
09:38:41.011 -> Scanning sound font: Shared/Spare2 done
09:38:41.011 -> Scanning sound font: Shared/Function done
09:38:41.044 -> Activating polyphonic font.
09:38:41.044 -> Activating SmoothSwing V2
09:38:41.044 -> Accent Swings NOT Detected: 
09:38:41.044 -> Unmounting SD Card.
09:38:55.662 -> Battery voltage: 3.46

Without seeing the complete file(s) I only have one guess:
Maybe it’s failing to get a free wav player?
(Not sure why that would happen though.)

The complete files are here below.
The rest is ProffieOS 7.14.

1 Like

And where on the SD card are these array files stored?

They’re all in my version of the common folder (which is actually Shared/Function on my test saber). They don’t exist anywhere else on the SD card (I checked) and the system seems able to find the first three - just not the rest. All files were produced at the same time and I even renamed array4 to array3 temporarily to see if it played and it did, so the files are definitely the correct format.

I think the problem is that SaberSenseArraySelector::loop() is never called anywhere.
That means that checkAndPlaySound is only called once, and if it hasn’t been long enough (which depends on how long it takes to scan the font directories) then it won’t play.

As always prof, you set me onto the correct investigative path, and I think I’ve now cracked it - it was a combination of the call thing and also the delay which was initially added to give the system time to complete all the array switch processes before playing the wav, but it seems it was set too long at 200ms. I’ve now dropped it to 50ms and all seems to work.

Now I have to decide if, in the interests of consistency, I try to modify the true BladeID function - which I’ve also made available on a button press using a define, but rather than switch arrays manually it actually performs the scan and switches to the correct array - be accompanied by also playing arrayX.wav files.

Think I need to sleep on that one, as early indications are that it will be tricky.

Anyway thanks again for steering me in the right direction on the first thing. :pray: :slight_smile:

2 Likes

I need to learn when to stop! Been trying to get this new feature working whereby true BladeID plays a unique array file associated with each array. With my manual ARRAY_SELECTOR this could be done using the index numbers on each array for the system to know which array it had switched to. But of course with true BladeID, that number is used to hold the scan results against which the next BladeID scan is compared.

So the challenge has been how do we make the system recognise that, say, the third array down the list (which would normally be index 2 but on my BladeID is shown as 64) actually plays the wav file array3.wav?

I’ve got as far as making it successfully switch arrays and play a wav file, but it always plays the same wav (array1.wav).

Below is where I’ve got to so far, but I guess my main question before I pursue this further is, is this even possible given that there isn’t really anything concrete for the system to actually grab on to to know where each array sits in the arrays list?

#ifdef SABERSENSE_BLADE_ID
// Declare the PlaySound function at the top of the file
void PlaySound(const char* sound) {
  Serial.print("Attempting to play sound: ");
  Serial.println(sound);

  RefPtr<BufferedWavPlayer> player = GetFreeWavPlayer();
  if (player) {
    Serial.println("Free player found.");
    if (!player->PlayInCurrentDir(sound)) {
      Serial.println("Failed to play in current directory, trying default directory...");
      player->Play(sound);
    } else {
      Serial.println("Sound played successfully.");
    }
  } else {
    Serial.println("No free WAV player available.");
  }
}

// SabersenseBladeID class definition (this should be after PlaySound)
struct SabersenseBladeID {
    static int return_value;  // Tracks the current array index (BladeID).
    static bool isSwitchingInProgress;  // Flag to indicate if array switch is in progress.
    static unsigned long lastSwitchTime;  // Track time of the last array switch.
    static const unsigned long soundDelay = 50;  // Delay in ms before playing sound after switch.

    // This method will return the current Blade ID
    float id() { 
      return return_value; 
    }

    // Function to get the sound file based on the current Blade ID (array index).
    static const char* getSoundFileForCurrentArray() {
      static char soundFileName[32];

      // Access return_value via the SabersenseBladeID class
      snprintf(soundFileName, sizeof(soundFileName), "array%d.wav", return_value + 1); // 1-based index for filenames
      
      return soundFileName;
    }

    // Function to trigger a blade switch and play sound after switch.
    static void switchBlade(int newBladeIndex) {
      return_value = newBladeIndex;  // Update the blade ID.
      lastSwitchTime = millis();  // Update the last switch time

      // Immediately play the corresponding sound after switching
      playArraySound();  // Call the sound-playing function directly

      // Debugging: Confirm that the blade ID is being updated
      Serial.print("Switching to Blade: ");
      Serial.println(return_value);
    }

    // Function to play sound after switching to a new blade array
    static void playArraySound() {
      const char* soundFile = getSoundFileForCurrentArray();  // Get the dynamic sound file name.

      // Debugging: Print the sound file being played to the serial monitor.
      Serial.println("Playing sound: ");
      Serial.println(soundFile);

      // Now that PlaySound is global, we can call it directly
      PlaySound(soundFile);  // Call the global PlaySound function
    }
};

// Static member initialization
int SabersenseBladeID::return_value = 0;
bool SabersenseBladeID::isSwitchingInProgress = false;
unsigned long SabersenseBladeID::lastSwitchTime = 0;
#endif

Event handler:

#ifdef SABERSENSE_BLADE_ID
  case EVENTID(BUTTON_POWER, EVENT_THIRD_SAVED_CLICK_SHORT, MODE_OFF):
    FindBladeAgain();  // Perform the scan and find the blade ID
    Serial.println("Switching blade...");
    SabersenseBladeID::switchBlade(SabersenseBladeID::return_value);  // Directly switch the blade and play the sound
    return true;
#endif

Array:

BladeConfig blades[] = {
   { 76, //  Used by FindBladeAgain to match array to xternal scanned value. 
//  Main Blade:
 	WS281XBladePtr<8, bladePin, Color8::GRB, PowerPINS<bladePowerPin2, bladePowerPin3>>(),
//  Bluetooth Module:   
    SimpleBladePtr<Bluetooth, NoLED, NoLED, NoLED, bladePowerPin6, -1, -1, -1>(),   
   CONFIGARRAY(noblade), "save1"}, 
   
   { 71, //  Used by FindBladeAgain to match array to xternal scanned value. 
//  Main Blade:
 	WS281XBladePtr<68, bladePin, Color8::GRB, PowerPINS<bladePowerPin2, bladePowerPin3>>(),
//  Bluetooth Module:   
    SimpleBladePtr<Bluetooth, NoLED, NoLED, NoLED, bladePowerPin6, -1, -1, -1>(),   
   CONFIGARRAY(testblde), "save2"},
   
   { 64,  //  Used by FindBladeAgain to match array to xternal scanned value. 
//  Main Blade:
 	WS281XBladePtr<114, bladePin, Color8::GRB, PowerPINS<bladePowerPin2, bladePowerPin3>>(),
//  Bluetooth Module:   
    SimpleBladePtr<Bluetooth, NoLED, NoLED, NoLED, bladePowerPin6, -1, -1, -1>(),   
   CONFIGARRAY(lgt), "save3"},
   
   { 52, //  Used by FindBladeAgain to match array to xternal scanned value. 
//  Main Blade:
 	WS281XBladePtr<10, bladePin, Color8::GRB, PowerPINS<bladePowerPin2, bladePowerPin3>>(),
//  Bluetooth Module:   
    SimpleBladePtr<Bluetooth, NoLED, NoLED, NoLED, bladePowerPin6, -1, -1, -1>(),   
   CONFIGARRAY(charging), "save4"},
};
#endif

This is a pointer arithmetic problem, the expression you want is probably current_config - blades.

Thanks Prof.
This has got us a little closer I think, but for some reason the system keeps comparing scan results to zero rather than comparing them with the int ohm numbers in the array, and then concluding that a return value of 76 is the most different to an array value of 76 rather than being the closest, like this:

21:32:39.284 → ID: 76.00
21:32:39.284 → blade = 0
21:32:39.571 → Switching blade to ID: 0
21:32:39.571 → Error: Blade ID is 0.
21:32:39.571 → Switching blade to ID: 0
21:32:39.571 → Searching for closest blade to ID: 0
21:32:39.571 → Checking Blade: 0, Blade ID: 76, Difference: 76
21:32:39.571 → Checking Blade: 1, Blade ID: 71, Difference: 71
21:32:39.571 → Checking Blade: 2, Blade ID: 64, Difference: 64
21:32:39.571 → Checking Blade: 3, Blade ID: 52, Difference: 52
21:32:39.571 → Closest index: 3
21:32:39.571 → Attempting to play sound: array4.wav
21:32:39.571 → Playing array4.wav, channels: 1 rate: 44100 bits: 16.

So it scans and finds 76, correctly interprets that it’s the first array, correctly switches to that array under BladeID, but then decides that rather than compare the scanned value to the array values to play the wav file, it will compare them to zero… 52 is the closest to zero, so it plays array4 when it should play array1.

Anyway the good news that it feels like what I’m attempting is possible - I just need to keep plugging away until I crack it.

No it doesn’t.

It finds zero.

Ah!
OK, this could be key.

So this must mean that BladeID scans and gets a reading of 76 which it then associates with the first array, 0, and then it makes 0 the return value and then switches to that array. But my wav player effort is out of sync with the process and is expecting return values of 76, 71, 64 or 52, when it should be expecting return values of 0, 1, 2 or 3.

In other words the scan value and the return value are two different things - and my system is muddling them up somewhat.

OK, back we go. Thanks Prof - hopefully this will be the vital link I was missing. :pray:

The idea is just to cycle → next array → next array yes?
Then plays the appropriate arrayN.wav once switched?

Well I got something working, even though despite many attempts to have it work in conjunction with BLADE_ID_SCAN_MILLIS active, it seems that’s just not going to happen. If the scan result is different than a manually set blade array, it either just takes over or freezes the board :grimacing:

That said, I got it to work.

  • disable #define BLADE_ID_SCAN_MILLIS in the config file.

  • optional - add array.wavs to the font or a common folder, and EFFECT(array) to the prop

  • I ended up making a “FakeFindBladeAgain” that does what normally happens minus the part about getting the best_config. It just uses the manually set current_config.

  • This method totally disregards the resistance argument in the blade arrays. It just strictly cycles through them sequentially.

Here’s what I got in the prop file:


  void NextBladeArray() {
    current_config = blades + (current_config - blades + 1) % NELEM(blades);
    FakeFindBladeAgain();
    // option if no array.wavs used, play font.wav instead
    //  SaberBase::DoNewFont();
    SFX_array.Select(current_config - blades);
    hybrid_font.PlayCommon(&SFX_array);
  }

  // Manual Blade Array Selection version of FindBladeAgain()
  void FakeFindBladeAgain() {
    // Do everything FindBladeAgain() and FindBlade() do, except for recalculating best_config
    ONCEPERBLADE(UNSET_BLADE_STYLE)

#undef DEACTIVATE
#define DEACTIVATE(N) do {                      \
    if (current_config->blade##N)               \
      current_config->blade##N->Deactivate();   \
  } while(0);

    ONCEPERBLADE(DEACTIVATE);
    SaveVolumeIfNeeded();

#undef ACTIVATE
#define ACTIVATE(N) do {                        \
    if (!current_config->blade##N) {            \
      goto bad_blade;                           \
    }                                           \
    current_config->blade##N->Activate(N);      \
  } while(0);

    ONCEPERBLADE(ACTIVATE);
    RestoreGlobalState();

#ifdef SAVE_PRESET
    ResumePreset();
#else
    SetPreset(0, false);
#endif // SAVE_PRESET
    return;

#if NUM_BLADES != 0
  bad_blade:
    ProffieOSErrors::error_in_blade_array();
#endif
  }

Then you just call NextBladeArray() with your button event.
I didn’t bother with a reverse direction. Are there really going to be so many that just cycling through forwards isn’t good enough? Maybe, but I already spent too much overnight playing with this :slight_smile:

Anyway, that was fun.

1 Like