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:
Родитель
151825beb3
Коммит
c222771312
81
Audio.cs
81
Audio.cs
|
@ -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)
|
||||
|
|
21
Options.xaml
21
Options.xaml
|
@ -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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче