Attempting to add a "Reset Color" sound effect

So the saber_BC_buttons.h file has a nifty ResetColorChangeMode() function that allows the user to effectively “cancel” a color wheel change and reset the blade to its original color:

// Revert color change without saving (reset to Variation == 0)
  void ResetColorChangeMode() {
    if (!current_style()) return;
      STDOUT << "Reset Color Variation" << "\n";
      SetVariation(0);
      STDOUT << "Color change mode done, variation = 0" << "\n";
      SaberBase::SetColorChangeMode(SaberBase::COLOR_CHANGE_MODE_NONE);
  }

However, it doesn’t generate a unique sound effect that distinguishes it from any other color wheel exit. It looks like the code that governs that is in sounds/hybrid_font.h. Can I simply override that code by adding something like this to the prop file?

  void SB_Change(SaberBase::ChangeType change) override {
    switch (change) {
      case SaberBase::ENTER_COLOR_CHANGE:
        if (!hybrid_font.PlayPolyphonic(&SFX_ccbegin) && !hybrid_font.PlayPolyphonic(&SFX_color)) {
          beeper.Beep(0.20, 1000.0);
          beeper.Beep(0.20, 1414.2);
          beeper.Beep(0.20, 2000.0);
        }
        break;
      case SaberBase::EXIT_COLOR_CHANGE:
        if (SaberBase::GetCurrentVariation() == 0) {
          if (!hybrid_font.PlayPolyphonic(&SFX_ccreset)) {
            beeper.Beep(0.20, 2000.0);
            beeper.Beep(0.20, 1414.2);
            beeper.Beep(0.20, 1000.0);
          }
        } else {
          if (!hybrid_font.PlayPolyphonic(&SFX_ccend)) {
            beeper.Beep(0.20, 2000.0);
            beeper.Beep(0.20, 1414.2);
            beeper.Beep(0.20, 1000.0);
          }
        }
        break;
      case SaberBase::CHANGE_COLOR:
        if (!hybrid_font.PlayPolyphonic(&SFX_ccchange)) {
          beeper.Beep(0.05, 2000.0);
        }
        break;
    }
  }

Obviously I’d have to #include …/sound/hybrid_font.h and declare EFFECT(ccreset); but assuming I’ve done that already, would the above block work?

When customizing a prop file (speaking from experience since I used Matt’s sa22c button effects for menu sounds in Fernando’s Fett263 5.9 prop) it’s gonna come down to you personally testing the change out. Make sure it compiles clean and then test it in action. REPEATEDLY.

@NoSloppy (Brian) may be interested in this though since he’s put a ton of work in to bring about his prop as well as some other very sweet stuff.

*It’s a solid idea since it’ll help to make sure the button sounds made it easier to validate the “click” happened.

You can do it right in the prop. Just make the reset routine check for the sound you want and play it with hybrid.fontPlayCommon() and then return, else play the ccend as usual.

You can have an SB_Change function in your prop class, and it will be called, but it won’t override the one in hybrid_font.h, so both will be called. That means that hybrid_font will always try to play it’s sound, and there isn’t a whole lot you can do in the prop to change that. You can play another sound if you like, but from the code, it doesn’t seem like that’s what you want.

Checking for SaberBase::GetCurrentVariation() == 0 might not be what you want though, since you could then get the same sound by just rotating to the zero position, but maybe that’s intentional?

If this is just a hack for yourself, then the easiest option is just to make the modifications you want in hybrid_font.h. Another, much less simple option would be to build a way to change the variation that doesn’t play a sound, then play your own sound instead. This would give the control to the prop file and could be a reasonable path to something that could be checked in or distributed since it would only take space if the prop file uses it.

1 Like

Yeah, that’s the heart of what I was asking about. So the “override” in the declaration of the function really means “extend” and not “replace.” I suspected as much based on the way the rest of the prop file worked, but wasn’t sure if there was a way to actually replace the existing function. Unfortunately, it sounds like there isn’t. Thanks for the clarification.

Checking for SaberBase::GetCurrentVariation() == 0 might not be what you want though, since you could then get the same sound by just rotating to the zero position, but maybe that’s intentional?

Only in the sense that I was willing to live with that outcome in order to keep the solution simple to implement. I figured with 32768 steps in the color wheel, rotating back to zero would be unlikely enough that it wouldn’t be an issue.

If this is just a hack for yourself, then the easiest option is just to make the modifications you want in hybrid_font.h. Another, much less simple option would be to build a way to change the variation that doesn’t play a sound, then play your own sound instead. This would give the control to the prop file and could be a reasonable path to something that could be checked in or distributed since it would only take space if the prop file uses it.

Yes, that’s exactly it – I was trying not to alter any code outside the prop file so that I could check it in when I had it finished and tested.

