public Player_AD(ScummEngine scumm, IMixer mixer) { _vm = scumm; _mixer = mixer; _rate = mixer.OutputRate; // TODO: vs OPL // _opl2 = OPL::Config::create(); _opl2 = new DosBoxOPL(OplType.Opl2); _opl2.Init(_rate); _samplesPerCallback = _rate / AD_CALLBACK_FREQUENCY; _samplesPerCallbackRemainder = _rate % AD_CALLBACK_FREQUENCY; _samplesTillCallback = 0; _samplesTillCallbackRemainder = 0; WriteReg(0x01, 0x00); WriteReg(0xBD, 0x00); WriteReg(0x08, 0x00); WriteReg(0x01, 0x20); _soundHandle = _mixer.PlayStream(SoundType.Plain, this, -1, Mixer.MaxChannelVolume, 0, false, true); _engineMusicTimer = 0; _soundPlaying = -1; _curOffset = 0; _sfxTimer = 4; _rndSeed = 1; for (int i = 0; i < _sfx.Length; ++i) { _sfx[i] = new SfxSlot(); _sfx[i].Resource = -1; for (int j = 0; j < _sfx[i].Channels.Length; ++j) { _sfx[i].Channels[j].HardwareChannel = -1; } } _numHWChannels = _hwChannels.Length; _musicVolume = _sfxVolume = 255; _isSeeking = false; }
bool StartSfx(SfxSlot sfx, byte[] resource) { WriteReg(0xBD, 0x00); // Clear the channels. sfx.Channels[0].State = ChannelState.Off; sfx.Channels[1].State = ChannelState.Off; sfx.Channels[2].State = ChannelState.Off; // Set up the first channel to pick up playback. // Try to allocate a hardware channel. sfx.Channels[0].HardwareChannel = AllocateHWChannel(sfx.Priority, sfx); if (sfx.Channels[0].HardwareChannel == -1) { Debug.WriteLine("AD No hardware channel available"); return false; } sfx.Channels[0].MusicData = resource; sfx.Channels[0].CurrentOffset = sfx.Channels[0].StartOffset = 2; sfx.Channels[0].State = ChannelState.Parse; // Scan for the start of the other channels and set them up if required. int curChannel = 1; var bufferPosition = 2; byte command = 0; while ((command = resource[bufferPosition]) != 0xFF) { switch (command) { case 1: // INSTRUMENT DEFINITION bufferPosition += 15; break; case 2: // NOTE DEFINITION bufferPosition += 11; break; case 0x80: // LOOP bufferPosition += 1; break; default: // START OF CHANNEL bufferPosition += 1; if (curChannel >= 3) { throw new InvalidOperationException(string.Format("AD SFX resource {0} uses more than 3 channels", sfx.Resource)); } sfx.Channels[curChannel].HardwareChannel = AllocateHWChannel(sfx.Priority, sfx); if (sfx.Channels[curChannel].HardwareChannel == -1) { Debug.WriteLine("AD No hardware channel available"); return false; } sfx.Channels[curChannel].CurrentOffset = bufferPosition; sfx.Channels[curChannel].StartOffset = bufferPosition; sfx.Channels[curChannel].State = ChannelState.Parse; ++curChannel; break; } } return true; }
void StopSfx(SfxSlot sfx) { if (sfx.Resource == -1) { return; } // 1. step: Clear all the channels. for (int i = 0; i < sfx.Channels.Length; ++i) { if (sfx.Channels[i].State != ChannelState.Off) { ClearChannel(sfx.Channels[i]); sfx.Channels[i].State = ChannelState.Off; } if (sfx.Channels[i].HardwareChannel != -1) { FreeHWChannel(sfx.Channels[i].HardwareChannel); sfx.Channels[i].HardwareChannel = -1; } } // TODO: 2. step: Unlock the resource. // _vm._res.unlock(rtSound, sfx.resource); sfx.Resource = -1; }
int AllocateHWChannel(int priority, SfxSlot owner = null) { // We always reaLlocate the channel with the lowest priority in case none // is free. int channel = -1; int minPrio = priority; for (int i = 0; i < _numHWChannels; ++i) { if (!_hwChannels[i].Allocated) { channel = i; break; } // We don't allow SFX to reallocate their own channels. Otherwise we // would call stopSfx in the midst of startSfx and that can lead to // horrible states... // We also prevent the music from reallocating its own channels like // in the original. if (_hwChannels[i].Priority <= minPrio && _hwChannels[i].SfxOwner != owner) { minPrio = _hwChannels[i].Priority; channel = i; } } if (channel != -1) { // In case the HW channel belongs to a SFX we will completely // stop playback of that SFX. // TODO: Maybe be more fine grained in the future and allow // detachment of individual channels of a SFX? if (_hwChannels[channel].Allocated && _hwChannels[channel].SfxOwner != null) { StopSfx(_hwChannels[channel].SfxOwner); } _hwChannels[channel].Allocated = true; _hwChannels[channel].Priority = priority; _hwChannels[channel].SfxOwner = owner; } return channel; }