示例#1
0
        private static int GetOutOfSyncSamples(SoundProvider soundProvider, int sampleIndex, TimeSpan duration,
                                               int samplesRead)
        {
            SoundFormat sourceFormat = soundProvider.SourceFormat;
            SoundFormat audioFormat  = soundProvider.Format;

            // Get number of source samples read and expected number of source
            double secondsPassed   = (double)duration.Ticks / ticksPerSec;
            int    expectedSamples = (int)(secondsPassed * sourceFormat.SamplesPerSecond);

            // Get sample ratio
            double samplesRatio = (double)sourceFormat.SamplesPerSecond / audioFormat.SamplesPerSecond;

            // Get number of samples in each packet
            int packetSamples = (int)((soundProvider.PacketLength * sourceFormat.SamplesPerSecond) / 1000.0);

            // Get total number of source samples read
            int totalSamplesRead = samplesRead + (int)(sampleIndex * samplesRatio);

            // Check if more than two packets are missing or out of sync
            if ((totalSamplesRead + 2 * packetSamples < expectedSamples) ||
                (totalSamplesRead > 2 * packetSamples + expectedSamples))
            {
                return(expectedSamples - totalSamplesRead);
            }
            // Few or zero samples are out of sync
            // We can ignore this now.
            return(0);
        }
示例#2
0
        private void ChangeSoundDevice(SoundDevice soundDevice)
        {
            // Check recording state
            RecordingState state = this.recorder.State;

            // Debug.Assert(state == RecordingState.Idle);
            if (state != RecordingState.Idle)
            {
                return;
            }
            SoundSettings soundSettings = this.SoundSettings;

            if (soundDevice != null)
            {
                soundSettings.DeviceId = soundDevice.Id;
                if (soundSettings.Format == null)
                {
                    soundSettings.Format = SoundProvider.SuggestFormat(soundDevice.Id, null, null, null);
                    this.configuration.Sound.DeviceId = soundDevice.Id;
                }
            }
            else
            {
                soundSettings.DeviceId   = null;
                this.configuration.Sound = soundSettings;
            }
            this.SoundSettings = soundSettings;
        }
    // Token: 0x0600106E RID: 4206
    public void PerformChargeDash()
    {
        this.m_hasHitAttackable       = false;
        this.m_chargeJumpWasReleased  = false;
        this.m_chargeDashAttackTarget = (this.FindClosestAttackable as IAttackable);
        if (this.m_chargeDashAttackTarget != null)
        {
            this.m_chargeDashAtTarget         = true;
            this.m_chargeDashDirection        = (this.m_chargeDashAttackTarget.Position - this.m_sein.Position).normalized;
            this.m_chargeDashAtTargetPosition = this.m_chargeDashAttackTarget.Position;
        }
        else
        {
            this.m_chargeDashAtTarget = false;
        }
        SoundProvider dashSound = (!SeinDashAttack.RainbowDashActivated) ? this.ChargeDashSound : this.RainbowDashSound;

        this.PerformDash(this.ChargeDashAnimation, dashSound);
        if (this.m_chargeDashAtTarget)
        {
            this.SpriteRotation = Mathf.Atan2(this.m_chargeDashDirection.y, this.m_chargeDashDirection.x) * 57.29578f - (float)((!this.m_faceLeft) ? 0 : 180);
        }
        this.ChangeState(SeinDashAttack.State.ChargeDashing);
        this.CompleteChargeEffect();
        this.UpdateChargeDashing();
    }
示例#4
0
        private void view_SoundFormatTagChanged(object sender, EventArgs e)
        {
            SoundFormatTag?viewFormatTag = this.view.SoundFormatTag;

            if (viewFormatTag.HasValue)
            {
                List <SoundFormat> soundFormatList = new List <SoundFormat>();
                foreach (var format in this.formatList)
                {
                    if (format.Tag == viewFormatTag)
                    {
                        soundFormatList.Add(format);
                    }
                }
                SoundFormat    currentFormat       = this.view.SoundFormat;
                SoundFormatTag?preferredTag        = viewFormatTag;
                int?           preferredSampleRate = null;
                int?           preferredChannels   = null;
                if (currentFormat != null)
                {
                    preferredSampleRate = currentFormat.SamplesPerSecond;
                    preferredChannels   = currentFormat.Channels;
                }
                this.view.SoundFormats = soundFormatList.ToArray();
                SoundFormat suggestedFormat = SoundProvider.SuggestFormat(this.view.SoundDevice.Id, viewFormatTag,
                                                                          preferredSampleRate, preferredChannels);
                this.view.SoundFormat = suggestedFormat;
            }
            else
            {
                this.view.SoundFormats = null;
            }
        }
 // Token: 0x06001790 RID: 6032 RVA: 0x00014D45 File Offset: 0x00012F45
 public void PlaySound(SoundProvider sound)
 {
     if (sound != null)
     {
         Sound.Play(sound.GetSound(null), this.Position, null);
     }
 }
示例#6
0
        public async Task WaitForCompletion(CancellationToken cancellationToken)
        {
            this.cancellationToken = cancellationToken;

            bool enemyDead = await tcs.Task;

            this.cancellationToken = null;
            tcs = null;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            if (enemyDead)
            {
                SoundProvider.PlayDeathSound();
            }
            else
            {
                SoundProvider.PlayHouseReachedSound();
            }

            var   animationTask = enemyDead ? Animator.Die(cancellationToken) : Animator.HouseReached(cancellationToken);
            await animationTask;
        }
示例#7
0
文件: SoundStorage.cs 项目: desla/AS
        /// <summary>
        /// Добавление провайдера к существующим. Приоритет выпора - порядок добавления.
        /// </summary>
        /// <param name="aProviders">Провайдер.</param>
        public void AddProvider(SoundProvider aProviders)
        {
            if (aProviders == null) {
                throw new ArgumentNullException("aProviders");
            }

            providers.Add(aProviders);
        }
    // Token: 0x0600106B RID: 4203
    public void PerformWallDash()
    {
        this.m_chargeDashAtTarget = false;
        SoundProvider dashSound = (!SeinDashAttack.RainbowDashActivated) ? this.DashSound : this.RainbowDashSound;

        this.PerformDash(this.DashAnimation, dashSound);
        this.ChangeState(SeinDashAttack.State.Dashing);
        this.UpdateDashing();
        SeinDashAttack.OnWallDashEvent();
    }
    // Token: 0x0600106A RID: 4202
    public void PerformDash()
    {
        this.m_chargeDashAtTarget = false;
        SoundProvider dashSound = (!SeinDashAttack.RainbowDashActivated) ? this.DashSound : this.RainbowDashSound;
        bool          isGliding = this.m_sein.Controller.IsGliding;

        this.PerformDash((!isGliding) ? this.DashAnimation : this.GlideDashAnimation, dashSound);
        this.ChangeState(SeinDashAttack.State.Dashing);
        this.UpdateDashing();
        SeinDashAttack.OnDashEvent();
    }
示例#10
0
        private void view_SoundDeviceChanged(object sender, EventArgs e)
        {
            SoundDevice device = this.view.SoundDevice;

            if (device != null && !string.IsNullOrEmpty(device.Id))
            {
                SoundFormat[] formats = null;
                try {
                    formats = SoundProvider.GetFormats(device.Id, true);
                }
                catch (SoundException) {
                    this.view.SoundDevice               = null;
                    this.view.SoundFormats              = null;
                    this.view.SoundFormatTags           = null;
                    this.view.AllowSelectSoundFormat    = false;
                    this.view.AllowSelectSoundFormatTag = false;
                    return;
                }
                this.view.AllowSelectSoundFormat    = true;
                this.view.AllowSelectSoundFormatTag = true;

                this.formatList = new List <SoundFormat>(formats);
                this.formatList.Sort(SoundFormatComparer);
                List <SoundFormatTag> distinctTags = new List <SoundFormatTag>(formatList.Count);
                foreach (var format in formats)
                {
                    if (!distinctTags.Contains(format.Tag))
                    {
                        distinctTags.Add(format.Tag);
                    }
                }
                SoundFormat currentFormat = this.view.SoundFormat;
                this.view.SoundFormatTags = distinctTags.ToArray();
                SoundFormatTag?preferredTag        = null;
                int?           preferredChannels   = null;
                int?           preferredSampleRate = null;
                if (currentFormat != null)
                {
                    preferredTag        = currentFormat.Tag;
                    preferredSampleRate = currentFormat.SamplesPerSecond;
                    preferredChannels   = currentFormat.Channels;
                }
                SoundFormat suggestedFormat = SoundProvider.SuggestFormat(device.Id, preferredTag, preferredSampleRate,
                                                                          preferredChannels);
                this.view.SoundFormatTag = suggestedFormat.Tag;
                this.view.SoundFormat    = suggestedFormat;
            }
            else
            {
                this.view.AllowSelectSoundFormat    = false;
                this.view.AllowSelectSoundFormatTag = false;
            }
        }
