Fixed a really cool race condition where a byte[] was being GC'ed in the middle of a call to PlaySound()

Also, added MouseWheel Zoom animations
This commit is contained in:
shanselman 2008-07-11 00:09:06 +00:00
Родитель 151825beb3
Коммит c222771312
12 изменённых файлов: 139 добавлений и 56 удалений

Просмотреть файл

@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.CodeDom.Compiler;
namespace BabySmash
{
public class Winmm
public class Win32Audio
{
public const UInt32 SND_ASYNC = 0x0001;
public const UInt32 SND_LOOP = 0x0008;
@ -16,29 +17,45 @@ namespace BabySmash
// this is the overload we want to play embedded resource...
public static Dictionary<string, byte[]> cachedWavs = new Dictionary<string, byte[]>();
public static Dictionary<string, string> cachedWavs = new Dictionary<string, string>();
public static object cachedWavsLock = new object();
[DllImport("Winmm.dll")]
[DllImport("winmm.dll", SetLastError = true)]
static extern bool PlaySound(string pszSound, IntPtr hmod, UInt32 fdwSound);
[DllImport("winmm.dll")]
public static extern bool PlaySound(byte[] data, IntPtr hMod, UInt32 dwFlags);
public static void PlayWavResource(string wav)
public void PlayWavResource(string wav)
{
byte[] b = GetWavResource(wav);
PlaySound(b, IntPtr.Zero, SND_ASYNC | SND_MEMORY);
string s = GetWavResource(wav);
PlaySound(s, IntPtr.Zero, SND_ASYNC);
}
public static void PlayWavResourceYield(string wav)
public void PlayWavResourceYield(string wav)
{
byte[] b = GetWavResource(wav);
PlaySound(b, IntPtr.Zero, SND_ASYNC | SND_MEMORY | SND_NOSTOP);
string s = GetWavResource(wav);
PlaySound(s, IntPtr.Zero, SND_ASYNC | SND_NOSTOP);
}
//public static void PlayWavResource(string wav)
//{
// byte[] b = GetWavResource(wav);
// PlaySound(b, IntPtr.Zero, SND_ASYNC | SND_MEMORY);
//}
private static byte[] GetWavResource(string wav)
//public static void PlayWavResourceYield(string wav)
//{
// byte[] b = GetWavResource(wav);
// PlaySound(b, IntPtr.Zero, SND_ASYNC | SND_MEMORY | SND_NOSTOP);
//}
TempFileCollection tempFiles = new TempFileCollection();
private string GetWavResource(string wav)
{
//TODO: Is this valid double-check caching?
byte[] b = null;
string b = null;
if (cachedWavs.ContainsKey(wav))
b = cachedWavs[wav];
if (b == null)
@ -51,17 +68,47 @@ namespace BabySmash
// get the resource into a stream
using (Stream str = Assembly.GetExecutingAssembly().GetManifestResourceStream(strNameSpace + wav))
{
if (str == null)
throw new ArgumentException(wav + " not found!");
// bring stream into a byte array
string tempfile = System.IO.Path.GetTempFileName();
tempFiles.AddFile(tempfile,false);
var bStr = new Byte[str.Length];
str.Read(bStr, 0, (int) str.Length);
cachedWavs.Add(wav, bStr);
return bStr;
str.Read(bStr, 0, (int)str.Length);
File.WriteAllBytes(tempfile, bStr);
cachedWavs.Add(wav, tempfile);
return tempfile;
}
}
}
return b;
}
//private static byte[] GetWavResource(string wav)
//{
// //TODO: Is this valid double-check caching?
// byte[] b = null;
// if (cachedWavs.ContainsKey(wav))
// b = cachedWavs[wav];
// if (b == null)
// {
// lock (cachedWavsLock)
// {
// // get the namespace
// string strNameSpace = Assembly.GetExecutingAssembly().GetName().Name;
// // get the resource into a stream
// using (Stream str = Assembly.GetExecutingAssembly().GetManifestResourceStream(strNameSpace + wav))
// {
// if (str == null)
// throw new ArgumentException(wav + " not found!");
// // bring stream into a byte array
// var bStr = new Byte[str.Length];
// str.Read(bStr, 0, (int) str.Length);
// cachedWavs.Add(wav, bStr);
// return bStr;
// }
// }
// }
// return b;
//}
}
}

Просмотреть файл

@ -20,6 +20,7 @@ namespace BabySmash
private readonly SpeechSynthesizer objSpeech = new SpeechSynthesizer();
private readonly List<MainWindow> windows = new List<MainWindow>();
private int FiguresCount = 0;
private readonly Win32Audio audio = new Win32Audio();
public void Launch()
{
@ -109,11 +110,34 @@ namespace BabySmash
face.FaceVisible = Settings.Default.FacesOnShapes ? Visibility.Visible : Visibility.Hidden;
}
f.MouseLeftButtonDown += HandleMouseLeftButtonDown;
f.MouseEnter += f_MouseEnter;
f.MouseWheel += f_MouseWheel;
}
FiguresCount++;
PlaySound(template);
}
void f_MouseWheel(object sender, MouseWheelEventArgs e)
{
if(lastEnteredUserControl != null)
{
if (e.Delta < 0)
{
Animation.ApplyZoom(lastEnteredUserControl, new Duration(TimeSpan.FromSeconds(0.5)), 2.5);
}
else
{
Animation.ApplyZoom(lastEnteredUserControl, new Duration(TimeSpan.FromSeconds(0.5)), 0.5);
}
}
}
private UserControl lastEnteredUserControl;
void f_MouseEnter(object sender, MouseEventArgs e)
{
lastEnteredUserControl = sender as UserControl;
}
void HandleMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
UserControl f = sender as UserControl;
@ -144,9 +168,9 @@ namespace BabySmash
}
}
private static void PlayLaughter()
private void PlayLaughter()
{
Winmm.PlayWavResource(Utils.GetRandomSoundFile());
audio.PlayWavResource(Utils.GetRandomSoundFile());
}
private void SpeakString(string s)
@ -186,18 +210,18 @@ namespace BabySmash
isDrawing = true;
main.CaptureMouse();
Winmm.PlayWavResource(".Resources.Sounds." + "smallbumblebee.wav");
audio.PlayWavResource(".Resources.Sounds." + "smallbumblebee.wav");
}
public void MouseWheel(MainWindow main, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
Winmm.PlayWavResource(".Resources.Sounds." + "rising.wav");
audio.PlayWavResourceYield(".Resources.Sounds." + "rising.wav");
}
else
{
Winmm.PlayWavResource(".Resources.Sounds." + "falling.wav");
audio.PlayWavResourceYield(".Resources.Sounds." + "falling.wav");
}
}
@ -243,7 +267,7 @@ namespace BabySmash
Canvas.SetTop(shape, p.Y - 25);
if (Settings.Default.MouseDraw)
Winmm.PlayWavResourceYield(".Resources.Sounds." + "smallbumblebee.wav");
audio.PlayWavResourceYield(".Resources.Sounds." + "smallbumblebee.wav");
}
public void LostMouseCapture(MainWindow main, MouseEventArgs e)

Просмотреть файл

@ -20,7 +20,7 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="43" />
<RowDefinition Height="Auto" MinHeight="20" />
<RowDefinition Height="Auto" MinHeight="43" />
<RowDefinition Height="Auto" MinHeight="20" />
<RowDefinition Height="Auto" MinHeight="20" />
@ -38,11 +38,14 @@
<Bold>Welcome to BabySmash!</Bold><LineBreak/>We're adding new features weekly.
This week added click animations and all new graphics!
<LineBreak/>Try turning <Bold>OFF</Bold> Clickless Mouse <LineBreak/>and show your baby<LineBreak/> how to click on shapes!<LineBreak/>
<Italic>There's even more fun soon!</Italic>
<Italic>There's even more fun coming soon!</Italic>
</TextBlock >
<Label Height="23" Margin="10,20,0,0" Grid.Row="0" Grid.ColumnSpan="1">Clear after x Shapes</Label>
<TextBox Text="{Binding Path=Default.ClearAfter}" Grid.Row="0"
Height="23" Width="40" Grid.Column="1" Margin="15,20,0,0" HorizontalAlignment="Right"/>
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.ColumnSpan="2" Height="43" VerticalAlignment="Top">
<Label Margin="10,20,0,0" >Clear screen after</Label>
<TextBox Text="{Binding Path=Default.ClearAfter}"
Height="20" Width="30" Margin="0,20,0,0" />
<Label Margin="0,20,0,0" >Shapes</Label>
</StackPanel>
<Label Height="23" Grid.Row="1" Margin="10">Sounds</Label>
<ComboBox
SelectedValue="{Binding Path=Default.Sounds}"
@ -67,16 +70,16 @@
IsChecked="{Binding Path=Default.MouseDraw,Mode=TwoWay}" >
Clickless Mouse Drawing
</CheckBox>
<StackPanel Orientation="Horizontal"
<StackPanel Orientation="Horizontal"
Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Stretch">
<CheckBox x:Name="FadeChecked" Margin="15,0,0,0"
<CheckBox x:Name="FadeChecked" Margin="15,0,0,0"
IsChecked="{Binding Path=Default.FadeAway,Mode=TwoWay}" >
Fade Shapes Away in</CheckBox>
<TextBox Margin="5,0,0,0"
Text="{Binding Path=Default.FadeAfter}"
IsEnabled="{Binding ElementName=FadeChecked,Path=IsChecked,Mode=TwoWay}"
Height="20" Width="25" />
<TextBlock>secs.</TextBlock>
Height="20" Width="30" />
<TextBlock Margin="5,0,0,0">secs.</TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="8" Grid.ColumnSpan="2" HorizontalAlignment="Right">

Просмотреть файл

@ -109,6 +109,25 @@ namespace BabySmash
fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da);
}
public static void ApplyZoom(FrameworkElement fe, Duration duration, double scale)
{
var da = new DoubleAnimation
{
From = 1,
To = scale,
Duration = duration,
AutoReverse = true
};
da.AccelerationRatio = da.DecelerationRatio = 0.2;
fe.RenderTransformOrigin = new Point(0.5, 0.5);
fe.RenderTransform = new ScaleTransform(scale, scale);
fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, da);
fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da);
}
public static void ApplyRotate(FrameworkElement fe, Duration duration)
{
DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames();
@ -144,5 +163,10 @@ namespace BabySmash
fe.RenderTransform = new ScaleTransform(1, 1);
fe.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, da);
}
public static void DoZoom(FrameworkElement lastEnteredUserControl)
{
}
}
}

Просмотреть файл

@ -15,36 +15,21 @@
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="CircleEye2" Storyboard.TargetProperty="(UIElement.Opacity)" RepeatBehavior="Forever">
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="CircleSpin">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Circle" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.6000000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.7000000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.9000000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<!--<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Circle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="-50"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.6000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.7000000" Value="5"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.9000000" Value="0"/>
</DoubleAnimationUsingKeyFrames>-->
</Storyboard>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource CircleEyesSB}"/>
<BeginStoryboard Storyboard="{StaticResource CircleSpin}"/>
</EventTrigger>
</UserControl.Triggers>

Просмотреть файл

@ -14,7 +14,7 @@
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>

Просмотреть файл

@ -14,7 +14,7 @@
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>

Просмотреть файл

@ -14,7 +14,7 @@
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>

Просмотреть файл

@ -14,7 +14,7 @@
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>

Просмотреть файл

@ -14,7 +14,7 @@
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>

Просмотреть файл

@ -14,7 +14,7 @@
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>

Просмотреть файл

@ -14,7 +14,7 @@
<SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:02.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:10.300000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:7.300000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>