Music selection with ATMLib

I am trying to get a music selection menu with it previewing the music selected, right now it all works but 1 thing is not working as it should.

When i am on the selection menu, and it’s on one song, the song isn’t playing but it looks like it’s playing only the first note over and over instead… I do suspect that it’s because my code is always checking if the selected music is X and play music X, but instead of keeping that music X playing until i select something else, it may be restarting the selected song every loops.

Can anybody help me finding what i am doing wrong there? I am pretty sure it’s pretty easy for others, but i am a newbie at all this.

here’s how the music selector is right now

void radioMusic() 
{
  if (radioStation == 0)
  {
  ATM.play(music1);
  }
  if (radioStation == 1)
  {
  ATM.play(music2);
  }
  if (radioStation == 2)
  {
  ATM.stop();
  }
}

So i am just calling that function on the music selection screen, on that screen you can use left/right to switch the song, 3 choices there: Music1, Music2 and No Music.

Once selected, the music in-game is the one selected and works nicely, only problem is that on the selection screen, the song isn’t playing, it seems to get stuck on the first note…

Also, is there an easy way to repeat a song infinitely? Not sure but i think there’s nothing on the Team ARG website about that.

Thanks!

Hi! If you are calling radioMusic() repeatedly then you are restarting the song every time ATM.play() is called. The solution is to call the radioMusic() only when the selection changes.

If this is ATMlib v1 then a pattern can carry a set pattern loop command which sets the pattern index to loop back to when the song is over (one pattern index for each of the 4 channels, pattern index 255 disables loop on a channel). This command can be anywhere before the end of the song, once the end of the song is reached it takes effect and the song starts again from the patterns specified in the set loop command.

HTH

2 Likes

I think @dxb is probably right that you’re probably calling radioMusic repeatedly with your loop function.


Edit:
Also I don’t think it’s the loop command issue because if that were the issue, this wouldn’t be true:


I think the easiest solution would be:

// This is a global variable
uint8_t previousRadioStation;

void radioMusic() 
{
  if(previousRadioStation != radioStation)
  {
    if (radioStation == 0)
    {
      ATM.play(music1);
    }
    if (radioStation == 1)
    {
      ATM.play(music2);
    }
    if (radioStation == 2)
    {
      ATM.stop();
    }
    previousRadioStation = radioStation;
  }
}

And of course, a switch would be better than an if-chain if your conditions are going to be mutually exclusive (i.e. only one can true).

// This is a global variable
uint8_t previousRadioStation;

void radioMusic() 
{
  if(previousRadioStation != radioStation)
  {
    switch(radioStation)
    {
      case 0:
      {
        ATM.play(music1);
        break;
      }
      case 1:
      {
        ATM.play(music2);
        break;
      }
      case 2:
      {
        ATM.stop();
        break;
      }
    }
    previousRadioStation = radioStation;
  }
}

Or, if they’re all going to be ATM.play except for the last one then:

// This is a global variable
uint8_t previousRadioStation;

const uint8_t * const radioStations[] PROGMEM =
{
  music1, music2,
  // etc
};

// I'm assuming 'arraySize' is the same as
// 'ArrayLength' defined here:
// https://github.com/Pharap/Minesweeper/blob/master/Utils/ArrayUtils.h#L23
constexpr const size_t numberOfStations = arraySize(radioStations);