Well, the problem with that is that I wanted the action in my prop file to reset the variation and exit the color wheel simultaneously. The problem is that entering or exiting the color wheel generates a sound via the SB_Change function, which is in hybrid_font.h, and not in the prop file. It seems that if I want to change the sound file that plays when I exit the color wheel, I have to change that code directly.

I could make this work if I could delay the color wheel exit until after my own sound finished playing. For instance:

      case EVENTID(BUTTON_AUX, EVENT_CLICK_SHORT, MODE_ON):
        if (SaberBase::GetColorChangeMode() != SaberBase::COLOR_CHANGE_MODE_NONE) {
          if (SFX_ccreset) {
            hybrid_font.PlayPolyphonic(&SFX_ccreset);
          }
          ResetColorChangeMode();
        }
        break;

Is there some way to ensure that ResetColorChangeMode() doesn’t trigger until after SFX_ccreset finishes playing? Maybe by playing the sound using something other than hybrid_font.PlayPolyphonic() ? The goal would be to play ccreset, and then to play ccend (as part of the color wheel exit), in order, rather than at the same time.

sound_library plays one sound and queues up subsequent sounds…

I suspected as much. But SB_Change doesn’t call that function so ccend won’t get queued behind ccreset. So even if I use sound_library.Play(“ccreset”), I need to keep ResetColorChangeMode() from executing until after the ccreset sound is finished playing. Does sound_library.Play() accomplish that on its own?

You’d probably need to edit the line in SB_Change to use sound_library too. Not sure how feasible that is.

Well, I’m trying to keep from editing anything outside of my prop file, so it’s a moot point. Sounds like I need to just live with not being able to distinguish “saving” from “resetting” via an audio cue.

There is always a way, but it’s not always a simple one.
Basically, you need to do what the sound library does: Play the sound, then remember that you did it, and then have loop() poll to see if the sound is done yet. Once it’s done, then you can continue whatever it is you were wanted to do next.

ProffieOS doesn’t have threads, and simply stopping and waiting would make EVERYTHING stop and wait, which is not what you want, and not really allowed in ProffieOS, that’s why we have to use this polling method to get what you want.

1 Like

Just use Select(), it will simplify everything. Create two ccend.wav files one for normal exit and one for revert.

ccend01.wav // normal
ccend02.wav // revert

Then in your prop BEFORE executing the respective function that triggers the sound you’d do the following. This will select that specific sound to play when called. You just have to do it for all instances where the sound would be played before executing the function that plays the sound.

case EVENTID()
...
   SFX_ccend.Select(0); // use this to select first file (normal) (ccend01.wav)
   SomeFunction();
...

case EVENTID()
...
  SFX_ccend.Select(1); // use this to select second file (revert) (ccend02.wav)
  SomeOtherFunction();
...
1 Like

That’s a very clever idea! Unfortunately it still means modifying hybrid_font.h since that’s where the other instance of ccend is.

Got it. Might be more than I want to do here, but I’ll take a look at sound_library and see if I can get some ideas. It’s not the end of the world if I can’t make this work.

1 Like

Nope, you only need it where your prop triggers the effect that uses sound no changes anywhere else. You just need it to Select before your prop calls otherwise the previous Select will remain. :wink:

In your instance should be two locations in your prop, one normal, one revert, that’s it.

1 Like

Oh, I see what you mean! Sorry, I misunderstood. I thought the select had to be done as part of the playback, like:

hybrid_font.PlayPolyphonic(SFX_ccend.Select(0));

But you’re saying the select is its own function and can be executed in advance, and then I can just call ToggleColorChangeMode() and it’ll pick the right one? That’s a brilliant solution. Thank you!

Yup, very simple. Select() is just setting which sound to play BEFORE hybrid_font plays it. If you don’t Select() it defaults to -1 which is “random”.

1 Like

What happens if I select a number that doesn’t exist? Like, if there’s only a single ccend.wav and I do: SFX_ccend.Select(1);

While using Select() would assure the correct sound gets played when resetting, it also means that the “reset” sound ccend02.wav file has a 50% chance of being played randomly when we’re not actually resetting, no?
Could we have Select() set a different (or custom) EFFECT sound?
Like as in adding EFFECT(ccreset); in the prop

No, once you Select() that sound will be used each time the SFX is called, the only way a random file is called is if you reset Select(-1) somewhere else. That’s why you have the 2nd Select() for the other instance above. So when the first usage is called for Select(0) then only the first file will play, then for the revert Select(1) is used only the 2nd will play. That’s why each needs their own Select() before playing the sound. If you only had Select(0) then everytime SFX_ccend is played it would only ever be the first file. The only time Select resets is when you change presets or if you set Select(-1), otherwise the selected file is always selected until you Select() another file.