示例#11
0
 public Engine(IMap map, IGameRenderer renderer)
 {
     this.gameMap       = map;
     this.gameRenderer  = renderer;
     this.bestScore     = new HighScore();
     this.isGameStarted = false;
     this.timer         = new DispatcherTimer();
     this.soundProvider = new SoundProvider();
     this.dotFactory    = new DotFactory();
     this.gameRenderer.UIActionHappened += this.HandleUIActionHappened;
     this.StartGame();
 }
 // Token: 0x06001069 RID: 4201
 private void PerformDash(TextureAnimationWithTransitions dashAnimation, SoundProvider dashSound)
 {
     this.m_sein.Mortality.DamageReciever.ResetInviciblity();
     this.m_hasDashed = true;
     if (RandomizerBonus.DoubleAirDash() && !RandomizerBonus.DoubleAirDashUsed)
     {
         this.m_hasDashed = false;
         RandomizerBonus.DoubleAirDashUsed = true;
     }
     this.m_isOnGround    = this.m_sein.IsOnGround;
     this.m_lastDashTime  = Time.time;
     this.m_lastPressTime = 0f;
     this.SpriteRotation  = this.m_sein.PlatformBehaviour.PlatformMovement.GroundAngle;
     this.m_allowNoDecelerationForThisDash = true;
     if (this.m_chargeDashAtTarget)
     {
         this.m_faceLeft = (this.m_chargeDashDirection.x < 0f);
     }
     else if (this.m_sein.PlatformBehaviour.PlatformMovement.HasWallLeft)
     {
         this.m_faceLeft = false;
     }
     else if (this.m_sein.PlatformBehaviour.PlatformMovement.HasWallRight)
     {
         this.m_faceLeft = true;
     }
     else if (this.m_sein.Input.NormalizedHorizontal != 0)
     {
         this.m_faceLeft = (this.m_sein.Input.NormalizedHorizontal < 0);
     }
     else if (!Mathf.Approximately(this.m_sein.Speed.x, 0f))
     {
         this.m_faceLeft = (this.m_sein.Speed.x < 0f);
     }
     else
     {
         this.m_faceLeft = this.m_sein.FaceLeft;
         this.m_allowNoDecelerationForThisDash = false;
     }
     this.m_sein.FaceLeft = this.m_faceLeft;
     this.m_stopAnimation = false;
     if (dashSound)
     {
         Sound.Play(dashSound.GetSound(null), this.m_sein.Position, null);
     }
     this.m_sein.Animation.Play(dashAnimation, 154, new Func <bool>(this.KeepDashAnimationPlaying));
     if (SeinDashAttack.RainbowDashActivated)
     {
         ((GameObject)InstantiateUtility.Instantiate(this.DashFollowRainbowEffect, this.m_sein.Position, Quaternion.identity)).transform.parent = this.m_sein.Transform;
     }
     this.m_sein.PlatformBehaviour.PlatformMovement.LocalSpeedY = -this.DashDownwardSpeed;
 }
