Example #1
0
        OggVorbis_File ogg;             // OggVorbis file

        public unsafe virtual void Decode(SoundSample sample, int sampleOffset44k, int sampleCount44k, float *dest)
        {
            if (sample.objectInfo.wFormatTag != lastFormat || sample != lastSample)
            {
                ClearDecoder();
            }

            lastDecodeTime = soundSystemLocal.CurrentSoundTime;

            if (failed)
            {
                UnsafeX.InitBlock(dest, 0, sampleCount44k * sizeof(float)); return;
            }

            // samples can be decoded both from the sound thread and the main thread for shakes
            ISystem.EnterCriticalSection(CRITICAL_SECTION.SECTION_ONE);
            var readSamples44k = sample.objectInfo.wFormatTag switch
            {
                WAVE_FORMAT_TAG.PCM => DecodePCM(sample, sampleOffset44k, sampleCount44k, dest),
                WAVE_FORMAT_TAG.OGG => DecodeOGG(sample, sampleOffset44k, sampleCount44k, dest),
                _ => 0,
            };

            ISystem.LeaveCriticalSection(CRITICAL_SECTION.SECTION_ONE);

            if (readSamples44k < sampleCount44k)
            {
                UnsafeX.InitBlock(dest + readSamples44k, 0, (sampleCount44k - readSamples44k) * sizeof(float));
            }
        }
Example #2
0
        public virtual void ClearDecoder()
        {
            ISystem.EnterCriticalSection(CRITICAL_SECTION.SECTION_ONE);
            switch (lastFormat)
            {
            case WAVE_FORMAT_TAG.PCM: break;

            case WAVE_FORMAT_TAG.OGG: ov_clear(ogg); ogg.memset(); break;
            }
            Clear();
            ISystem.LeaveCriticalSection(CRITICAL_SECTION.SECTION_ONE);
        }
Example #3
0
        unsafe int OpenOGG(string strFileName, out WaveformatEx pwfx)
        {
            pwfx   = default;
            mhmmio = fileSystem.OpenFileRead(strFileName);
            if (mhmmio == null)
            {
                return(-1);
            }

            ISystem.EnterCriticalSection(CRITICAL_SECTION.SECTION_ONE);

            var ov = new OggVorbis_File();

            if (OggVorbis.ov_openFile(mhmmio, ov) < 0)
            {
                ISystem.LeaveCriticalSection(CRITICAL_SECTION.SECTION_ONE); fileSystem.CloseFile(mhmmio); mhmmio = null; return(-1);
            }

            mfileTime = mhmmio.Timestamp;

            var vi = ov_info(ov, -1);

            mpwfx.Format.nSamplesPerSec = (int)vi->rate;
            mpwfx.Format.nChannels      = (short)vi->channels;
            mpwfx.Format.wBitsPerSample = sizeof(short) * 8;
            mdwSize = (int)(ov_pcm_total(ov, -1) * vi->channels);   // pcm samples * num channels
            mbIsReadingFromMemory = false;

            if (SoundSystemLocal.s_realTimeDecoding.Bool)
            {
                ov_clear(ov);
                fileSystem.CloseFile(mhmmio);
                mhmmio = null;

                mpwfx.Format.wFormatTag = WAVE_FORMAT_TAG.OGG;
                mhmmio   = fileSystem.OpenFileRead(strFileName);
                mMemSize = mhmmio.Length;
            }
            else
            {
                ogg = ov;

                mpwfx.Format.wFormatTag = WAVE_FORMAT_TAG.PCM;
                mMemSize = mdwSize * sizeof(short);
            }

            pwfx = mpwfx.Format;

            ISystem.LeaveCriticalSection(CRITICAL_SECTION.SECTION_ONE);
            isOgg = true;
            return(0);
        }
Example #4
0
        void Session_Hitch_f(CmdArgs args)
        {
            var sw = soundSystem.PlayingSoundWorld;

            if (sw != null)
            {
                soundSystem.SetMute(true); sw.Pause(); ISystem.EnterCriticalSection();
            }
            SysW.Sleep(args.Count == 2 ? int.Parse(args[1]) : 100);
            if (sw != null)
            {
                ISystem.LeaveCriticalSection(); sw.UnPause(); soundSystem.SetMute(false);
            }
        }