void radioMusic() 
{
  if(previousRadioStation != radioStation)
  {
    if(radioStation < numberOfRadioStations)
      ATM.play(reinterpret_cast<const uint8_t *>(pgm_read_ptr(&radioStations[radioStation]));
    else
      ATM.stop();
    previousRadioStation = radioStation;
  }
}
2 Likes

Thank you! I will try that.

2 Likes

Thanks for the help, i got it working now. But i didn’t expect ATMLid music to make everything else slow down that much. If there’s no way to make it more efficient we may not even be able to reader the game fast enough to be worth using it… i might need help there.

Yes, for now it’s ATMLib 1 (since i am using the ATM track editor on Team ARG website). Could you be more precise about what i should be doing? you seem to imply that i know the command to use. I am a total newbie at this. :wink:

Could you show me how to do it using the test song below? (it’s the one available on team ARG website to test)

Song music[] = {                // total song in bytes = 78 
  //                            // setup bytes 17
  0x06,                         // Number of tracks
  0x00, 0x00,                   // Address of track 0
  0x03, 0x00,                   // Address of track 1
  0x0B, 0x00,                   // Address of track 2
  0x20, 0x00,                   // Address of track 3
  0x24, 0x00,                   // Address of track 4
  0x36, 0x00,                   // Address of track 5
  
  0x01,                         // Channel 0 entry track (PULSE)
  0x00,                         // Channel 1 entry track (SQUARE)
  0x00,                         // Channel 2 entry track (TRIANGLE)
  0x03,                         // Channel 3 entry track (NOISE)

  //"Track 0"                   // ticks = 0 / bytes = 3
  0x40, 0,                      // FX: SET VOLUME: volume = 0
  0x9F,                         // FX: STOP CURRENT CHANNEL

  //"Track 1"                   // ticks = 3072 / bytes = 8
  0x9D, 50,                     // SET song tempo: value = 50
  0x40, 63,                     // FX: SET VOLUME: volume = 63
  0xFD, 31, 2,                  // REPEAT: count = 31 + 1 / track = 2 (32 * 96 ticks)
  0x9F,                         // FX: STOP CURRENT CHANNEL

  //"Track 2"                   // ticks = 96 / bytes = 21
  0x00 + 24,                    // NOTE ON: note = 24
  0x9F + 24,                    // DELAY: 24 ticks
  0x00 + 36,                    // NOTE ON: note = 36
  0x47, 0x43, 0x00 + 0x00 + 0,  // FX: ARPEGGIO ON: notes =  +4 +3 / don't play third note = OFF / ritrigger = OFF / ticks = 0
  0x9F +  8,                    // DELAY: 8 ticks
  0x00,                         // NOTE OFF
  0x48,                         // FX: ARPEGGIO OFF
  0x9F + 16,                    // DELAY: 16 ticks
  0x00 + 22,                    // NOTE ON: note = 22
  0x9F + 24,                    // DELAY: 24 ticks
  0x00 + 34,                    // NOTE ON: note = 34
  0x47, 0x43, 0x00 + 0x00 + 0,  // FX: ARPEGGIO ON: notes =  +4 +3 / don't play third note = OFF / ritrigger = OFF / ticks = 0
  0x9F +  8,                    // DELAY: 8 ticks
  0x00,                         // NOTE OFF
  0x48,                         // FX: ARPEGGIO OFF
  0x9F + 16,                    // DELAY: 16 ticks
  0xFE,                         // RETURN

  //"Track 3"                   // ticks = 3072 / bytes = 4
  0xFD, 31, 4,                  // REPEAT: count = 31 + 1 / track = 4  (32 * 96 ticks)
  0x9F,                         // FX: STOP CURRENT CHANNEL

  //"Track 4"                   // ticks = 96 / bytes = 18
  0xFD, 1, 5,                   // REPEAT: count = 1 + 1 / track = 5  (24 ticks)
  0x9F + 12,                    // DELAY: 12 ticks
  0xFD, 1, 5,                   // REPEAT: count = 1 + 1 / track = 5  (24 ticks)
  0x9F + 12,                    // DELAY: 12 ticks
  0x49, 4 + 0,                  // FX: RETRIG NOISE: point = 1 (*4) / speed = 0 (fastest)
  0x40, 48,                     // FX: SET VOLUME: volume = 63
  0x42, -8, 1,                  // FX: VOLUME SLIDE ON: steps = -8
  0x9F + 24,                    // DELAY:  24 ticks
  0x4A,                         // FX: RETRIG: off
  0xFE,                         // RETURN

  //"Track 5"                   // ticks = 12 / bytes = 7
  0x40, 48,                     // FX: SET VOLUME: volume = 48
  0x42, -16, 1,                 // FX: VOLUME SLIDE ON: steps = -16 / every 1 ticks
  0x9F + 12,                    // DELAY: 12 ticks
  0xFE,                         // RETURN

};

Thank you for your help.

Hi, the command is listed here https://github.com/TEAMarg/ATMlib as GOTO advanced.

0x9E followed by 4 bytes indicating the index of the the pattern each channel should restart from.

//"Track 5"                   // ticks = 12 / bytes = 7
  0x40, 48,                     // FX: SET VOLUME: volume = 48
  0x42, -16, 1,                 // FX: VOLUME SLIDE ON: steps = -16 / every 1 ticks
  0x9F + 12,                    // DELAY: 12 ticks
  0x9E, // "GOTO advanced"
  0x01, // channel 1 restarts on pattern 1
  0x00, // channel 2 restarts on pattern 0
  0x00, // channel 3 restarts on pattern 0
  0x03, // channel 4 restarts on pattern 3
  0xFE, // RETURN

Note that I added the command to the last track because I didn’t want to update the pattern offsets listed at the beginning of the listing you quoted. I would work also if it was inserted at the beginning or the middle of a pattern.

1 Like

Sorry, ATMlib v1 is always mixing 4 channels audio even if you use less than 4 and interrupts the MCU at twice the sample rate. This is not easy to fix on the fly.

FYI all improvements made into ATMlib2 (which does skip processing unused channels and doesn’t trigger interrupt at twice the sample rate).

1 Like