Log In  

Hello friends.

I have one music track in my game. When the player picks up a certain item, I would like the music to get one octave higher.

My first thought was to have a second song that is just a transposed version of the first song, and switch to it upon item pickup -- but this of course resets to the beginning of the song instead of continuing smoothly from the current position. Is there any clever way to achieve a more seamless transition?

I'm open to any other tricks that would let me get the same effect. I'm also open to forgetting all about it if it's not possible. =P

P#52987 2018-05-24 19:08 ( Edited 2018-05-25 11:35)

well music does have a fade_len argument which I think will crossfade (?), but it will start the new music from the beginning, and it sounds like what you want is for the position in the new music to match the position in the old music.

For that, I think the easiest thing to do would just be to modify the SFX notes in place (using poke), to increase all their pitch by one octave (you can modify SFX memory while playing and it takes effect immediately). It's not exactly the same thing, since it won't crossfade, but depending on what you are going for, you may consider this as a solution.

If it helps, I'll go into a bit more detail just because I already have some code that does this in Orbiter Suite

here is an excerpt:

function transpose_sfx(n, offset)
  local firstnote = get_note(n, 0)
  local firstpitch = firstnote.pitch

  local origfirstpitch = original_pitches[n]
  if origfirstpitch then
    -- add the amount to get back to the original pitch, so that the new offset
    -- is still relative to the original pitch
    offset += (origfirstpitch - firstpitch)
  else
    original_pitches[n] = firstpitch
  end

  -- offset all notes in the sfx
  for i = 0, 31 do
    local note = get_note(n, i)
    local byte1 = note.byte1
    local newpitch = note.pitch + offset

    byte1 = band(byte1, bnot(note_pitch_mask)) -- clear pitch
    byte1 = bor(byte1, newpitch) -- set new pitch

    poke(note.addr, byte1)
  end
end

it just uses a global variable original_pitches (just an empty table that gets created beforehand) to keep track for ease of use so the offset is always relative to the original pitch, but you could go even simpler and just add to the current pitches each time. Oh and it references a get_note function which is this (more info than this function needs, but this cart had other uses for getting notes so it includes a lot of info):

function get_note(sfx, n)
  local addr = 0x3200 + (68 * sfx) + (2 * n)
  local byte1 = peek(addr)
  local byte2 = peek(addr + 1)
  local inst_r = shr(band(byte1, 0b11000000), 6)
  local inst_l = shl(band(byte2, 0b00000001), 2)

  return {
    addr = addr,
    byte1 = byte1,
    byte2 = byte2,
    pitch = band(byte1, note_pitch_mask),
    volume = shr(band(byte2, 0b00001110), 1),
    effect = shr(band(byte2, 0b01110000), 4),
    instrument = bor(inst_l, inst_r)
  }
end

oh and note_pitch_mask is 0b00111111

Anyway I hope that helps. Music/SFX tricks in PICO-8 are so fun :D

P#52989 2018-05-24 19:29 ( Edited 2018-05-24 23:37)

Thanks buddy! That works a treat. I will have to go back over it and make sure I understand it fully, but now I know a little bit about poke and am consequently unstoppable. >_<

P#52994 2018-05-24 23:43 ( Edited 2018-05-25 03:43)

Oh yeah and I forgot to mention an even simpler way to do it! If you don't need the flexibility of transposing to any key, you can just prepare SFXs ahead of time which have the alternate notes that you want, and simply swap the SFXs with a couple of memcpys. This way uses less code but more SFX slots :)

function sfx_addr(n)
  return 0x3200 + (68 * n)
end

function swap_sfx(a, b)
  local addr1 = sfx_addr(a)
  local addr2 = sfx_addr(b)
  local tmp = 0x4300
  local len = 68

  memcpy(tmp, addr1, len)
  memcpy(addr1, addr2, len)
  memcpy(addr2, tmp, len)
end
P#53003 2018-05-25 07:35 ( Edited 2018-05-25 11:47)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-29 13:01:08 | 0.006s | Q:10