milkytracker / MilkyTracker

An FT2 compatible music tracker
http://milkytracker.github.io/
Other
1.69k stars 162 forks source link

Allow muting doesn't work for xms with more than 32 channels #242

Closed ptyl-dragon closed 1 year ago

ptyl-dragon commented 3 years ago

Hi

I'm trying to record the channels of an xm with more than 32 channels. I put a channel in solo-> click disk operation-> save as wav-> ensure "allow muting" is checked-> click "save as" -> choose a file name-> play the created wav

Expected: The created wav file will include only the track in solo.

Actual: The wav includes all the channels, exactly like it would if i didn't put only one channel in solo

Note: I tried unchecking the "Allow muting" button. Same result

windows 10, v1.03.00

Note, this will still work if the xm has 32 channels. It breaks at 34 and up

caseyjoy commented 2 years ago

I think I tracked this one down.

This issue only seems to be affecting channel muting. Why? because PlayerBase::startPlaying does this:

this->module = module;

    if (numChannels == -1)
        initialNumChannels = module->header.channum;
    else
        initialNumChannels = numChannels;

    ChannelMixer::setNumChannels(initialNumChannels);

and it turns out the ChannelMixer has a default channel count of 32 (which means up to 32 channels it works as expected) when it gets set up when creating PlayerBase::PlayerBase:

PlayerBase::PlayerBase(mp_uint32 frequency) : 
  ChannelMixer(32, frequency), 
  timeRecord(NULL)

and resizes later using ChannelMixer::setNumChannels.

Unfortunately, in PlayerGeneric::exportToWAV it does this:

    if (mutingArray && mutingNumChannels > 0 &&
        mutingNumChannels <= module->header.channum) {
      std::cout<<"export to wave : muting channel array\n";

      for (mp_uint32 i = 0; i < mutingNumChannels; i++) {
        // std::cout<<"Muting channel #"<<i<<"\n";
        player->muteChannel(i, mutingArray[i] == 1);
      }

      std::cout<<"export to wave : end muting channel array\n";
    }

    player->startPlaying(module, false, startOrder, 0, -1, customPanningTable,false, -1);

    mixer.start();

which means the ChannelMixer resize happens after the muting happens, which means the channel muting gets thrown out since we don't have the right number of channels already and the channel amount changing process happens.

Instead, I added a function to call ChannelMixer::setNumChannels from PlayerGeneric::exportToWAV (PlayerBase::setNumChannelMixerChannelsToModuleCount) to make sure the channels get resized first.