示例#13
0
        private void ApplyConfiguration(Configuration oldConfiguration)
        {
            // General
            GeneralSettings general = this.configuration.General;

            this.view.HideFromTaskbar = general.HideFromTaskbar;
            // Display (Mouse, Tracking and Watermark)
            this.DisplaySettings = new DisplaySettings()
            {
                Mouse     = configuration.Mouse,
                Tracking  = configuration.Tracking,
                Watermark = configuration.Watermark,
            };
            this.view.TrackingSettings = configuration.Tracking;
            // Hot Keys
            HotKeySettings hotKey = this.configuration.HotKeys;

            this.view.CancelHotKey = hotKey.Cancel;
            this.view.PauseHotKey  = hotKey.Pause;
            this.view.RecordHotKey = hotKey.Record;
            this.view.StopHotKey   = hotKey.Stop;
            this.UpdateHotKeys(oldConfiguration != null ? oldConfiguration.HotKeys : null);
            // Sound
            SoundSettings sound = this.configuration.Sound;

            SoundDevice[] soundDevices = SoundProvider.GetDevices();
            this.view.SoundDevices = soundDevices;
            string      soundDeviceId = sound.DeviceId;
            SoundDevice soundDevice   = null;

            if (!string.IsNullOrEmpty(soundDeviceId))
            {
                soundDevice = SoundProvider.GetDeviceOrDefault(soundDeviceId);
                if (soundDevice != null)
                {
                    // Update configuration if device id is invalid
                    sound.DeviceId = soundDevice.Id;
                }
            }
            this.view.SoundDevice = soundDevice;
            this.SoundSettings    = this.configuration.Sound;
            // Get updated (valid) configuration from recorder
            this.configuration.Sound = this.SoundSettings;
            // Video
            this.recorder.VideoSettings = this.configuration.Video;
            // Get updated (valid) configuration from recorder
            this.configuration.Video = this.recorder.VideoSettings;
            this.UpdateView();
        }
示例#14
0
        private void view_Load(object sender, EventArgs e)
        {
            // TODO: Display screen bit depth (16, 24 and 32 is currently supported)
            // Read config
            Configuration config = this.view.Configuration;

            if (config == null)
            {
                return;
            }
            // Get list of sound devices
            SoundDevice[] soundDevices = SoundProvider.GetDevices();
            this.view.SoundDevices = soundDevices;
            string soundDeviceId = config.Sound.DeviceId;

            if (!string.IsNullOrEmpty(soundDeviceId))
            {
                foreach (var soundDevice in soundDevices)
                {
                    if (soundDevice.Id.Equals(soundDeviceId))
                    {
                        this.view.SoundDevice = soundDevice;
                        break;
                    }
                }
            }
            // Get list of video compressors
            var compressors = new List <VideoCompressor>(VideoCompressor.GetAll());

            compressors.Add(VideoCompressor.None);
            this.view.VideoCompressors = compressors.ToArray();
            string compressorFCC = this.view.Configuration.Video.Compressor;

            // Find video compressor using it's ffc handler string
            if (!string.IsNullOrEmpty(compressorFCC))
            {
                foreach (var compressor in compressors)
                {
                    uint fccHandler = VideoCompressor.FccHandlerFromString(compressorFCC);
                    if (compressor.FccHandler == fccHandler)
                    {
                        this.view.VideoCompressor = compressor;
                        break;
                    }
                }
            }
        }
示例#15
0
        public static void LoadSounds(Logger logger, SoundProvider soundProvider, string folderLocation)
        {
            foreach (var fileName in FileServices.GetResourceFiles(folderLocation, ".ogg", ".wav", ".flac", ".mp3"))
            {
                var sound = FileServices.LoadAudioResource(fileName);

                if (sound != null)
                {
                    sound.name = FileServices.GetEndOfResourcePath(fileName);
                    soundProvider.AddSound(sound);
                }
                else
                {
                    logger.Log("WARNING! tried to load a sound into the provider but it was null! (file : " + fileName + ")");
                }
            }
        }
示例#16
0
        /// <summary>
        /// Gets the transform information for all object types and calls the relevant apply method for each one.
        /// </summary>
        protected virtual void Animate(float deltaTime)
        {
            FrameData = DataProvider.GetFrameData(Time, deltaTime, factor, CurrentAnimation, NextAnimation);

            for (int i = 0; i < FrameData.SpriteData.Count; ++i)
            {
                SpriterObject info   = FrameData.SpriteData[i];
                TSprite       sprite = SpriteProvider.Get(info.FolderId, info.FileId);
                if (sprite != null)
                {
                    ApplySpriteTransform(sprite, info);
                }
            }

            for (int i = 0; i < FrameData.Sounds.Count; ++i)
            {
                SpriterSound info  = FrameData.Sounds[i];
                TSound       sound = SoundProvider.Get(info.FolderId, info.FileId);
                if (sound != null)
                {
                    PlaySound(sound, info);
                }
            }

            var pointE = FrameData.PointData.GetEnumerator();

            while (pointE.MoveNext())
            {
                var e = pointE.Current;
                ApplyPointTransform(e.Key, e.Value);
            }

            var boxE = FrameData.BoxData.GetEnumerator();

            while (boxE.MoveNext())
            {
                var e = boxE.Current;
                ApplyBoxTransform(Entity.ObjectInfos[e.Key], e.Value);
            }

            for (int i = 0; i < FrameData.Events.Count; ++i)
            {
                DispatchEvent(FrameData.Events[i]);
            }
        }
