簡體   English   中英

隨機時間間隔生成器,用於在指定的時間段內設置一定數量的實例

[英]Random Interval Generator For a Set Number of Instances Over a Set Period of Time

我在c#中遇到了一個有趣的問題,我不確定該怎么做。

我需要兩個曲目互相疊加播放。 需要在設定的時間內播放恆定數量的蜂鳴聲。 其中一個將有一個固定的間隔(以節拍器為准),但另一個則需要以隨機的間隔播放。

我不確定如何解決第二個問題,即在一定時間內隨機播放一定數量的嗶嗶聲。

只需花費設定的時間T,即可將其表示為某種足夠細粒度的結構(以毫秒為單位)。 如果您需要發出N次蜂鳴聲,則需要將時間間隔拆分N次。 因此,使一個循環運行N次,並且在每次迭代中,在時間間隔中為蜂鳴聲選擇一個隨機位置。 根據之后對數據的處理方式,可能需要對提示音點進行排序。

使用隨機數生成可在總時間范圍內生成日期時間。 完成放置隨機蜂鳴聲后,間隔當然是隨機的。 像這樣:

    List<DateTime> randomBeeps = new List<DateTime>();

    Random rand = new Random();
    for( int j = 0; j < numberBeepsNeeded; j++ )
    {
         int randInt = rand.Next();
         double percent = ((double)randInt) / Int32.MaxValue;
         double randTicksOfTotal = ((double)setAmountOfTime.Ticks) * percent;
         DateTime randomBeep = new DateTime((long)randTicksOfTotal);
         randomBeeps.Add(randomBeep);
    }

您可能需要使用Convert.ToLong或類似的東西。 不知道它是否會在四舍五入的過程中給您從double轉換為long的錯誤,在這里很好。

您可以將其實現為一系列的一次性計時器。 當每個計時器到期(或“滴答”)時,您會發出嗶聲,然后隨機確定下一個計時器的持續時間。 如果您選擇的持續時間是介於1到1000(毫秒)之間的某個隨機數,則您將平均每半秒一次“滴答”。

編輯:只是為了好玩,我想提一提,這對於行為心理學家進行由BF Skinner啟發的各種實驗是一個老問題。 他們有時使用稱為“可變間隔”的加固計划,其中加固之間的時間在某個預定的平均間隔附近隨機變化。 請參閱http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1404199/pdf/jeabehav00190-0145.pdf ,以深入了解所涉及的公式。

這樣的事情應該可以解決(此代碼未經測試...但是編譯干凈)

using System;
using System.Security.Cryptography;
using System.Threading;

class BeatBox : IDisposable
{
    private RandomNumberGenerator RNG;

    private DateTime dtStarted;
    private TimeSpan TimeElapsed { get { return DateTime.Now - dtStarted; } }

    private TimeSpan  Duration;
    private TimeSpan  BeatInterval;
    private uint      MinRandomInterval;
    private uint      MaxRandomInterval;
    private uint      RandomIntervalDomain;

    private Timer     RegularIntervalTimer;
    private Timer     RandomIntervalTimer;

    public delegate void TickHandler( object sender , bool isRandom );
    public event TickHandler TickEvent;

    private EventWaitHandle CompletionEventWaitHandle;

    public BeatBox( TimeSpan duration , TimeSpan beatInterval , uint minRandomInterval , uint maxRandomInterval )
    {
        this.RNG = RandomNumberGenerator.Create();

        this.Duration             = duration          ;
        this.BeatInterval         = beatInterval      ;
        this.MinRandomInterval    = minRandomInterval ;
        this.MaxRandomInterval    = maxRandomInterval ;
        this.RandomIntervalDomain = ( maxRandomInterval - minRandomInterval ) + 1 ;
        this.dtStarted            = DateTime.MinValue ;

        this.RegularIntervalTimer = null ;
        this.RandomIntervalTimer  = null ;

        return;
    }

    private long NextRandomInterval()
    {
        byte[] entropy = new byte[sizeof(long)] ;

        RNG.GetBytes( entropy );

        long randomValue    = BitConverter.ToInt64( entropy , 0 ) & long.MaxValue; // ensure that its positive
        long randomoffset   = ( randomValue % this.RandomIntervalDomain );
        long randomInterval = this.MinRandomInterval + randomoffset;

        return randomInterval;
    }

    public EventWaitHandle Start()
    {
        long randomInterval = NextRandomInterval();

        this.CompletionEventWaitHandle = new ManualResetEvent( false );
        this.RegularIntervalTimer = new Timer( RegularBeat , null , BeatInterval , BeatInterval );
        this.RandomIntervalTimer = new Timer( RandomBeat , null , randomInterval , Timeout.Infinite );

        return this.CompletionEventWaitHandle;
    }

    private void RegularBeat( object timer )
    {
        if ( this.TimeElapsed >= this.Duration )
        {
            MarkComplete();
        }
        else
        {
            this.TickEvent.Invoke( this , false );
        }
        return;
    }
    private void RandomBeat( object timer )
    {
        if ( this.TimeElapsed >= this.Duration )
        {
            MarkComplete();
        }
        else
        {
            this.TickEvent.Invoke( this , true );

            long nextInterval = NextRandomInterval();
            this.RandomIntervalTimer.Change( nextInterval , Timeout.Infinite );

        }
        return;
    }

    private void MarkComplete()
    {
        lock ( this.CompletionEventWaitHandle )
        {
            bool signaled = this.CompletionEventWaitHandle.WaitOne( 0 );
            if ( !signaled )
            {
                this.RegularIntervalTimer.Change( Timeout.Infinite , Timeout.Infinite );
                this.RandomIntervalTimer.Change( Timeout.Infinite , Timeout.Infinite );
                this.CompletionEventWaitHandle.Set();
            }
        }
        return;
    }

    public void Dispose()
    {
        if ( RegularIntervalTimer != null )
        {
            WaitHandle handle = new ManualResetEvent( false );
            RegularIntervalTimer.Dispose( handle );
            handle.WaitOne();
        }
        if ( RandomIntervalTimer != null )
        {
            WaitHandle handle = new ManualResetEvent( false );
            RegularIntervalTimer.Dispose( handle );
            handle.WaitOne();
        }
        return;
    }
}

class Program
{
    static void Main( string[] args )
    {
        TimeSpan duration          = new TimeSpan( 0 , 5 , 0 ); // run for 5 minutes total
        TimeSpan beatInterval      = new TimeSpan( 0 , 0 , 1 ); // regular beats every 1 second
        uint     minRandomInterval = 5; // minimum random interval is 5ms
        uint     maxRandomInterval = 30; // maximum random interval is 30ms

        using ( BeatBox beatBox = new BeatBox( duration , beatInterval , minRandomInterval , maxRandomInterval ) )
        {
            beatBox.TickEvent += TickHandler;

            EventWaitHandle completionHandle = beatBox.Start();

            completionHandle.WaitOne();

        }
        return;
    }

    static void TickHandler( object sender , bool isRandom )
    {
        Console.WriteLine( isRandom ? "Random Beep!" : "Beep!" );
        return;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM