private void playNextMessage(int carsOnLeftCount, int carsOnRightCount, DateTime now)
 {
     if (nextMessageType != NextMessageType.none && now > nextMessageDue)
     {
         if (messageIsValid(nextMessageType, carsOnLeftCount, carsOnRightCount))
         {
             switch (nextMessageType)
             {
                 case NextMessageType.threeWide:
                     audioPlayer.removeImmediateClip(folderStillThere);
                     audioPlayer.removeImmediateClip(folderCarLeft);
                     audioPlayer.removeImmediateClip(folderCarRight);
                     audioPlayer.removeImmediateClip(folderClearAllRound);
                     audioPlayer.removeImmediateClip(folderClearLeft);
                     audioPlayer.removeImmediateClip(folderClearRight);
                     QueuedMessage inTheMiddleMessage = new QueuedMessage(folderInTheMiddle, 0, null);
                     inTheMiddleMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + inTheMiddleMessageExpiresAfter;
                     audioPlayer.playClipImmediately(inTheMiddleMessage, true, true);
                     nextMessageType = NextMessageType.stillThere;
                     nextMessageDue = now.Add(repeatHoldFrequency);
                     reportedOverlapLeft = true;
                     reportedOverlapRight = true;
                     wasInMiddle = true;
                     break;
                 case NextMessageType.carLeft:
                     audioPlayer.removeImmediateClip(folderStillThere);
                     audioPlayer.removeImmediateClip(folderInTheMiddle);
                     audioPlayer.removeImmediateClip(folderCarRight);
                     audioPlayer.removeImmediateClip(folderClearAllRound);
                     audioPlayer.removeImmediateClip(folderClearLeft);
                     audioPlayer.removeImmediateClip(folderClearRight);
                     QueuedMessage carLeftMessage = new QueuedMessage(folderCarLeft, 0, null);
                     carLeftMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                     audioPlayer.playClipImmediately(carLeftMessage, true, true);
                     nextMessageType = NextMessageType.stillThere;
                     nextMessageDue = now.Add(repeatHoldFrequency);
                     reportedOverlapLeft = true;
                     break;
                 case NextMessageType.carRight:
                     audioPlayer.removeImmediateClip(folderStillThere);
                     audioPlayer.removeImmediateClip(folderCarLeft);
                     audioPlayer.removeImmediateClip(folderInTheMiddle);
                     audioPlayer.removeImmediateClip(folderClearAllRound);
                     audioPlayer.removeImmediateClip(folderClearLeft);
                     audioPlayer.removeImmediateClip(folderClearRight);
                     QueuedMessage carRightMessage = new QueuedMessage(folderCarRight, 0, null);
                     carRightMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                     audioPlayer.playClipImmediately(carRightMessage, true, true);
                     nextMessageType = NextMessageType.stillThere;
                     nextMessageDue = now.Add(repeatHoldFrequency);
                     reportedOverlapRight = true;
                     break;
                 case NextMessageType.clearAllRound:
                     if (reportedOverlapLeft || reportedOverlapRight)
                     {
                         QueuedMessage clearAllRoundMessage = new QueuedMessage(folderClearAllRound, 0, null);
                         clearAllRoundMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearAllRoundMessageExpiresAfter;
                         audioPlayer.removeImmediateClip(folderCarLeft);
                         audioPlayer.removeImmediateClip(folderStillThere);
                         audioPlayer.removeImmediateClip(folderCarRight);
                         audioPlayer.removeImmediateClip(folderInTheMiddle);
                         audioPlayer.removeImmediateClip(folderClearLeft);
                         audioPlayer.removeImmediateClip(folderClearRight);
                         audioPlayer.playClipImmediately(clearAllRoundMessage, false);
                         nextMessageType = NextMessageType.none;
                     }
                     audioPlayer.closeChannel();
                     reportedOverlapLeft = false;
                     reportedOverlapRight = false;
                     wasInMiddle = false;
                     break;
                 case NextMessageType.clearLeft:
                     if (reportedOverlapLeft)
                     {
                         if (carsOnRightCount == 0 && wasInMiddle)
                         {
                             QueuedMessage clearAllRoundMessage = new QueuedMessage(folderClearAllRound, 0, null);
                             clearAllRoundMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                             audioPlayer.removeImmediateClip(folderCarLeft);
                             audioPlayer.removeImmediateClip(folderStillThere);
                             audioPlayer.removeImmediateClip(folderCarRight);
                             audioPlayer.removeImmediateClip(folderInTheMiddle);
                             audioPlayer.removeImmediateClip(folderClearRight);
                             audioPlayer.removeImmediateClip(folderClearLeft);
                             audioPlayer.playClipImmediately(clearAllRoundMessage, false);
                             nextMessageType = NextMessageType.none;
                             audioPlayer.closeChannel();
                             reportedOverlapRight = false;
                             wasInMiddle = false;
                         }
                         else
                         {
                             QueuedMessage clearLeftMessage = new QueuedMessage(folderClearLeft, 0, null);
                             clearLeftMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                             audioPlayer.removeImmediateClip(folderCarLeft);
                             audioPlayer.removeImmediateClip(folderStillThere);
                             audioPlayer.removeImmediateClip(folderCarRight);
                             audioPlayer.removeImmediateClip(folderInTheMiddle);
                             audioPlayer.removeImmediateClip(folderClearRight);
                             audioPlayer.removeImmediateClip(folderClearAllRound);
                             audioPlayer.playClipImmediately(clearLeftMessage, false);
                             if (wasInMiddle)
                             {
                                 nextMessageType = NextMessageType.carRight;
                                 nextMessageDue = now.Add(repeatHoldFrequency);
                             }
                             else
                             {
                                 nextMessageType = NextMessageType.none;
                             }
                         }
                     }
                     if (carsOnRightCount == 0)
                     {
                         audioPlayer.closeChannel();
                     }
                     reportedOverlapLeft = false;
                     break;
                 case NextMessageType.clearRight:
                     if (reportedOverlapRight)
                     {
                         if (carsOnLeftCount == 0 && wasInMiddle)
                         {
                             QueuedMessage clearAllRoundMessage = new QueuedMessage(folderClearAllRound, 0, null);
                             clearAllRoundMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                             audioPlayer.removeImmediateClip(folderCarLeft);
                             audioPlayer.removeImmediateClip(folderStillThere);
                             audioPlayer.removeImmediateClip(folderCarRight);
                             audioPlayer.removeImmediateClip(folderInTheMiddle);
                             audioPlayer.removeImmediateClip(folderClearLeft);
                             audioPlayer.removeImmediateClip(folderClearRight);
                             audioPlayer.playClipImmediately(clearAllRoundMessage, false);
                             nextMessageType = NextMessageType.none;
                             audioPlayer.closeChannel();
                             reportedOverlapLeft = false;
                             wasInMiddle = false;
                         }
                         else
                         {
                             QueuedMessage clearRightMessage = new QueuedMessage(folderClearRight, 0, null);
                             clearRightMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                             audioPlayer.removeImmediateClip(folderCarLeft);
                             audioPlayer.removeImmediateClip(folderStillThere);
                             audioPlayer.removeImmediateClip(folderCarRight);
                             audioPlayer.removeImmediateClip(folderInTheMiddle);
                             audioPlayer.removeImmediateClip(folderClearLeft);
                             audioPlayer.removeImmediateClip(folderClearAllRound);
                             audioPlayer.playClipImmediately(clearRightMessage, false);
                             if (wasInMiddle)
                             {
                                 nextMessageType = NextMessageType.carLeft;
                                 nextMessageDue = now.Add(repeatHoldFrequency);
                             }
                             else
                             {
                                 nextMessageType = NextMessageType.none;
                             }
                         }
                     }
                     if (carsOnLeftCount == 0)
                     {
                         audioPlayer.closeChannel();
                     }
                     reportedOverlapRight = false;
                     break;
                 case NextMessageType.stillThere:
                     if (reportedOverlapLeft || reportedOverlapRight)
                     {
                         QueuedMessage holdYourLineMessage = new QueuedMessage(folderStillThere, 0, null);
                         holdYourLineMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                         audioPlayer.removeImmediateClip(folderClearRight);
                         audioPlayer.removeImmediateClip(folderClearLeft);
                         audioPlayer.removeImmediateClip(folderClearAllRound);
                         audioPlayer.playClipImmediately(holdYourLineMessage, true, false);
                         nextMessageType = NextMessageType.stillThere;
                         nextMessageDue = now.Add(repeatHoldFrequency);
                     }
                     break;
                 case NextMessageType.none:
                     break;
             }
         }
         else
         {
             audioPlayer.closeChannel();
             reportedOverlapLeft = false;
             reportedOverlapRight = false;
         }
     }
 }
 public void queueClip(QueuedMessage queuedMessage, PearlsOfWisdom.PearlType pearlType, double pearlMessageProbability)
 {
     if (queuedMessage.canBePlayed)
     {
         lock (queuedClips)
         {
             if (queuedClips.Contains(queuedMessage.messageName))
             {
                 Console.WriteLine("Clip for event " + queuedMessage.messageName + " is already queued, ignoring");
                 return;
             }
             else
             {
                 PearlsOfWisdom.PearlMessagePosition pearlPosition = PearlsOfWisdom.PearlMessagePosition.NONE;
                 if (pearlType != PearlsOfWisdom.PearlType.NONE && checkPearlOfWisdomValid(pearlType))
                 {
                     pearlPosition = pearlsOfWisdom.getMessagePosition(pearlMessageProbability);
                 }
                 if (pearlPosition == PearlsOfWisdom.PearlMessagePosition.BEFORE)
                 {
                     QueuedMessage pearlQueuedMessage = new QueuedMessage(queuedMessage.abstractEvent);
                     pearlQueuedMessage.dueTime = queuedMessage.dueTime;
                     queuedClips.Add(PearlsOfWisdom.getMessageFolder(pearlType), pearlQueuedMessage);
                 }
                 queuedClips.Add(queuedMessage.messageName, queuedMessage);
                 if (pearlPosition == PearlsOfWisdom.PearlMessagePosition.AFTER)
                 {
                     QueuedMessage pearlQueuedMessage = new QueuedMessage(queuedMessage.abstractEvent);
                     pearlQueuedMessage.dueTime = queuedMessage.dueTime;
                     queuedClips.Add(PearlsOfWisdom.getMessageFolder(pearlType), pearlQueuedMessage);
                 }
             }
         }
     }
 }
 public void queueClip(QueuedMessage queuedMessage)
 {
     queueClip(queuedMessage, PearlsOfWisdom.PearlType.NONE, 0);
 }
 public void playClipImmediately(QueuedMessage queuedMessage, Boolean keepChannelOpen, Boolean useShortBeep)
 {
     if (disableImmediateMessages)
     {
         return;
     }
     if (queuedMessage.canBePlayed)
     {
         lock (immediateClips)
         {
             if (immediateClips.Contains(queuedMessage.messageName))
             {
                 Console.WriteLine("Clip for event " + queuedMessage.messageName + " is already queued, ignoring");
                 return;
             }
             else
             {
                 if (keepChannelOpen)
                 {
                     holdOpenChannel(useShortBeep);
                 }
                 else
                 {
                     openChannel(useShortBeep);
                 }
                 immediateClips.Add(queuedMessage.messageName, queuedMessage);
             }
         }
     }
 }
 public void playClipImmediately(QueuedMessage queuedMessage, Boolean useShortBeep)
 {
     playClipImmediately(queuedMessage, false, useShortBeep);
 }
 private List<String> playSounds(List<String> eventNames, Boolean isImmediateMessages, out Boolean wasInterrupted)
 {
     //Console.WriteLine("Playing sounds, events: " + String.Join(", ", eventNames));
     List<String> soundsProcessed = new List<String>();
     OrderedDictionary thisQueue = isImmediateMessages ? immediateClips : queuedClips;
     wasInterrupted = false;
     int playedEventCount = 0;
     foreach (String eventName in eventNames)
     {
         // if there's anything in the immediateClips queue, stop processing
         if (isImmediateMessages || immediateClips.Count == 0)
         {
             if (thisQueue.Contains(eventName))
             {
                 QueuedMessage thisMessage = (QueuedMessage)thisQueue[eventName];
                 if (!isImmediateMessages && playedEventCount > 0 && pauseBetweenMessages > 0)
                 {
                     Console.WriteLine("Pausing before " + eventName);
                     Thread.Sleep(TimeSpan.FromSeconds(pauseBetweenMessages));
                 }
                 if (clipIsPearlOfWisdom(eventName))
                 {
                     soundsProcessed.Add(eventName);
                     if (hasPearlJustBeenPlayed())
                     {
                         Console.WriteLine("Rejecting pearl of wisdom " + eventName +
                             " because one has been played in the last " + minTimeBetweenPearlsOfWisdom + " seconds");
                         continue;
                     }
                     else if (!allowPearlsOnNextPlay)
                     {
                         Console.WriteLine("Rejecting pearl of wisdom " + eventName +
                             " because they've been temporarily disabled");
                         continue;
                     }
                     else if (disablePearlsOfWisdom)
                     {
                         Console.WriteLine("Rejecting pearl of wisdom " + eventName +
                                " because pearls have been disabled for the last phase of the race");
                         continue;
                     }
                     else
                     {
                         timeLastPearlOfWisdomPlayed = DateTime.UtcNow;
                         List<SoundPlayer> clipsList = clips[eventName];
                         int index = random.Next(0, clipsList.Count);
                         SoundPlayer clip = clipsList[index];
                         if (!mute)
                         {
                             clip.PlaySync();
                         }
                     }
                 }
                 else
                 {
                     lastMessagePlayed = thisMessage;
                     foreach (String message in thisMessage.messageFolders)
                     {
                         List<SoundPlayer> clipsList = clips[message];
                         int index = random.Next(0, clipsList.Count);
                         SoundPlayer clip = clipsList[index];
                         if (!mute)
                         {
                             clip.PlaySync();
                         }
                     }
                     if (playedMessagesCount.ContainsKey(eventName))
                     {
                         int count = playedMessagesCount[eventName] + 1;
                         playedMessagesCount[eventName] = count;
                     }
                     else
                     {
                         playedMessagesCount.Add(eventName, 1);
                     }
                     soundsProcessed.Add(eventName);
                 }
                 playedEventCount++;
             }
         }
         else
         {
             Console.WriteLine("we've been interrupted after playing " + playedEventCount + " events");
             wasInterrupted = true;
             break;
         }
     }
     if (soundsProcessed.Count == 0)
     {
         Console.WriteLine("Processed no messages in this queue");
         holdChannelOpen = true;
     }
     else
     {
         Console.WriteLine("*** Processed " + String.Join(", ", soundsProcessed.ToArray()));
     }
     return soundsProcessed;
 }