示例#17
0
        public void Record(DisplayProvider displayProvider, SoundProvider soundProvider)
        {
            if (this.fileName == null)
            {
                throw new InvalidOperationException("FileName is not specified");
            }
            // Check state
            lock (syncRoot) {
                if (state != RecordingState.Idle)
                {
                    throw new InvalidOperationException("Invalid state.");
                }
                state = RecordingState.Preparing;
            }
            record = new RecordDelegate(this.RecordPrivate);
            AsyncCallback callback = new AsyncCallback(this.RecordCallBack);

            record.BeginInvoke(displayProvider, soundProvider, callback, null); // Start a new thread for recording
        }
示例#18
0
        public MainPresenter(IMainView view)
        {
            if (view == null)
            {
                throw new ArgumentNullException("view");
            }
            // Load configuration
            this.configuration = Configuration.Load();
            // Initialize recorder
            this.displayProvider = new DisplayProvider();
            this.displaySettings = new DisplaySettings()
            {
                Mouse     = this.displayProvider.MouseSettings,
                Tracking  = this.displayProvider.TrackingSettings,
                Watermark = this.displayProvider.WatermarkSettings,
            };
            this.soundProvider = new SoundProvider();
            this.soundSettings = new SoundSettings()
            {
                DeviceId = this.soundProvider.DeviceId,
                Format   = this.soundProvider.Format,
            };
            this.recorder        = new Recorder();
            this.recorder.Error += new RecordErrorEventHandler(recorder_Error);

            // Initialize view
            this.view = view;
            this.InitializeView();

            // Apply configuration
            this.ApplyConfiguration(null);

            // Update View
            this.view.AllowUpdate = true;
            // this.UpdateView();
        }
示例#19
0
        public void Start()
        {
            /* RESOURCE LIST CREATION */
#if UNITY_EDITOR
            AssetDatabase.Refresh();
            FileServices.CreateResourcesList("Assets/Resources/resourceslist.txt");
#endif
            FileServices.LoadResourcesList("resourceslist");

            #region LOAD RESOURCES
            // logger and ioc
            _logger   = new Logger("info.log", false);
            _resolver = new IoCResolver(_logger);
            _resolver.RegisterItem(_logger);

            _config = new UserConfigurationManager(new UserConfigurationData
            {
                GameVolume  = 1f,
                MusicVolume = 1f
            });
            _resolver.RegisterItem(_config);

            // messager
            _messager = new Messager();
            _resolver.RegisterItem(_messager);

            // unity reference master
            _unity = GetComponent <UnityReferenceMaster>();
            _unity.DebugModeActive = false;
            _resolver.RegisterItem(_unity);

            // player
            var player = new UserAccountManager();
            _resolver.RegisterItem(player);

            // material provider
            var materialProvider = new MaterialProvider(_logger);
            MaterialLoader.LoadMaterial(materialProvider, "Materials");
            _resolver.RegisterItem(materialProvider);

            // texture provider
            var textureProvider = new TextureProvider(_logger);
            var spriteProvider  = new SpriteProvider(_logger);
            TextureLoader.LoadTextures(textureProvider, spriteProvider, "Textures");
            _resolver.RegisterItem(textureProvider);
            _resolver.RegisterItem(spriteProvider);

            // sound provider
            var soundProvider = new SoundProvider(_logger);
            SoundLoader.LoadSounds(_logger, soundProvider, "Sounds");
            _resolver.RegisterItem(soundProvider);

            // prefab provider
            var prefabProvider = new PrefabProvider(_logger);
            PrefabLoader.LoadPrefabs(prefabProvider);
            _resolver.RegisterItem(prefabProvider);

            // pooling
            var poolingObjectManager = new PoolingObjectManager(_logger, prefabProvider);
            _resolver.RegisterItem(poolingObjectManager);

            var soundPoolManager = new PoolingAudioPlayer(_logger, _config, _unity, prefabProvider.GetPrefab("audio_source_prefab"));
            _resolver.RegisterItem(soundPoolManager);

            _particles = new PoolingParticleManager(_resolver);
            _resolver.RegisterItem(_particles);

            // canvas provider
            var canvasProvider = new CanvasProvider(_logger);
            _unity.LoadCanvases(canvasProvider);
            _resolver.RegisterItem(canvasProvider);

            // data provider
            var gameDataProvider = new GameDataProvider(_logger);

            /* DATA GOES HERE */

            _resolver.RegisterItem(gameDataProvider);
            #endregion

            _uiManager = new UiManager();
            _resolver.RegisterItem(_uiManager);

            // lock the resolver (stop any new items being registered)
            _resolver.Lock();

            /* BEGIN STATE */
            _currentState = new MenuState(_resolver);
            _currentState.Initialize();

            /* SUBSCRIBE FOR GAME END */
            _onExit = _messager.Subscribe <ExitMessage>(OnExit);
        }
示例#20
0
        private void RecordPrivate(DisplayProvider displayProvider, SoundProvider soundProvider)
        {
            bool       recordDisplay = displayProvider != null;
            bool       recordSound   = soundProvider != null;
            AviFile    aviFile       = null;
            AcmEncoder audioEncoder  = null;

            this.duration = TimeSpan.Zero;
            try {
                DisplayFormat videoFormat = null;
                SoundFormat   audioFormat = null;

                int soundReadInterval = 0;
                if (recordDisplay)
                {
                    displayProvider.Open();
                    videoFormat = displayProvider.Format;
                }
                if (recordSound)
                {
                    soundProvider.Open();
                    soundReadInterval = (int)Math.Ceiling(soundProvider.BufferLength / 2.0); // ms
                    audioFormat       = soundProvider.Format;
                    audioEncoder      = soundProvider.GetEncoder();
                }
                // Open AVI file
                aviFile = new AviFile();
                aviFile.Open(fileName, videoFormat, fps, this.compressor, audioFormat, audioEncoder);

                // Initialize helper variables
                int      frameIndex         = 0;
                int      frameDuration      = recordDisplay ? (int)(msPerSecond / this.fps) : 0;
                int      frameBufferLength  = recordDisplay ? displayProvider.BitmapBytes : 0;
                int      startingFrameIndex = 0;
                int      soundSampleIndex   = 0;
                long     startTime          = DateTime.Now.Ticks;
                long     lastSoundRead      = DateTime.Now.Ticks;
                TimeSpan prevDuration       = TimeSpan.Zero;
                TimeSpan currentDuration    = TimeSpan.Zero;

                // Update state
                lock (syncRoot) {
                    this.state = RecordingState.Recording;
                }
                if (recordSound)
                {
                    // Start sound recording
                    soundProvider.Start();
                }
                // Recording loop; this is a long one huh?!
                do
                {
                    // Check if paused
                    if (this.state == RecordingState.Paused)
                    {
                        prevDuration = prevDuration.Add(currentDuration);
                        if (recordSound)
                        {
                            // Read remaining sound data and stop sound recording
                            byte[] soundData = soundProvider.Read(true);
                            soundSampleIndex += aviFile.AddSound(soundSampleIndex, soundData, true);
                            soundProvider.Stop();
                        }
                        // Let the thread executing Pause() know that pause is done
                        this.stateTransition.Set();
                        while (this.state == RecordingState.Paused)
                        {
                            Thread.Sleep(pauseDelay);
                        }

                        // State is changed, check new state
                        if (this.state == RecordingState.Idle)
                        {
                            return;
                        }

                        // Resume() is called
                        if (recordSound)
                        {
                            soundProvider.Start();
                            lastSoundRead = DateTime.Now.Ticks;
                        }
                        if (recordDisplay)
                        {
                            startingFrameIndex = frameIndex;
                        }

                        // Reset duration variables
                        startTime       = DateTime.Now.Ticks;
                        currentDuration = TimeSpan.Zero;

                        // Let that executing thread known resume is done
                        this.stateTransition.Set();
                    }

                    // Add a video from
                    if (recordDisplay)
                    {
                        // Render display and add rendered bitmap to the avi file
                        displayProvider.Render();
                        IntPtr pFrameData = displayProvider.Lock();
                        try {
                            aviFile.AddFrame(pFrameData, frameIndex, 1, frameBufferLength);
                        }
                        finally {
                            displayProvider.Unlock();
                        }
                        frameIndex++;
                    }

                    // Add sound
                    if (recordSound)
                    {
                        // Read recorded sound if it's time to do so
                        if ((DateTime.Now.Ticks - lastSoundRead) / ticksPerMs >= soundReadInterval)
                        {
                            // Read sound data
                            SoundFormat sourceFormat = soundProvider.SourceFormat;
                            byte[]      soundData    = soundProvider.Read();
                            int         samplesRead  = (int)(soundData.Length / sourceFormat.BlockAlign);

                            // Get number of out of sync samples
                            TimeSpan durationByNow     = prevDuration + new TimeSpan(DateTime.Now.Ticks - startTime);
                            int      nOutOfSyncSamples = GetOutOfSyncSamples(soundProvider, soundSampleIndex, durationByNow,
                                                                             samplesRead);
                            if (nOutOfSyncSamples > 0)
                            {
                                // Add silence samples if we have less than expected samples
                                soundSampleIndex += aviFile.AddSilence(soundSampleIndex, nOutOfSyncSamples);
                            }
                            else if (nOutOfSyncSamples < 0)
                            {
                                // Drop read samples as much as possible if we have more than expected samples
                                int nSamplesToKeep = Math.Max(0, samplesRead + nOutOfSyncSamples);
                                if (nSamplesToKeep > 0)
                                {
                                    int    nBytesToKeep     = nSamplesToKeep * sourceFormat.BlockAlign;
                                    int    nBytesToDrop     = soundData.Length - nBytesToKeep;
                                    byte[] droppedSoundData = new byte[nBytesToKeep];
                                    Array.Copy(soundData, nBytesToDrop, droppedSoundData, 0, nBytesToKeep);
                                    soundData = droppedSoundData;
                                }
                                samplesRead = nSamplesToKeep;
                            }
                            // Add sound data to the avi file
                            if (samplesRead > 0)
                            {
                                soundSampleIndex += aviFile.AddSound(soundSampleIndex, soundData, false);
                            }
                            lastSoundRead = DateTime.Now.Ticks;
                        }
                    }

                    // Synchronize display
                    if (recordDisplay)
                    {
                        long delay = (DateTime.Now.Ticks - startTime) / ticksPerMs -
                                     frameDuration * ((frameIndex - startingFrameIndex) - 1);
                        if (delay < frameDuration)
                        {
                            // Extra delay to synchornize with fps
                            Thread.Sleep((int)(frameDuration - delay));
                        }
                        else
                        {
                            // Calculate how many frames are lost
                            int lostFrames = (int)Math.Floor((decimal)delay / frameDuration);
                            frameIndex += lostFrames;
                            // Extra delay to synchornize with fps
                            Thread.Sleep((int)(frameDuration - delay % frameDuration));
                        }
                    }
                    else /* No display recording, just sleep for a while so that sound buffers get filled  */
                    {
                        Thread.Sleep(1);
                    }

                    // Update duration
                    currentDuration = new TimeSpan(DateTime.Now.Ticks - startTime);
                    this.duration   = prevDuration + currentDuration;
                } while (this.state != RecordingState.Idle);

                // Read remaining sound data and stop sound recording
                if (recordSound)
                {
                    byte[] soundData = soundProvider.Read(true);
                    soundSampleIndex += aviFile.AddSound(soundSampleIndex, soundData, true);
                    soundProvider.Stop();
                }
            }
            finally {
                if (recordSound)
                {
                    soundProvider.Close();
                    if (audioEncoder != null)
                    {
                        audioEncoder.Dispose();
                    }
                }
                if (recordDisplay)
                {
                    displayProvider.Close();
                }
                if (aviFile != null)
                {
                    aviFile.Dispose();
                }
            }
        }