Example #5
0
        // can pass SCHANNEL_ANY
        public virtual void StopSound(int channel)
        {
            int i;

            if (SoundSystemLocal.s_showStartSound.Integer != 0)
            {
                common.Printf($"StopSound({index},{channel})\n");
            }

            if (soundWorld != null && soundWorld.writeDemo != null)
            {
                soundWorld.writeDemo.WriteInt((int)VFileDemo.DS.SOUND);
                soundWorld.writeDemo.WriteInt((int)SCMD.STOP);
                soundWorld.writeDemo.WriteInt(index);
                soundWorld.writeDemo.WriteInt(channel);
            }

            ISystem.EnterCriticalSection();
            for (i = 0; i < SoundSystemLocal.SOUND_MAX_CHANNELS; i++)
            {
                var chan = channels[i];

                if (!chan.triggerState)
                {
                    continue;
                }
                if (channel != ISoundSystem.SCHANNEL_ANY && chan.triggerChannel != channel)
                {
                    continue;
                }

                // stop it
                chan.Stop();

                // free hardware resources
                chan.ALStop();

                // if this was an onDemand sound, purge the sample now
                if (chan.leadinSample.onDemand)
                {
                    chan.leadinSample.PurgeSoundSample();
                }

                chan.leadinSample = null;
                chan.soundShader  = null;
            }
            ISystem.LeaveCriticalSection();
        }
Example #6
0
        unsafe int CloseOGG()
        {
            var ov = (OggVorbis_File)ogg;

            if (ov != null)
            {
                ISystem.EnterCriticalSection(CRITICAL_SECTION.SECTION_ONE);
                ov_clear(ov);
                ISystem.LeaveCriticalSection(CRITICAL_SECTION.SECTION_ONE);
                fileSystem.CloseFile(mhmmio);
                mhmmio = null;
                ogg    = null;
                return(0);
            }
            return(-1);
        }
Example #7
0
        // returns the length of the started sound in msec
        public virtual int StartSound(ISoundShader shader, int channel, float diversity = 0, int shaderFlags = 0, bool allowSlow = true /* D3XP */)
        {
            int i;

            if (shader == null)
            {
                return(0);
            }
            var shader2 = (SoundShader)shader;

            if (SoundSystemLocal.s_showStartSound.Integer != 0)
            {
                common.Printf($"StartSound {soundWorld.gameMsec}ms ({index},{channel},{shader2.Name}) = ");
            }

            if (soundWorld != null && soundWorld.writeDemo != null)
            {
                soundWorld.writeDemo.WriteInt((int)VFileDemo.DS.SOUND);
                soundWorld.writeDemo.WriteInt((int)SCMD.START);
                soundWorld.writeDemo.WriteInt(index);
                soundWorld.writeDemo.WriteHashString(shader2.Name);
                soundWorld.writeDemo.WriteInt(channel);
                soundWorld.writeDemo.WriteFloat(diversity);
                soundWorld.writeDemo.WriteInt(shaderFlags);
            }

            // build the channel parameters by taking the shader parms and optionally overriding
            SoundShaderParms chanParms;

            chanParms = shader2.parms;
            OverrideParms(chanParms, this.parms, out chanParms);
            chanParms.soundShaderFlags |= shaderFlags;

            if (chanParms.shakes > 0f)
            {
                shader2.CheckShakesAndOgg();
            }

            // this is the sample time it will be first mixed
            var start44kHz = soundWorld.fpa[0] != null
                ? soundWorld.lastAVI44kHz + Simd.MIXBUFFER_SAMPLES // if we are recording an AVI demo, don't use hardware time
                : soundSystemLocal.Current44kHzTime + Simd.MIXBUFFER_SAMPLES;

            // pick which sound to play from the shader
            if (shader2.numEntries == 0)
            {
                if (SoundSystemLocal.s_showStartSound.Integer != 0)
                {
                    common.Printf("no samples in sound shader\n");
                }
                return(0); // no sounds
            }

            // pick a sound from the list based on the passed diversity
            var choice = (int)(diversity * shader2.numEntries);

            if (choice < 0 || choice >= shader2.numEntries)
            {
                choice = 0;
            }

            // bump the choice if the exact sound was just played and we are NO_DUPS
            if ((chanParms.soundShaderFlags & ISoundSystem.SSF_NO_DUPS) != 0)
            {
                var sample = shader2.leadins[choice] ?? shader2.entries[choice];
                for (i = 0; i < SoundSystemLocal.SOUND_MAX_CHANNELS; i++)
                {
                    var chan2 = channels[i];
                    if (chan2.leadinSample == sample)
                    {
                        choice = (choice + 1) % shader2.numEntries; break;
                    }
                }
            }

            // PLAY_ONCE sounds will never be restarted while they are running
            if ((chanParms.soundShaderFlags & ISoundSystem.SSF_PLAY_ONCE) != 0)
            {
                for (i = 0; i < SoundSystemLocal.SOUND_MAX_CHANNELS; i++)
                {
                    var chan2 = channels[i];
                    if (chan2.triggerState && chan2.soundShader == shader2)
                    {
                        if (SoundSystemLocal.s_showStartSound.Integer != 0)
                        {
                            common.Printf("PLAY_ONCE not restarting\n");
                        }
                        return(0);
                    }
                }
            }

            // never play the same sound twice with the same starting time, even if they are on different channels
            for (i = 0; i < SoundSystemLocal.SOUND_MAX_CHANNELS; i++)
            {
                var chan2 = channels[i];
                if (chan2.triggerState && chan2.soundShader == shader2 && chan2.trigger44kHzTime == start44kHz)
                {
                    if (SoundSystemLocal.s_showStartSound.Integer != 0)
                    {
                        common.Printf("already started this frame\n");
                    }
                    return(0);
                }
            }

            ISystem.EnterCriticalSection();

            // kill any sound that is currently playing on this channel
            if (channel != ISoundSystem.SCHANNEL_ANY)
            {
                for (i = 0; i < SoundSystemLocal.SOUND_MAX_CHANNELS; i++)
                {
                    var chan2 = channels[i];
                    if (chan2.triggerState && chan2.soundShader != null && chan2.triggerChannel == channel)
                    {
                        if (SoundSystemLocal.s_showStartSound.Integer != 0)
                        {
                            common.Printf($"(override {chan2.soundShader.base_.Name})");
                        }
                        chan2.Stop();
                        // if this was an onDemand sound, purge the sample now
                        if (chan2.leadinSample.onDemand)
                        {
                            chan2.ALStop(); chan2.leadinSample.PurgeSoundSample();
                        }
                        break;
                    }
                }
            }

            // find a free channel to play the sound on
            SoundChannel chan;

            for (i = 0; i < SoundSystemLocal.SOUND_MAX_CHANNELS; i++)
            {
                chan = channels[i];
                if (!chan.triggerState)
                {
                    break;
                }
            }

            if (i == SoundSystemLocal.SOUND_MAX_CHANNELS)
            {
                // we couldn't find a channel for it
                ISystem.LeaveCriticalSection();
                if (SoundSystemLocal.s_showStartSound.Integer != 0)
                {
                    common.Printf("no channels available\n");
                }
                return(0);
            }

            chan = channels[i];
            chan.leadinSample = shader2.leadins[choice] != null ? shader2.leadins[choice] : shader2.entries[choice];

            // if the sample is onDemand (voice mails, etc), load it now
            if (chan.leadinSample.purged)
            {
                var start = SysW.Milliseconds;
                chan.leadinSample.Load();
                var end = SysW.Milliseconds;
                session.TimeHitch(end - start);
                // recalculate start44kHz, because loading may have taken a fair amount of time
                if (soundWorld.fpa[0] == null)
                {
                    start44kHz = soundSystemLocal.Current44kHzTime + Simd.MIXBUFFER_SAMPLES;
                }
            }

            if (SoundSystemLocal.s_showStartSound.Integer != 0)
            {
                common.Printf($"'{chan.leadinSample.name}'\n");
            }

            chan.disallowSlow = SoundSystemLocal.s_skipHelltimeFX.Bool || !allowSlow;

            ResetSlowChannel(chan);

            // the sound will start mixing in the next async mix block
            chan.triggered             = true;
            chan.openalStreamingOffset = 0;
            chan.trigger44kHzTime      = start44kHz;
            chan.parms = chanParms;
            chan.triggerGame44kHzTime = soundWorld.game44kHz;
            chan.soundShader          = shader2;
            chan.triggerChannel       = channel;
            chan.stopped = false;
            chan.Start();

            // we need to start updating the def and mixing it in
            playing = true;

            // spatialize it immediately, so it will start the next mix block
            // even if that happens before the next PlaceOrigin()
            Spatialize(soundWorld.listenerPos, soundWorld.listenerArea, soundWorld.rw);

            // return length of sound in milliseconds
            var length = chan.leadinSample.LengthIn44kHzSamples;

            if (chan.leadinSample.objectInfo.nChannels == 2)
            {
                length /= 2;                                                 // stereo samples
            }
            // adjust the start time based on diversity for looping sounds, so they don't all start at the same point
            if ((chan.parms.soundShaderFlags & ISoundSystem.SSF_LOOPING) != 0 && chan.leadinSample.LengthIn44kHzSamples == 0)
            {
                chan.trigger44kHzTime -= (int)(diversity * length);
                chan.trigger44kHzTime &= ~7;        // so we don't have to worry about the 22kHz and 11kHz expansions
                                                    // starting in fractional samples
                chan.triggerGame44kHzTime -= (int)(diversity * length);
                chan.triggerGame44kHzTime &= ~7;
            }

            length *= (int)(1000 / (float)SoundSystemLocal.PRIMARYFREQ);

            ISystem.LeaveCriticalSection();
            return(length);
        }