maxton/LibForge

Mismatching audio track and instruments

Blackened15 opened this issue · 6 comments

Any Multitrack song (both Guitar Hero conversion and Original C3 release), the sound track are messed up.

Playing drum:
Missing the Bass Pedal note mutes the whole drum track, and it won't come back until you hit another bass pedal note.

Missing Red/Snare mutes the Bass track.

Missing Toms or Cymbals (Yellow, Blue, Green), mutes the guitar track.

This is using single converted song via ForgeToolGUI-0.1.163

Tested with a bunch of Guitar Hero: Metallica conversion and one of the latest Multi-Track C3 release (Thin Lizzy - Jailbreak)

While this is not too bad once the drum kicks in and you don't miss too many notes, intro of song that have no drums are mostly silent.

Edit: Tried so many way to mess with the mogg.dta track and shuffling them around but to no avail. While I was able to get the guitar to mute some other parts (drum), I wasn't able to come up with a combination that worked properly. And if you omit a track (let say, cut the drum short to (0 1 2 3) instead of (0 1 2 3 4 5), the songs will start, but hang a few seconds in. The audio preview will reflect the change and omit some sound channel, but will also hang after a few seconds.

Changing the DTA before the conversion from:

   (tracks
      (
         (drum (0 1 2 3 4 5))
         (bass (6 7))
         (guitar (8 9))
         (vocals (10 11))
         (fake (12 13))))

to

   (tracks
      (
         (drum (0 1))
         (drum (2 3))
         (drum (4 5))
         (bass (6 7))
         (guitar (8 9))
         (vocals (10 11))
         (fake (12 13))))

fixes the problem

That's weird, I need to look into this further

if you need more example of "fixed" dta, the patched_songs folder of the 2.3.1 patch contains a bunch, it's not always 2 track per lines, sometimes it's only 1, although I am unsure if any of the C3 multitrack custom would have such an instance.

If you are worried about edge case, on instruments that only have one track where the original dta goes (bass 5), when converted into pkg, the line will be ignored (and the song will stop playing after 2 seconds in-game). If the dta is modified to (bass (5)) then the conversion goes properly.

Otherwise, I been able to get a 100% success rate on converting songs by adjusting the dta file and running the mid file through C3ConTools's midi cleaner on song that crashes mid-song.

Fixed by adding some code to PkgCreator.cs
Someone more adept with coding and C# should be able to come up with something more elegant.

Changing

foreach (var child in array.Array("song").Array("tracks").Array(1).Children)
      {
        if(child is DataArray a && a.Children[1] is DataArray b && b.Count > 0)
          trackSubArray.AddNode(child);
      }

to

      foreach (var child in array.Array("song").Array("tracks").Array(1).Children)
      {
        if (child is DataArray a)
        {
          int solovalue;
          var tracks = a.Children[1].ToString().Split(new[] { ' ', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
          int nboftrack = tracks.Count();

          //fix solo track without () aka (bass 5), (bass (5)) worked without this
          //also split tracks with 3 or more channel into groups of 1/2, might not represent channel perfectly, but better than nothing
          //aka (drum (0 1 2 3 4)) into (drum (0)) (drum (1 2)) (drum (3 4)), odd is always first here, but might not be the case
          //in all songs, can't really tell without audibly listening to the splitted ogg. Worse scenario, snare misses cuts half of the bass pedal sounds etc..
          if (nboftrack > 0)
          {
            int i = 0;
            if (nboftrack % 2 != 0) //if odd
            {
              trackSubArray.AddNode(DTX.FromDtaString(a.Name + " (" + tracks[i] + ")"));
              i++;
            }
            while (i < nboftrack)
            {
              trackSubArray.AddNode(DTX.FromDtaString(a.Name + " (" + tracks[i] + " " + tracks[i + 1] + ")"));
              i += 2;
            }
          }
          //unsure the else if ever triggers, put left there just in case
          else if (a.Children[1] is DataArray b && b.Count > 0)
          {
            trackSubArray.AddNode(child);
          }
        }
      }

If there's more than one drum stem, you actually need to look in the midi to determine which drum mix it is, because it could be e.g. 2 stems on 4 tracks (stereo kick, stereo kit) or 3 stems on 4 tracks (mono kick, mono snare, stereo kit), and this is only disambiguated by the drum mix event in the rbmid.

http://docs.c3universe.com/rbndocs/index.php?title=Drum_Authoring#Drum_Mix_Events

As for things like (bass 5) well, that is an invalid songs.dta, and MAGMA wouldn't create it, so I'm not going to support it

Thanks for the info!
After reading it, there is 5 drum mix pattern accepted, and each of them have a different amount of track, so unless I'm misreading this, just relying on the number of channel should be ok to determine which mix is used. There is no mention of a possible 2 steam on 4 tracks (stereo kick, stereo rest) which would make it ambiguous with the 1-1-2 Mix1 configuration

  • Mix0 (2 channel) Whole kit in a stereo stream
  • Mix1 (4 channel) Mono kick, Mono Snare, Stereo Kit
  • Mix2 (5 channel) Mono kick, Stereo Snare, Stereo Kit
  • Mix3 (6 channel) Stereo kick, Stereo Snare, Stereo Kit
  • Mix4 (3 channel) Mono kick, Stereo Snare+Kit

So my code covers all of these possibilities except Mix1, which is 1-1-2. Will modify to account for the 1-1-2 case.

Edit: Changed wording
Edit2: After checking every mogg.dta for both rb4 and rivals, HMX really didn't wanna bother with many stems, every drum track is mix0, single stereo stream. Also checking every patched_song mogg.dta (2076 of them), never seen any song that would deviate from those pattern, so I'm guessing these are the only "legal" pattern.

Modified solution:

      foreach (var child in array.Array("song").Array("tracks").Array(1).Children)
      {
        if (child is DataArray a)
        {
          var tracks = a.Children[1].ToString().Split(new[] { ' ', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
          int nboftrack = tracks.Count();

          if (nboftrack > 0)
          {
            if ((nboftrack == 4) && (a.Name == "drum"))
            {
              trackSubArray.AddNode(DTX.FromDtaString(a.Name + " (" + tracks[0] + ")"));
              trackSubArray.AddNode(DTX.FromDtaString(a.Name + " (" + tracks[1] + ")"));
              trackSubArray.AddNode(DTX.FromDtaString(a.Name + " (" + tracks[2] + " " + tracks[3] + ")"));
            }
            else
            {
              int i = 0;
              if (nboftrack % 2 != 0) //if odd
              {
                trackSubArray.AddNode(DTX.FromDtaString(a.Name + " (" + tracks[i] + ")"));
                i++;
              }
              while (i < nboftrack)
              {
                trackSubArray.AddNode(DTX.FromDtaString(a.Name + " (" + tracks[i] + " " + tracks[i + 1] + ")"));
                i += 2;
              }
            }
          }
          //unsure the else if is still needed
          else if (a.Children[1] is DataArray b && b.Count > 0)
          {
            trackSubArray.AddNode(child);
          }
        }
      }