2011-10-31 55 views
4

我在c#中遇到了一个令人感兴趣的问题,我不知道该怎么做。随机间隔发生器对于设定的时间段内的实例数量

我需要有两个轨道顶部彼此玩。一定数量的嘟嘟声需要在一段时间内播放。其中一个会有一个设定的时间间隔(想想节拍器),但另一个需要随机播放。

我不确定如何解决第二个问题,在设定的时间内随机播放一组嘟嘟声。

回答

2

只需要设置一定的时间量T即可表示为某种足够细化的结构,也就是说毫秒。如果您需要发出N次哔哔声,则需要将时间段拆分N次。因此,建立一个循环,运行N次,并且在每次迭代中,在时间间隔中选择随机位置以发出嘟嘟声。根据您之后对数据所做的操作,您可能需要对哔声点进行排序。

+0

您可能还需要验证您没有选择同一个点的两倍。 – Fantius

+0

这里的哔哔声是划分点,而不是块,所以对于N次哔哔声,您需要在时间间隔内有N个随机位置。当然,这将导致N + 1个块。 – phoog

+0

OP也可能希望确保哔哔声的时间不超过某个最小跨度。例如,如果哔哔声本身需要500毫秒才能发声,则可能需要将哔声至少保持半秒钟。 – phoog

0

使用随机数生成在总时间范围内生成日期时间。当你完成随机发出的嘟嘟声时,间隔当然是随机的。像这样:

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或类似的东西。不知道它是否会给你一个从双倍到长整数的错误,因为它正在四舍五入,这在这里很好。

0

您可以将其作为一系列单次定时器来实现。当每个定时器到期(或“滴答”)时,您会播放蜂鸣声,然后随机确定用于下一个单次定时器的持续时间。如果您选择的持续时间是1到1000(毫秒)之间的某个随机数,则您将每半秒平均一次“打勾”。

编辑:只是为了好玩,我想我会提一下,这是行为心理学家运行由B.F. Skinner启发的各种实验的老问题。他们有时使用称为“可变间隔”的加固时间表,其中加固之间的时间在某个预定平均间隔内随机变化。请参阅http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1404199/pdf/jeabehav00190-0145.pdf以了解涉及的公式。

0

像这样的东西应该做的伎俩(此代码没有测试...但它编译干净的)

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; 
    } 
}