Permalink
Browse files

Translation sample:

Shows using Translation API for language translation
and text to speech conversion.
Also shows view/viewmodel interaction via bindings, commands and triggers
  • Loading branch information...
1 parent a901192 commit 09544261bd6d3c2e8e301ce7410323b3dc1893ff unknown committed Mar 23, 2010
View
7 samples/Samples.sln
@@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "News", "News\News.csproj",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwitFaves", "TwitFaves\TwitFaves.csproj", "{DB259CE6-96A8-4F59-A0D5-A3F6815F4732}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Translate", "Translate\Translate.csproj", "{CDDC7D32-B9D3-4828-B145-933780C87089}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -83,6 +85,10 @@ Global
{DB259CE6-96A8-4F59-A0D5-A3F6815F4732}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB259CE6-96A8-4F59-A0D5-A3F6815F4732}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB259CE6-96A8-4F59-A0D5-A3F6815F4732}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CDDC7D32-B9D3-4828-B145-933780C87089}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CDDC7D32-B9D3-4828-B145-933780C87089}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CDDC7D32-B9D3-4828-B145-933780C87089}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CDDC7D32-B9D3-4828-B145-933780C87089}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -99,5 +105,6 @@ Global
{A8C08DAF-477C-4CEB-9AA8-21C412A06452} = {38EE0482-5653-49CE-9C94-EBF490218D23}
{750026A4-3EA6-4D5F-B6DB-EBECDD3A8D3A} = {38EE0482-5653-49CE-9C94-EBF490218D23}
{DB259CE6-96A8-4F59-A0D5-A3F6815F4732} = {38EE0482-5653-49CE-9C94-EBF490218D23}
+ {CDDC7D32-B9D3-4828-B145-933780C87089} = {38EE0482-5653-49CE-9C94-EBF490218D23}
EndGlobalSection
EndGlobal
View
BIN samples/Translate/Assets/Background.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
61 samples/Translate/Assets/Styles.xaml
@@ -0,0 +1,61 @@
+<ResourceDictionary
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+
+ <Style x:Key="logo" TargetType="ContentControl">
+ <Setter Property="ContentTemplate">
+ <Setter.Value>
+ <DataTemplate>
+ <Canvas Width="48" Height="48" Margin="10">
+ <Path Width="17.845" Height="25.211" Canvas.Left="22.934" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 45.76,5.29333C 46.4133,2.13333 50.2,4.09333 52.24,4.28C 54.56,4.78667 55.5733,6.28 55.0133,8.69334C 57.28,7.45333 60.04,4.97334 62.5867,7.12C 64.1067,12.7867 56.6667,13.3733 52.92,14.2533C 52.8133,14.4533 52.6267,14.84 52.52,15.04C 55.4267,15.0933 59.2133,14.8133 61.28,17.1333C 58.76,17.9067 56.5067,19.52 53.8533,19.8533C 53.7467,19.2267 53.5467,17.9733 53.44,17.36L 52.3333,17.4267C 52.4933,18.0667 52.8133,19.36 52.9733,20C 51.1333,20.6533 49.0933,21.1733 47.96,22.9333C 47.6133,25.04 49.3333,26.8 49.68,28.8133L 48.8267,30.6133C 48.4933,29.44 47.8267,27.08 47.4933,25.8933C 44.84,28.0667 41.32,31.6933 42.9467,35.4C 42.84,35.68 42.6533,36.24 42.5467,36.52C 44.4,37 46.2667,37.4533 48.0267,38.2267C 45.6,39.3067 42.8533,39.28 40.32,38.7067C 37.4133,37.1867 37.36,33.5067 37.8,30.68C 39.3467,26.2133 43.3467,23.4667 47.2,21.1333C 47.32,19 47.2533,16.8533 47.2267,14.7067C 43.6,15.2267 39.68,13.9467 38.0933,10.3867C 40.4667,5.44 44.2533,12.8 47.9867,10.4933C 49.04,8 48.0267,6.41334 45.76,5.29333 Z " UseLayoutRounding="False" Canvas.Top="0.664" StrokeThickness="0"/>
+ <Path Width="21.561" Height="16.305" Canvas.Left="1.339" Canvas.Top="5.296" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 7,10.04C 10.1867,11.3867 12.08,14.64 14.9333,16.5467C 21.7333,12.9867 30.0533,13.1467 36.9733,16.3067L 37.4267,17.52C 32,18.3733 26.56,20.5867 23.2,25.1467C 20.5867,23.92 19.6667,20.5333 16.7867,19.6133C 14.2,19.0533 11.4933,18.2133 8.85333,18.9333C 8.28,21.3067 8.21333,23.7733 8.21333,26.2C 8.18667,28.12 8.24,30.0533 8.36,31.9733C 11.2533,32.0267 14.1333,31.9867 17.0267,32C 19.28,32.0133 21.56,32.0267 23.7867,31.6267C 24.0267,29.5733 24.2267,27.5333 24.3467,25.48C 26.2267,28.2667 30.2667,29.8 31.08,33.0267C 23.1067,33.0667 15.12,33.0667 7.13333,33.0267C 6.86667,25.3733 7.06667,17.6933 7,10.04 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="1.077" Height="1.87" Canvas.Left="33.305" Canvas.Top="10.476" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 52.3333,17.4267L 53.44,17.36C 53.5467,17.9733 53.7467,19.2267 53.8533,19.8533L 52.9733,20C 52.8133,19.36 52.4933,18.0667 52.3333,17.4267 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="21.128" Height="17.127" Canvas.Left="26.372" Canvas.Top="10.378" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 53.8533,19.8533C 56.5067,19.52 58.76,17.9067 61.28,17.1333C 61.5333,17.48 62.0133,18.16 62.2667,18.5067C 66.8667,18.6533 71.4,21.8 72.32,26.48C 73.1467,34.8933 63.9333,41.7067 56.28,41.2933L 55.24,39.5867C 59.64,36.2267 68.6533,34.2267 66.9733,26.8267C 65.7067,24.5333 63.6267,21.9867 60.68,22.6533C 58.9733,25.6533 57.3867,28.7333 55.4,31.56C 56.16,32.6133 56.92,33.6667 57.6933,34.7067C 56.8267,37.2133 53.8533,36.5867 52.0133,35.76C 50.44,36.0667 49.52,37.6533 48.0267,38.2267C 46.2667,37.4533 44.4,37 42.5467,36.52C 42.6533,36.24 42.84,35.68 42.9467,35.4C 45.3467,34.72 48.28,33.2533 48.8267,30.6133L 49.68,28.8133C 49.3333,26.8 47.6133,25.04 47.96,22.9333C 49.0933,21.1733 51.1333,20.6533 52.9733,20L 53.8533,19.8533 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="11.428" Height="9.457" Canvas.Left="2.099" Canvas.Top="11.517" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 8.85333,18.9333C 11.4933,18.2133 14.2,19.0533 16.7867,19.6133C 19.6667,20.5333 20.5867,23.92 23.2,25.1467L 24.3467,25.48C 24.2267,27.5333 24.0267,29.5733 23.7867,31.6267C 21.56,32.0267 19.28,32.0133 17.0267,32C 16.0533,27.9733 12.32,25.4933 8.21333,26.2C 8.21333,23.7733 8.28,21.3067 8.85333,18.9333 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="4.445" Height="5.157" Canvas.Left="32.065" Canvas.Top="13.153" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 52.52,21.04C 53.5733,21.0267 55.6667,21.0133 56.72,21C 56.36,23.7467 54.7467,27.16 52.1867,28.28C 50.7333,26.4533 50.0267,24.1733 50.7067,21.8533L 52.5867,22.9333C 52.5333,23.6 52.4,24.9467 52.3333,25.6133C 53.4933,26.44 56.24,22.3733 53.6933,22.5067L 52.52,21.04 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="6.248" Height="4.195" Canvas.Left="2.046" Canvas.Top="16.653" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 8.21333,26.2C 12.32,25.4933 16.0533,27.9733 17.0267,32C 14.1333,31.9867 11.2533,32.0267 8.36,31.9733C 8.24,30.0533 8.18667,28.12 8.21333,26.2 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="17.911" Height="21.405" Canvas.Left="0.449" Canvas.Top="25.358" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 9.90667,40.08C 15.24,37.8133 21.7733,37.48 27.04,40.1333C 31.6,42.92 30.76,48.8667 30.68,53.4133C 29.7067,58.16 30.9867,63.0133 31.0933,67.68C 29.1867,67.88 27.28,67.9867 25.3733,68.0133L 25.48,66.24C 26.52,66.36 28.6133,66.6 29.6533,66.72C 29.6133,60.4933 29.2667,54.28 29.08,48.0667C 23.5733,50.3467 26.8933,57.8533 25.48,62.4133C 24.84,62.4533 23.5467,62.5333 22.9067,62.5733C 23.3067,62.24 24.0933,61.5867 24.4933,61.2533C 24.68,59.0133 24.68,56.76 24.5733,54.5067C 20,52 9.92,54.5467 12.3733,61.36C 12.6933,61.6933 13.32,62.3467 13.64,62.6667C 13.36,63.7867 13.0933,64.9067 12.8133,66.0267C 15.6933,66.48 18.6133,66.7867 21.4133,67.6533C 16.6933,68.7733 10.4533,69.4133 7.13333,65.04C 4.21333,60.0267 6.24,52.2133 12.0667,50.36C 15.9867,48.64 20.4267,49.32 24.56,49.64C 25,47.3867 24.2133,44.44 21.5733,44.08C 17.92,42.88 14.3867,44.0533 10.8267,44.84C 10.16,43.32 9.85333,41.7333 9.90667,40.08 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="21.946" Height="16.453" Canvas.Left="20.828" Canvas.Top="30.769" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 41.64,45.96C 49.56,45.9733 57.4933,46.0933 65.4267,45.8933C 65.9467,53.6 65.5467,61.3867 65.6533,69.12C 62.9333,66.9867 60.5067,64.4933 57.9333,62.1867C 50.7733,65.8 41.3467,66.2533 34.72,61.28C 39.3867,60.72 43.9867,59.12 47.6267,56.0533C 50.7867,61.92 58.3733,61.6133 63.8133,59.7067C 64.2267,58.0933 64.4667,56.44 64.52,54.7733C 64.6133,52.8667 64.6267,50.9467 64.56,49.0267C 64.4,48.5467 64.1067,47.5733 63.9467,47.08C 60.3867,46.8533 56.8267,46.96 53.2667,46.8933C 51.28,46.7867 49.24,46.84 47.48,47.8933C 48.28,49.6533 49.32,51.2933 50.4,52.8933L 48.8133,53.6C 46.7333,50.8 42.8933,49.16 41.64,45.96 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="12.128" Height="6.734" Canvas.Left="29.91" Canvas.Top="31.369" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 47.48,47.8933C 49.24,46.84 51.28,46.7867 53.2667,46.8933C 53.0267,47.9867 52.84,49.0933 52.7067,50.2C 55.8267,54.9467 61.68,52.72 64.56,49.0267C 64.6267,50.9467 64.6133,52.8667 64.52,54.7733C 59.9067,56.7867 53.6933,57.5733 50.4,52.8933C 49.32,51.2933 48.28,49.6533 47.48,47.8933 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="8.397" Height="4.256" Canvas.Left="33.569" Canvas.Top="31.399" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 53.2667,46.8933C 56.8267,46.96 60.3867,46.8533 63.9467,47.08C 64.1067,47.5733 64.4,48.5467 64.56,49.0267C 61.68,52.72 55.8267,54.9467 52.7067,50.2C 52.84,49.0933 53.0267,47.9867 53.2667,46.8933 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="11.929" Height="13.875" Canvas.Left="5.31" Canvas.Top="32.228" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 25.48,62.4133C 26.8933,57.8533 23.5733,50.3467 29.08,48.0667C 29.2667,54.28 29.6133,60.4933 29.6533,66.72C 28.6133,66.6 26.52,66.36 25.48,66.24C 23.9867,66.2667 22.76,67.16 21.4133,67.6533C 18.6133,66.7867 15.6933,66.48 12.8133,66.0267C 13.0933,64.9067 13.36,63.7867 13.64,62.6667C 16.64,64.04 19.84,63.1467 22.9067,62.5733C 23.5467,62.5333 24.84,62.4533 25.48,62.4133 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ <Path Width="11.967" Height="5.698" Canvas.Left="29.971" Canvas.Top="35.662" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M 50.4,52.8933C 53.6933,57.5733 59.9067,56.7867 64.52,54.7733C 64.4667,56.44 64.2267,58.0933 63.8133,59.7067C 58.3733,61.6133 50.7867,61.92 47.6267,56.0533C 48.32,55.2667 49.7067,53.68 50.4,52.8933 Z " UseLayoutRounding="False" StrokeThickness="0"/>
+ </Canvas>
+ </DataTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <Style x:Key="titleText" TargetType="TextBlock">
+ <Setter Property="FontSize" Value="30" />
+ <Setter Property="FontFamily" Value="Segoe UI Light" />
+ <Setter Property="Foreground" Value="White" />
+ <Setter Property="Effect">
+ <Setter.Value>
+ <DropShadowEffect Color="Black" Opacity=".25" BlurRadius="6" ShadowDepth="0" />
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <Style x:Key="labelText" TargetType="TextBlock">
+ <Setter Property="FontSize" Value="14" />
+ <Setter Property="FontFamily" Value="Segoe UI" />
+ <Setter Property="Foreground" Value="White" />
+ <Setter Property="TextWrapping" Value="Wrap" />
+ <Setter Property="Margin" Value="4" />
+ </Style>
+
+ <Style x:Key="inputText" TargetType="TextBox">
+ <Setter Property="FontSize" Value="13" />
+ <Setter Property="FontFamily" Value="Segoe UI" />
+ <Setter Property="TextAlignment" Value="Left" />
+ <Setter Property="TextWrapping" Value="Wrap" />
+ </Style>
+
+ <Style x:Key="displayArea" TargetType="Border">
+ <Setter Property="Background" Value="#40000000" />
+ <Setter Property="BorderThickness" Value="0" />
+ <Setter Property="CornerRadius" Value="4" />
+ </Style>
+
+</ResourceDictionary>
View
23 samples/Translate/PlayWaveAudio.cs
@@ -0,0 +1,23 @@
+// PlayWaveAudio.cs
+//
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Windows.Data;
+using Translate.Services.Audio;
+using System.Windows.Interactivity;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+
+namespace Translate {
+
+ public class PlayWaveAudio : TriggerAction<MediaElement> {
+
+ protected override void InvokeAction(EventArgs e) {
+ StreamEventArgs streamEvent = (StreamEventArgs)e;
+ AssociatedObject.SetSource(new WaveMediaStreamSource(streamEvent.Stream));
+ }
+ }
+}
View
7 samples/Translate/Properties/AppManifest.xml
@@ -0,0 +1,7 @@
+<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+>
+ <Deployment.Parts>
+ </Deployment.Parts>
+
+</Deployment>
View
35 samples/Translate/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Translate")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Translate")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("37a000f7-8613-4b32-8fce-b2799fac2c21")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
473 samples/Translate/Services/Audio/RiffParser.cs
@@ -0,0 +1,473 @@
+// RiffParser.cs
+//
+
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Translate.Services.Audio {
+
+ /// <summary>
+ /// The different FourCC codes we know of
+ /// </summary>
+ internal enum FourCC {
+
+ /// <summary>
+ /// FCC.FourCC('W', 'A', 'V', 'E')
+ /// </summary>
+ Wave = 0x45564157,
+
+ /// <summary>
+ /// FCC.FourCC('f', 'm', 't', ' ')
+ /// </summary>
+ WavFmt = 0x20746d66,
+
+ /// <summary>
+ /// FCC.FourCC('D', 'A', 'T', 'A')
+ /// </summary>
+ WavData = 0x41544144,
+
+ /// <summary>
+ /// FCC.FourCC('d', 'a', 't', 'a')
+ /// </summary>
+ Wavdata = 0x61746164,
+
+ /// <summary>
+ /// FCC.FourCC('R', 'I', 'F', 'F')
+ /// </summary>
+ Riff = 0x46464952,
+
+ /// <summary>
+ /// FCC.FourCC('L', 'I', 'S', 'T')
+ /// </summary>
+ List = 0x5453494c,
+
+ /// <summary>
+ /// FCC.FourCC('A', 'V', 'I', ' ')
+ /// </summary>
+ Avi = 0x20495641,
+ }
+
+ /// <summary>
+ /// The structure of a RiffChunk
+ /// </summary>
+ internal struct RiffChunk {
+
+ /// <summary>
+ /// Gets or sets the FourCC code
+ /// </summary>
+ public FourCC FCC {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the data size of this chunk
+ /// </summary>
+ public uint Size {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the FourCC list
+ /// </summary>
+ public FourCC FCCList {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Is this a list chunk
+ /// </summary>
+ /// <returns>true or false</returns>
+ public bool IsList() {
+ return this.FCC == FourCC.List;
+ }
+ }
+
+ /// <summary>
+ /// Riff Parser. Parses a Riff style file.
+ /// </summary>
+ internal class RiffParser : IDisposable {
+
+ /// <summary>
+ /// The minimum size of a Riff List
+ /// </summary>
+ private const uint SizeOfRiffList = 12;
+
+ /// <summary>
+ /// The minimum size of a Riff Chunk
+ /// </summary>
+ private const uint SizeOfRiffChunk = 8;
+
+ /// <summary>
+ /// The current chunk
+ /// </summary>
+ private RiffChunk chunk;
+
+ /// <summary>
+ /// The current FourCC code
+ /// </summary>
+ private FourCC fccId;
+
+ /// <summary>
+ /// The current FourCC type
+ /// </summary>
+ private FourCC fccType;
+
+ /// <summary>
+ /// The stream that we are parsing
+ /// </summary>
+ private Stream stream;
+
+ /// <summary>
+ /// The binary reader for the stream
+ /// </summary>
+ private BinaryReader br;
+
+ /// <summary>
+ /// The number of bytes remaining in the stream
+ /// </summary>
+ private uint bytesRemaining;
+
+ /// <summary>
+ /// The size of the current container in bytes
+ /// </summary>
+ private uint containerSize;
+
+ /// <summary>
+ /// The offset of the current container in the stream
+ /// </summary>
+ private long containerOffset;
+
+ /// <summary>
+ /// The offset of the current chunk in the container
+ /// </summary>
+ private long currentChunkOffset;
+
+ /// <summary>
+ /// Initializes a new instance of the RiffParser class.
+ /// </summary>
+ /// <param name="stream">The stream that we will parse</param>
+ /// <param name="id">The primary Riff ID that we need</param>
+ /// <param name="startOfContainer">The start offset of the container in the stream</param>
+ public RiffParser(Stream stream, FourCC id, long startOfContainer) {
+ if (stream == null) {
+ throw new ArgumentNullException("stream");
+ }
+
+ this.fccId = id;
+ this.containerOffset = startOfContainer;
+
+ this.stream = stream;
+ this.br = new BinaryReader(stream);
+
+ this.ReadRiffHeader();
+ }
+
+ /// <summary>
+ /// Gets the RiffId
+ /// </summary>
+ public FourCC RiffId {
+ get {
+ return this.fccId;
+ }
+ }
+
+ /// <summary>
+ /// Gets the RiffType
+ /// </summary>
+ public FourCC RiffType {
+ get {
+ return this.fccType;
+ }
+ }
+
+ /// <summary>
+ /// Gets the current chunk
+ /// </summary>
+ public RiffChunk Chunk {
+ get {
+ return this.chunk;
+ }
+ }
+
+ /// <summary>
+ /// Gets the chunk'stream data position in the stream
+ /// </summary>
+ public long DataPosition {
+ get {
+ return this.currentChunkOffset + SizeOfRiffChunk;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of bytes left in the chunk
+ /// </summary>
+ public uint BytesRemainingInChunk {
+ get {
+ return this.bytesRemaining;
+ }
+ }
+
+ /// <summary>
+ /// Gets the actual size of a chunk (data + header)
+ /// </summary>
+ private long ChunkActualSize {
+ get {
+ return SizeOfRiffChunk + RiffRound(this.chunk.Size);
+ }
+ }
+
+ /// <summary>
+ /// Is the start index aligned
+ /// </summary>
+ /// <param name="startIndex">the start index</param>
+ /// <param name="align">The alignment value</param>
+ /// <returns>true or false</returns>
+ public static bool IsAligned(int startIndex, int align) {
+ return (startIndex % align) == 0;
+ }
+
+ /// <summary>
+ /// Is the start index aligned
+ /// </summary>
+ /// <param name="startIndex">the start index</param>
+ /// <param name="align">The alignment value</param>
+ /// <returns>true or false</returns>
+ public static bool IsAligned(long startIndex, int align) {
+ return (startIndex % align) == 0;
+ }
+
+ /// <summary>
+ /// Round a count for Riff chunks
+ /// </summary>
+ /// <param name="count">The count value that we want to round</param>
+ /// <returns>the rounded count</returns>
+ public static int RiffRound(int count) {
+ return count + (count & 1);
+ }
+
+ /// <summary>
+ /// Round a count for Riff chunks
+ /// </summary>
+ /// <param name="count">The count value that we want to round</param>
+ /// <returns>the rounded count</returns>
+ public static long RiffRound(long count) {
+ return count + (count & 1);
+ }
+
+ /// <summary>
+ /// Format a FourCC code
+ /// </summary>
+ /// <param name="fcc">The FourCC code</param>
+ /// <returns>A string for the FourCC code</returns>
+ public static string FormatFourCC(FourCC fcc) {
+ uint code = (uint)fcc;
+ return string.Format(
+ "{0}{1}{2}{3}",
+ (char)(code & 0xFF),
+ (char)((code >> 8) & 0xFF),
+ (char)((code >> 16) & 0xFF),
+ (char)((code >> 24) & 0xFF));
+ }
+
+ /// <summary>
+ /// Advance to the start of the next chunk and read the chunk header
+ /// </summary>
+ public void MoveToNextChunk() {
+ // chunk offset is always bigger than container offset,
+ // and both are always non-negative.
+ Debug.Assert(this.currentChunkOffset > this.containerOffset, "The chunk cannot be out of bounds of the container");
+ Debug.Assert(this.currentChunkOffset >= 0, "The chunk offset must be positive");
+ Debug.Assert(this.containerOffset >= 0, "The container offset must be positive");
+
+ long maxChunkSize;
+
+ // Update current chunk offset to the start of the next chunk
+ this.currentChunkOffset += this.ChunkActualSize;
+
+ // Are we at the end?
+ if (this.currentChunkOffset - this.containerOffset >= this.containerSize) {
+ throw new InvalidOperationException("We are at the end of the steam");
+ }
+
+ // Seek to the start of the chunk.
+ this.stream.Position = this.currentChunkOffset;
+
+ // Read the header.
+ this.ReadChunkHeader();
+
+ // This chunk cannot be any larger than (container size - (chunk offset - container offset) )
+ maxChunkSize = (long)this.containerSize - (this.currentChunkOffset - this.containerOffset);
+
+ if (maxChunkSize < this.ChunkActualSize) {
+ throw new InvalidOperationException("The current chunk is too big");
+ }
+
+ this.bytesRemaining = this.chunk.Size;
+ }
+
+ /// <summary>
+ /// Return a parser for a LIST
+ /// </summary>
+ /// <returns>A new parser for the list</returns>
+ public RiffParser EnumerateChunksInList() {
+ if (!this.chunk.IsList()) {
+ throw new InvalidOperationException("The current chunk is not a list");
+ }
+
+ return new RiffParser(this.stream, FourCC.List, this.currentChunkOffset);
+ }
+
+ /// <summary>
+ /// Print the chunk information of the current chunk and descendants
+ /// </summary>
+ /// <param name="indent">The indent level for this chunk</param>
+ public void PrintChunkInformation(int indent) {
+ try {
+ while (true) {
+ for (int i = 0; i < indent; i++) {
+ Console.Write("\t");
+ }
+
+ Console.WriteLine("{0} ({1} bytes) {2}", FormatFourCC(this.fccId), this.Chunk.Size, FormatFourCC(this.fccType));
+ if (this.chunk.IsList()) {
+ RiffParser listParser = this.EnumerateChunksInList();
+ listParser.PrintChunkInformation(indent + 1);
+ }
+
+ this.MoveToNextChunk();
+ }
+ }
+ catch (InvalidOperationException) {
+ }
+ }
+
+ /// <summary>
+ /// Move the file pointer to the start of the current chunk
+ /// </summary>
+ public void MoveToStartOfChunk() {
+ this.MoveToChunkOffset(0);
+ }
+
+ /// <summary>
+ /// Move the file pointer to a byte offset from the start of the
+ /// current chunk.
+ /// </summary>
+ /// <param name="offset">The offset we want to move to</param>
+ public void MoveToChunkOffset(uint offset) {
+ if (offset > this.chunk.Size) {
+ throw new ArgumentException("Offset specified is beyond the chunk");
+ }
+
+ this.stream.Position = this.currentChunkOffset + offset + SizeOfRiffChunk;
+ this.bytesRemaining = this.chunk.Size - offset;
+ }
+
+ /// <summary>
+ /// Read data from the current chunk. (Starts at the current file ptr.)
+ /// </summary>
+ /// <param name="count">The number of bytes we want to read</param>
+ /// <returns>The data read</returns>
+ public byte[] ReadDataFromChunk(uint count) {
+ if (count > this.bytesRemaining) {
+ throw new ArgumentException("Trying to read more than the size of the chunk");
+ }
+
+ this.stream.Position = this.currentChunkOffset + this.chunk.Size - this.bytesRemaining + RiffParser.SizeOfRiffChunk;
+
+ byte[] data = this.br.ReadBytes((int)count);
+ this.bytesRemaining -= (uint)data.Length;
+
+ return data;
+ }
+
+ /// <summary>
+ /// Process data from a chunk (just like reading without actually getting the data)
+ /// </summary>
+ /// <param name="count">The number of bytes we want to skip</param>
+ /// <returns>The number of bytes we want to skipped</returns>
+ public uint ProcessDataFromChunk(uint count) {
+ if (count > this.bytesRemaining) {
+ throw new ArgumentException("Trying to process more than the size of the chunk");
+ }
+
+ this.bytesRemaining -= count;
+
+ return count;
+ }
+
+ #region IDisposable Members
+ /// <summary>
+ /// Implement the Dispose method to release the resources
+ /// </summary>
+ public void Dispose() {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ #endregion
+
+ /// <summary>
+ /// Implementation of the IDisposable pattern
+ /// </summary>
+ /// <param name="disposing">Are we being destroyed</param>
+ protected virtual void Dispose(bool disposing) {
+ if (disposing) {
+ if (this.br != null) {
+ this.br.Close();
+ this.br = null;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Read the container header section. (The 'RIFF' or 'LIST' header.)
+ /// This method verifies the header is well-formed and caches the
+ /// container'stream FOURCC type.
+ /// </summary>
+ private void ReadRiffHeader() {
+ RiffChunk header = new RiffChunk();
+
+ // Riff chunks must be WORD aligned
+ if (!IsAligned(this.containerOffset, 2)) {
+ throw new InvalidOperationException("The chunk is not aligned");
+ }
+
+ // Offset must be positive.
+ if (this.containerOffset < 0) {
+ throw new InvalidOperationException("The container offset needs to be positive");
+ }
+
+ // Seek to the start of the container.
+ this.stream.Position = this.containerOffset;
+
+ // Read the header
+ header.FCC = (FourCC)this.br.ReadUInt32();
+ header.Size = this.br.ReadUInt32();
+ header.FCCList = (FourCC)this.br.ReadUInt32();
+
+ // Make sure the header ID matches what the caller expected.
+ if (header.FCC != this.fccId) {
+ throw new InvalidOperationException("We don't have the right FourCC code");
+ }
+
+ // The size given in the RIFF header does not include the 8-byte header.
+ // However, our _containerOffset is the offset from the start of the
+ // header. Therefore our container size = listed size + size of header.
+ this.containerSize = header.Size + SizeOfRiffChunk;
+ this.fccType = header.FCCList;
+
+ this.currentChunkOffset = this.containerOffset + SizeOfRiffList;
+
+ this.ReadChunkHeader();
+ }
+
+ private void ReadChunkHeader() {
+ this.chunk.FCC = (FourCC)this.br.ReadUInt32();
+ this.chunk.Size = this.br.ReadUInt32();
+ this.bytesRemaining = this.chunk.Size;
+ }
+ }
+}
View
130 samples/Translate/Services/Audio/WavParser.cs
@@ -0,0 +1,130 @@
+//-----------------------------------------------------------------------
+// <copyright file="WavParser.cs" company="Gilles Khouzam">
+// (c) Copyright Gilles Khouzam
+// This source is subject to the Microsoft Public License (Ms-PL)
+// All other rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Translate.Services.Audio {
+
+ /// <summary>
+ /// Class WavParser
+ /// Parses a standard WAVE file
+ /// </summary>
+ internal sealed class WavParser : RiffParser {
+
+ /// <summary>
+ /// The minimum size of the format structure
+ /// </summary>
+ private const uint MinFormatSize = WaveFormatEx.SizeOf - sizeof(short);
+
+ private WaveFormatEx waveFormat;
+ private long duration;
+
+ /// <summary>
+ /// Initializes a new instance of the WavParser class.
+ /// </summary>
+ /// <param name="stream">A stream that contains the Wave data</param>
+ public WavParser(Stream stream)
+ : base(stream, FourCC.Riff, 0) {
+ if (RiffType != FourCC.Wave) {
+ throw new InvalidOperationException("File is not a WAV file");
+ }
+ }
+
+ /// <summary>
+ /// Gets the WAVEFORMATEX structure
+ /// </summary>
+ public WaveFormatEx WaveFormatEx {
+ get {
+ return this.waveFormat;
+ }
+ }
+
+ /// <summary>
+ /// Gets the duration of the Wave file
+ /// </summary>
+ public long Duration {
+ get {
+ return this.duration;
+ }
+ }
+
+ /// <summary>
+ /// Parses the RIFF WAVE header.
+ /// .wav files should look like this:
+ /// RIFF ('WAVE'
+ /// 'fmt ' = WAVEFORMATEX structure
+ /// 'data' = audio data
+ /// )
+ /// </summary>
+ public void ParseWaveHeader() {
+ bool foundData = false;
+
+ try {
+ while (!foundData) {
+ // Go through each chunk and look for the WavFmt which
+ // contains the format information
+ if (Chunk.FCC == FourCC.WavFmt) {
+ this.ReadFormatBlock();
+ }
+ else if (Chunk.FCC == FourCC.WavData || Chunk.FCC == FourCC.Wavdata) {
+ // Found the Wave data.
+ foundData = true;
+ break;
+ }
+
+ MoveToNextChunk();
+ }
+ }
+ catch (Exception e) {
+ if (this.waveFormat == null || !foundData) {
+ throw new InvalidOperationException("Invalid file format", e);
+ }
+ }
+
+ // Now that we have a chunk with the data from the file,
+ // calculate the duration of the file based on the size
+ // of the buffer.
+ this.duration = this.waveFormat.AudioDurationFromBufferSize(Chunk.Size);
+ }
+
+ /// <summary>
+ /// Read the format block from the file and construct the WAVEFORMATEX
+ /// structure
+ /// </summary>
+ private void ReadFormatBlock() {
+ try {
+ Debug.Assert(Chunk.FCC == FourCC.WavFmt, "This is not a WavFmt chunk");
+ Debug.Assert(this.waveFormat == null, "The waveformat structure should have been set before");
+
+ // Some .wav files do not include the cbSize field of the WAVEFORMATEX
+ // structure. For uncompressed PCM audio, field is always zero.
+ uint formatSize = 0;
+ if (Chunk.Size < MinFormatSize) {
+ throw new InvalidOperationException("File is not a WAV file");
+ }
+
+ // Allocate a buffer for the WAVEFORMAT structure.
+ formatSize = Chunk.Size;
+
+ this.waveFormat = new WaveFormatEx();
+
+ // Read the format from the current chunk in the file
+ byte[] data = ReadDataFromChunk(formatSize);
+
+ // Copy the read data into our WAVFORMATEX
+ this.waveFormat.SetFromByteArray(data);
+ }
+ catch (Exception) {
+ this.waveFormat = null;
+ throw;
+ }
+ }
+ }
+}
View
256 samples/Translate/Services/Audio/WaveFormatEx.cs
@@ -0,0 +1,256 @@
+// WaveFormat.cs
+//
+
+using System;
+
+namespace Translate.Services.Audio {
+
+ /// <summary>
+ /// Class WAVEFORMATEX
+ /// Implementation of a standard WAVEFORMATEX structure
+ /// </summary>
+ internal class WaveFormatEx {
+
+ /// <summary>
+ /// The size of the basic structure
+ /// </summary>
+ public const uint SizeOf = 18;
+
+ /// <summary>
+ /// The different formats allowable. For now PCM is the only one we support
+ /// </summary>
+ private const short FormatPCM = 1;
+
+ /// <summary>
+ /// Gets or sets the FormatTag
+ /// </summary>
+ public short FormatTag {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the number of Channels
+ /// </summary>
+ public short Channels {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the number of samples per second
+ /// </summary>
+ public int SamplesPerSec {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the average bytes per second
+ /// </summary>
+ public int AvgBytesPerSec {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the alignment of the blocks
+ /// </summary>
+ public short BlockAlign {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the number of bits per sample (8 or 16)
+ /// </summary>
+ public short BitsPerSample {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the size of the structure
+ /// </summary>
+ public short Size {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Gets or sets the extension buffer
+ /// </summary>
+ public byte[] Ext {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Convert a BigEndian string to a LittleEndian string
+ /// </summary>
+ /// <param name="bigEndianString">A big endian string</param>
+ /// <returns>The little endian string</returns>
+ public static string ToLittleEndianString(string bigEndianString) {
+ if (bigEndianString == null) {
+ return string.Empty;
+ }
+
+ char[] bigEndianChars = bigEndianString.ToCharArray();
+
+ // Guard
+ if (bigEndianChars.Length % 2 != 0) {
+ return string.Empty;
+ }
+
+ int i, ai, bi, ci, di;
+ char a, b, c, d;
+ for (i = 0; i < bigEndianChars.Length / 2; i += 2) {
+ // front byte
+ ai = i;
+ bi = i + 1;
+
+ // back byte
+ ci = bigEndianChars.Length - 2 - i;
+ di = bigEndianChars.Length - 1 - i;
+
+ a = bigEndianChars[ai];
+ b = bigEndianChars[bi];
+ c = bigEndianChars[ci];
+ d = bigEndianChars[di];
+
+ bigEndianChars[ci] = a;
+ bigEndianChars[di] = b;
+ bigEndianChars[ai] = c;
+ bigEndianChars[bi] = d;
+ }
+
+ return new string(bigEndianChars);
+ }
+
+ /// <summary>
+ /// Convert the data to a hex string
+ /// </summary>
+ /// <returns>A string in hexadecimal</returns>
+ public string ToHexString() {
+ string s = string.Empty;
+
+ s += ToLittleEndianString(string.Format("{0:X4}", this.FormatTag));
+ s += ToLittleEndianString(string.Format("{0:X4}", this.Channels));
+ s += ToLittleEndianString(string.Format("{0:X8}", this.SamplesPerSec));
+ s += ToLittleEndianString(string.Format("{0:X8}", this.AvgBytesPerSec));
+ s += ToLittleEndianString(string.Format("{0:X4}", this.BlockAlign));
+ s += ToLittleEndianString(string.Format("{0:X4}", this.BitsPerSample));
+ s += ToLittleEndianString(string.Format("{0:X4}", this.Size));
+
+ return s;
+ }
+
+ /// <summary>
+ /// Set the data from a byte array (usually read from a file)
+ /// </summary>
+ /// <param name="byteArray">The array used as input to the stucture</param>
+ public void SetFromByteArray(byte[] byteArray) {
+ if ((byteArray.Length + 2) < SizeOf) {
+ throw new ArgumentException("Byte array is too small");
+ }
+
+ this.FormatTag = BitConverter.ToInt16(byteArray, 0);
+ this.Channels = BitConverter.ToInt16(byteArray, 2);
+ this.SamplesPerSec = BitConverter.ToInt32(byteArray, 4);
+ this.AvgBytesPerSec = BitConverter.ToInt32(byteArray, 8);
+ this.BlockAlign = BitConverter.ToInt16(byteArray, 12);
+ this.BitsPerSample = BitConverter.ToInt16(byteArray, 14);
+ if (byteArray.Length >= SizeOf) {
+ this.Size = BitConverter.ToInt16(byteArray, 16);
+ }
+ else {
+ this.Size = 0;
+ }
+
+ if (byteArray.Length > WaveFormatEx.SizeOf) {
+ this.Ext = new byte[byteArray.Length - WaveFormatEx.SizeOf];
+ Array.Copy(byteArray, (int)WaveFormatEx.SizeOf, this.Ext, 0, this.Ext.Length);
+ }
+ else {
+ this.Ext = null;
+ }
+ }
+
+ /// <summary>
+ /// Ouput the data into a string.
+ /// </summary>
+ /// <returns>A string representing the WAVEFORMATEX</returns>
+ public override string ToString() {
+ char[] rawData = new char[18];
+ BitConverter.GetBytes(this.FormatTag).CopyTo(rawData, 0);
+ BitConverter.GetBytes(this.Channels).CopyTo(rawData, 2);
+ BitConverter.GetBytes(this.SamplesPerSec).CopyTo(rawData, 4);
+ BitConverter.GetBytes(this.AvgBytesPerSec).CopyTo(rawData, 8);
+ BitConverter.GetBytes(this.BlockAlign).CopyTo(rawData, 12);
+ BitConverter.GetBytes(this.BitsPerSample).CopyTo(rawData, 14);
+ BitConverter.GetBytes(this.Size).CopyTo(rawData, 16);
+ return new string(rawData);
+ }
+
+ /// <summary>
+ /// Calculate the duration of audio based on the size of the buffer
+ /// </summary>
+ /// <param name="audioDataSize">the buffer size in bytes</param>
+ /// <returns>The duration of that buffer</returns>
+ public long AudioDurationFromBufferSize(uint audioDataSize) {
+ if (this.AvgBytesPerSec == 0) {
+ return 0;
+ }
+
+ return (long)audioDataSize * 10000000 / this.AvgBytesPerSec;
+ }
+
+ /// <summary>
+ /// Calculate the buffer size necessary for a duration of audio
+ /// </summary>
+ /// <param name="duration">the duration</param>
+ /// <returns>the size of the buffer necessary</returns>
+ public long BufferSizeFromAudioDuration(long duration) {
+ long size = duration * this.AvgBytesPerSec / 10000000;
+ uint remainder = (uint)(size % this.BlockAlign);
+ if (remainder != 0) {
+ size += this.BlockAlign - remainder;
+ }
+
+ return size;
+ }
+
+ /// <summary>
+ /// Validate that the Wave format is consistent.
+ /// </summary>
+ public void ValidateWaveFormat() {
+ if (this.FormatTag != FormatPCM) {
+ throw new InvalidOperationException("Only PCM format is supported");
+ }
+
+ if (this.Channels != 1 && this.Channels != 2) {
+ throw new InvalidOperationException("Only 1 or 2 channels are supported");
+ }
+
+ if (this.BitsPerSample != 8 && this.BitsPerSample != 16) {
+ throw new InvalidOperationException("Only 8 or 16 bit samples are supported");
+ }
+
+ if (this.Size != 0) {
+ throw new InvalidOperationException("Size must be 0");
+ }
+
+ if (this.BlockAlign != this.Channels * (this.BitsPerSample / 8)) {
+ throw new InvalidOperationException("Block Alignment is incorrect");
+ }
+
+ if (this.SamplesPerSec > (uint.MaxValue / this.BlockAlign)) {
+ throw new InvalidOperationException("SamplesPerSec overflows");
+ }
+
+ if (this.AvgBytesPerSec != this.SamplesPerSec * this.BlockAlign) {
+ throw new InvalidOperationException("AvgBytesPerSec is wrong");
+ }
+ }
+ }
+}
View
209 samples/Translate/Services/Audio/WaveMediaStreamSource.cs
@@ -0,0 +1,209 @@
+// WaveMediaStreamSource.cs
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Windows.Media;
+
+namespace Translate.Services.Audio {
+
+ /// <summary>
+ /// A Media Stream Source implemented to play WAVE files
+ /// </summary>
+ internal class WaveMediaStreamSource : MediaStreamSource, IDisposable {
+
+ /// <summary>
+ /// The stream that we're playing back
+ /// </summary>
+ private Stream stream;
+
+ /// <summary>
+ /// The WavParser that can extract the data
+ /// </summary>
+ private WavParser wavParser;
+
+ /// <summary>
+ /// The stream description
+ /// </summary>
+ private MediaStreamDescription audioDesc;
+
+ /// <summary>
+ /// The current position in the stream.
+ /// </summary>
+ private long currentPosition;
+
+ /// <summary>
+ /// The start position of the data in the stream
+ /// </summary>
+ private long startPosition;
+
+ /// <summary>
+ /// The current timestamp
+ /// </summary>
+ private long currentTimeStamp;
+
+ /// <summary>
+ /// The sample attributes (not used so empty)
+ /// </summary>
+ private Dictionary<MediaSampleAttributeKeys, string> emptySampleDict = new Dictionary<MediaSampleAttributeKeys, string>();
+
+ /// <summary>
+ /// Initializes a new instance of the WaveMediaStreamSource class.
+ /// </summary>
+ /// <param name="stream">The stream the will contain the data to playback</param>
+ public WaveMediaStreamSource(Stream stream) {
+ this.stream = stream;
+ }
+
+ /// <summary>
+ /// Implement the Dispose method to release the resources
+ /// </summary>
+ public void Dispose() {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Implementation of the IDisposable pattern
+ /// </summary>
+ /// <param name="disposing">Are we being destroyed</param>
+ protected virtual void Dispose(bool disposing) {
+ if (disposing) {
+ if (this.wavParser != null) {
+ this.wavParser.Dispose();
+ this.wavParser = null;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Open the media.
+ /// Create the structures.
+ /// </summary>
+ protected override void OpenMediaAsync() {
+ // Create a parser
+ this.wavParser = new WavParser(this.stream);
+
+ // Parse the header
+ this.wavParser.ParseWaveHeader();
+
+ this.wavParser.WaveFormatEx.ValidateWaveFormat();
+
+ this.startPosition = this.currentPosition = this.wavParser.DataPosition;
+
+ // Init
+ Dictionary<MediaStreamAttributeKeys, string> streamAttributes = new Dictionary<MediaStreamAttributeKeys, string>();
+ Dictionary<MediaSourceAttributesKeys, string> sourceAttributes = new Dictionary<MediaSourceAttributesKeys, string>();
+ List<MediaStreamDescription> availableStreams = new List<MediaStreamDescription>();
+
+ // Stream Description
+ streamAttributes[MediaStreamAttributeKeys.CodecPrivateData] = this.wavParser.WaveFormatEx.ToHexString();
+ MediaStreamDescription msd = new MediaStreamDescription(MediaStreamType.Audio, streamAttributes);
+
+ this.audioDesc = msd;
+ availableStreams.Add(this.audioDesc);
+
+ sourceAttributes[MediaSourceAttributesKeys.Duration] = this.wavParser.Duration.ToString();
+ ReportOpenMediaCompleted(sourceAttributes, availableStreams);
+ }
+
+ /// <summary>
+ /// Close the media. Release the resources.
+ /// </summary>
+ protected override void CloseMedia() {
+ // Close the stream
+ this.startPosition = this.currentPosition = 0;
+ this.wavParser = null;
+ this.audioDesc = null;
+ }
+
+ /// <summary>
+ /// Not implemented
+ /// </summary>
+ /// <param name="diagnosticKind">The diagnostic kind</param>
+ protected override void GetDiagnosticAsync(MediaStreamSourceDiagnosticKind diagnosticKind) {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Return the next sample requested
+ /// </summary>
+ /// <param name="mediaStreamType">The stream type that we are getting a sample for</param>
+ protected override void GetSampleAsync(MediaStreamType mediaStreamType) {
+ // Start with one second of data, rounded up to the nearest block.
+ uint bufferSize = (uint)AlignUp(
+ this.wavParser.WaveFormatEx.AvgBytesPerSec,
+ this.wavParser.WaveFormatEx.BlockAlign);
+
+ // Figure out how much data we have left in the chunk compared to the
+ // data that we need.
+ bufferSize = Math.Min(bufferSize, (uint)this.wavParser.BytesRemainingInChunk);
+ if (bufferSize > 0) {
+ this.wavParser.ProcessDataFromChunk(bufferSize);
+
+ // Send out the next sample
+ MediaStreamSample sample = new MediaStreamSample(
+ this.audioDesc,
+ this.stream,
+ this.currentPosition,
+ bufferSize,
+ this.currentTimeStamp,
+ this.emptySampleDict);
+
+ // Move our timestamp and position forward
+ this.currentTimeStamp += this.wavParser.WaveFormatEx.AudioDurationFromBufferSize(bufferSize);
+ this.currentPosition += bufferSize;
+
+ /* Uncomment to loop forever
+ // If there are no more bytes in the chunk, start again from the beginning
+ if (this.wavParser.BytesRemainingInChunk == 0)
+ {
+ this.wavParser.MoveToStartOfChunk();
+ this.currentPosition = this.startPosition;
+ }
+ */
+
+ ReportGetSampleCompleted(sample);
+ }
+ else {
+ // Report EOS
+ ReportGetSampleCompleted(new MediaStreamSample(this.audioDesc, null, 0, 0, 0, this.emptySampleDict));
+ }
+ }
+
+ /// <summary>
+ /// Called when asked to seek to a new position
+ /// </summary>
+ /// <param name="seekToTime">the time to seek to</param>
+ protected override void SeekAsync(long seekToTime) {
+ if (seekToTime > this.wavParser.Duration) {
+ throw new InvalidOperationException("The seek position is beyond the length of the stream");
+ }
+
+ this.currentPosition = this.wavParser.WaveFormatEx.BufferSizeFromAudioDuration(seekToTime) + this.startPosition;
+ this.currentTimeStamp = seekToTime;
+ ReportSeekCompleted(seekToTime);
+ }
+
+ /// <summary>
+ /// Stream media stream.
+ /// Not implemented
+ /// </summary>
+ /// <param name="mediaStreamDescription">The mediaStreamDescription that we want to switch to</param>
+ protected override void SwitchMediaStreamAsync(MediaStreamDescription mediaStreamDescription) {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Helper function to align a block
+ /// </summary>
+ /// <param name="a">The value we want to align</param>
+ /// <param name="b">The alignment value</param>
+ /// <returns>A new aligned value</returns>
+ private static int AlignUp(int a, int b) {
+ int tmp = a + b - 1;
+ return tmp - (tmp % b);
+ }
+ }
+}
View
38 samples/Translate/Services/Language.cs
@@ -0,0 +1,38 @@
+// Language.cs
+//
+
+using System;
+
+namespace Translate.Services {
+
+ public sealed class Language {
+
+ internal static readonly Language English = new Language("English", "en");
+ internal static readonly Language German = new Language("German", "de");
+ internal static readonly Language French = new Language("French", "fr");
+ internal static readonly Language Italian = new Language("Italian", "it");
+ internal static readonly Language Portugese = new Language("Portugese", "pt");
+ internal static readonly Language Russian = new Language("Russian", "ru");
+ internal static readonly Language Spanish = new Language("Spanish", "es");
+
+ private string _name;
+ private string _code;
+
+ public Language(string name, string code) {
+ _name = name;
+ _code = code;
+ }
+
+ public string Code {
+ get {
+ return _code;
+ }
+ }
+
+ public string Name {
+ get {
+ return _name;
+ }
+ }
+ }
+}
View
74 samples/Translate/Services/Translator.cs
@@ -0,0 +1,74 @@
+// Translator.cs
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.IO;
+using System.Net;
+using System.Runtime.Serialization;
+using System.Windows;
+using System.Windows.Browser;
+
+namespace Translate.Services {
+
+ internal sealed class Translator {
+
+ private const string SupportedLanguagesUriFormat = "http://api.microsofttranslator.com/V2/Http.svc/GetLanguagesForSpeak?appId={0}";
+ private const string TranslateUriFormat = "http://api.microsofttranslator.com/V2/Http.svc/Translate?appId={0}&to={2}&text={1}&from=en";
+ private const string SpeakUriFormat = "http://api.microsofttranslator.com/V2/Http.svc/Speak?appId={0}&text={1}&language={2}";
+
+ public void GetLanguages(Action<IEnumerable<Language>> languagesCallback) {
+ WebClient client = new WebClient();
+
+ client.OpenReadCompleted += (sender, e) => {
+ if (e.Error == null) {
+ DataContractSerializer dcs = new DataContractSerializer(typeof(List<string>));
+ List<string> languageCodes = dcs.ReadObject(e.Result) as List<string>;
+
+ IEnumerable<Language> languages =
+ from langCode in languageCodes
+ orderby langCode
+ select new Language(langCode, langCode);
+
+ languagesCallback(languages.ToArray());
+ }
+ };
+
+ string appID = Application.Current.Host.InitParams["TranslationApiKey"];
+ string url = String.Format(SupportedLanguagesUriFormat, appID);
+ client.OpenReadAsync(new Uri(url, UriKind.Absolute));
+ }
+
+ public void Translate(string text, string languageCode, Action<string> translationCallback) {
+ WebClient client = new WebClient();
+
+ client.OpenReadCompleted += (sender, e) => {
+ if (e.Error == null) {
+ DataContractSerializer dcs = new DataContractSerializer(typeof(string));
+ string translatedText = dcs.ReadObject(e.Result) as string;
+
+ translationCallback(translatedText);
+ }
+ };
+
+ string appID = Application.Current.Host.InitParams["TranslationApiKey"];
+ string url = String.Format(TranslateUriFormat, appID, HttpUtility.UrlEncode(text), languageCode);
+ client.OpenReadAsync(new Uri(url, UriKind.Absolute));
+ }
+
+ public void GetAudioStream(string text, string languageCode, Action<Stream> audioCallback) {
+ WebClient client = new WebClient();
+
+ client.OpenReadCompleted += (sender, e) => {
+ if (e.Error == null) {
+ audioCallback(e.Result);
+ }
+ };
+
+ string appID = Application.Current.Host.InitParams["TranslationApiKey"];
+ string url = String.Format(SpeakUriFormat, appID, HttpUtility.UrlEncode(text), languageCode);
+ client.OpenReadAsync(new Uri(url, UriKind.Absolute));
+ }
+ }
+}
View
23 samples/Translate/StreamEventArgs.cs
@@ -0,0 +1,23 @@
+// StreamEventArgs.cs
+//
+
+using System;
+using System.IO;
+
+namespace Translate {
+
+ public sealed class StreamEventArgs : EventArgs {
+
+ private Stream _stream;
+
+ public StreamEventArgs(Stream s) {
+ _stream = s;
+ }
+
+ public Stream Stream {
+ get {
+ return _stream;
+ }
+ }
+ }
+}
View
119 samples/Translate/Translate.csproj
@@ -0,0 +1,119 @@
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{CDDC7D32-B9D3-4828-B145-933780C87089}</ProjectGuid>
+ <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Translate</RootNamespace>
+ <AssemblyName>Translate</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <SilverlightApplication>true</SilverlightApplication>
+ <SupportedCultures>
+ </SupportedCultures>
+ <XapOutputs>true</XapOutputs>
+ <GenerateSilverlightManifest>true</GenerateSilverlightManifest>
+ <XapFilename>Translate.xap</XapFilename>
+ <SilverlightManifestTemplate>Properties\AppManifest.xml</SilverlightManifestTemplate>
+ <SilverlightAppEntry>Translate.TranslateApplication</SilverlightAppEntry>
+ <TestPageFileName>TestPage.html</TestPageFileName>
+ <CreateTestPage>true</CreateTestPage>
+ <ValidateXaml>true</ValidateXaml>
+ <EnableOutOfBrowser>false</EnableOutOfBrowser>
+ <OutOfBrowserSettingsFile>Properties\OutOfBrowserSettings.xml</OutOfBrowserSettingsFile>
+ <UsePlatformExtensions>false</UsePlatformExtensions>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ <LinkedServerProject>
+ </LinkedServerProject>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="SilverlightFX, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\binaries\Debug\Silverlight\SilverlightFX.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Windows" />
+ <Reference Include="mscorlib" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Windows.Browser" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Services\Audio\RiffParser.cs" />
+ <Compile Include="Services\Audio\WaveFormatEx.cs" />
+ <Compile Include="Services\Audio\WaveMediaStreamSource.cs" />
+ <Compile Include="Services\Audio\WavParser.cs" />
+ <Compile Include="Services\Language.cs" />
+ <Compile Include="StreamEventArgs.cs" />
+ <Compile Include="Services\Translator.cs" />
+ <Compile Include="TranslateApplication.xaml.cs">
+ <DependentUpon>TranslateApplication.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="TranslateWindow.xaml.cs">
+ <DependentUpon>TranslateWindow.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="TranslateWindowModel.cs" />
+ <Compile Include="PlayWaveAudio.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ApplicationDefinition Include="TranslateApplication.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:MarkupCompilePass1</Generator>
+ </ApplicationDefinition>
+ <Content Include="Assets\Styles.xaml">
+ <SubType>Designer</SubType>
+ </Content>
+ <Page Include="TranslateWindow.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:MarkupCompilePass1</Generator>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Properties\AppManifest.xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="Assets\Background.jpg" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\v3.0\Microsoft.Silverlight.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ProjectExtensions>
+ <VisualStudio>
+ <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
+ <SilverlightProjectProperties />
+ </FlavorProperties>
+ </VisualStudio>
+ </ProjectExtensions>
+</Project>
View
19 samples/Translate/TranslateApplication.xaml
@@ -0,0 +1,19 @@
+<Application
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:fxapp="clr-namespace:SilverlightFX.Applications;assembly=SilverlightFX"
+ x:Class="Translate.TranslateApplication">
+
+ <Application.Resources>
+ <ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
+ <ResourceDictionary Source="/Assets/Styles.xaml" />
+ </ResourceDictionary.MergedDictionaries>
+ </ResourceDictionary>
+ </Application.Resources>
+
+ <Application.ApplicationLifetimeObjects>
+ <fxapp:ApplicationContext x:Name="appContext" MainViewName="TranslateWindow" />
+ </Application.ApplicationLifetimeObjects>
+
+</Application>
View
15 samples/Translate/TranslateApplication.xaml.cs
@@ -0,0 +1,15 @@
+// TranslateApplication.xaml.cs
+//
+
+using System;
+using System.Windows;
+
+namespace Translate {
+
+ public partial class TranslateApplication : Application {
+
+ public TranslateApplication() {
+ InitializeComponent();
+ }
+ }
+}
View
57 samples/Translate/TranslateWindow.xaml
@@ -0,0 +1,57 @@
+<fxui:View
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:fxui="clr-namespace:SilverlightFX.UserInterface;assembly=SilverlightFX"
+ xmlns:local="clr-namespace:Translate"
+ x:Class="Translate.TranslateWindow"
+ mc:Ignorable="d"
+ d:DesignWidth="800" d:DesignHeight="600"
+ TextOptions.TextHintingMode="Animated">
+
+ <fxui:View.Resources>
+ <fxui:Command x:Key="translateCommand" Method="Translate" />
+ <fxui:Command x:Key="speakCommand" Method="Speak" />
+ </fxui:View.Resources>
+
+ <Grid>
+ <Image Source="/Assets/Background.jpg" Stretch="UniformToFill" />
+
+ <fxui:VStackPanel Margin="10" ChildAlignment="Center" ChildSpacing="4">
+ <fxui:HStackPanel HorizontalAlignment="Center" ChildAlignment="Center" ChildSpacing="10">
+ <ContentControl Style="{StaticResource logo}" />
+ <TextBlock Style="{StaticResource titleText}" Text="Microsoft Translator" />
+ </fxui:HStackPanel>
+
+ <TextBlock Style="{StaticResource labelText}"
+ Text="Enter some text to translate:" />
+ <TextBox Style="{StaticResource inputText}"
+ AcceptsReturn="True" Width="400" Height="100"
+ HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"
+ Text="{Binding Text, Mode=TwoWay}" />
+
+ <TextBlock Style="{StaticResource labelText}"
+ Text="Select a language:" />
+ <ComboBox Width="100" ItemsSource="{Binding Languages}" DisplayMemberPath="Name"
+ fxui:Commands.Selection="{StaticResource translateCommand}" />
+
+ <Border Style="{StaticResource displayArea}" Margin="0,10,0,0">
+ <TextBlock Style="{StaticResource labelText}" Width="400"
+ Text="{Binding TranslatedText}" />
+ </Border>
+
+ <Button Width="100" Height="23"
+ fxui:Commands.Click="{StaticResource speakCommand}"
+ Content="Say It!" />
+ </fxui:VStackPanel>
+
+ <MediaElement x:Name="mediaPlayer" IsMuted="False" AutoPlay="True">
+ <fxui:Interaction.Triggers>
+ <fxui:ModelEventTrigger EventName="PlayStream">
+ <local:PlayWaveAudio />
+ </fxui:ModelEventTrigger>
+ </fxui:Interaction.Triggers>
+ </MediaElement>
+ </Grid>
+</fxui:View>
View
16 samples/Translate/TranslateWindow.xaml.cs
@@ -0,0 +1,16 @@
+// TranslateWindow.xaml.cs
+//
+
+using System;
+using System.Windows;
+using SilverlightFX.UserInterface;
+
+namespace Translate {
+
+ public partial class TranslateWindow : View {
+
+ public TranslateWindow() {
+ InitializeComponent();
+ }
+ }
+}
View
90 samples/Translate/TranslateWindowModel.cs
@@ -0,0 +1,90 @@
+// TranslateWindowModel.cs
+//
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.IO;
+using Translate.Services;
+
+namespace Translate {
+
+ public class TranslateWindowModel : ViewModel {
+
+ private ObservableCollection<Language> _languages;
+
+ private string _text;
+ private string _translatedText;
+ private Language _translatedLanguage;
+
+ public TranslateWindowModel() {
+ _languages = new ObservableCollection<Language>() {
+ Language.German,
+ Language.French,
+ Language.Italian,
+ Language.Portugese,
+ Language.Spanish,
+ Language.English
+ };
+ }
+
+ public bool CanSpeak {
+ get {
+ return (String.IsNullOrEmpty(_translatedText) == false);
+ }
+ }
+
+ public IEnumerable<Language> Languages {
+ get {
+ return _languages;
+ }
+ }
+
+ public string Text {
+ get {
+ return _text;
+ }
+ set {
+ _text = value;
+ RaisePropertyChanged("Text");
+
+ TranslatedText = String.Empty;
+ }
+ }
+
+ public string TranslatedText {
+ get {
+ return _translatedText;
+ }
+ private set {
+ _translatedText = value;
+ RaisePropertyChanged("TranslatedText", "CanSpeak");
+ }
+ }
+
+ public event EventHandler<StreamEventArgs> PlayStream;
+
+ public void Speak() {
+ Translator translator = new Translator();
+ translator.GetAudioStream(_translatedText, _translatedLanguage.Code, delegate(Stream s) {
+ if (PlayStream != null) {
+ PlayStream(this, new StreamEventArgs(s));
+ }
+ });
+ }
+
+ public void Translate(Language language) {
+ if (String.IsNullOrEmpty(Text)) {
+ return;
+ }
+
+ _translatedLanguage = language;
+
+ Translator translator = new Translator();
+ translator.Translate(_text, _translatedLanguage.Code, delegate(string translatedText) {
+ TranslatedText = translatedText;
+ });
+ }
+ }
+}
View
4 samples/Web/Web.csproj
@@ -11,7 +11,7 @@
<RootNamespace>Web</RootNamespace>
<AssemblyName>Web</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
- <SilverlightApplicationList>{AC2DE467-846C-4621-AFEC-FF35DA1F8062}|..\EffectsSample\EffectsSample.csproj|Effects|False,{E333259B-1F2E-473E-90D4-7306D3E283B4}|..\EffectControl\EffectControl.csproj|Effects|False,{750026A3-3EA6-4D5F-B6DB-EBECDD3A8D3A}|..\TaskList\TaskList.csproj|TaskList|False,{783F6A15-E472-41A9-903C-105DC10F9BF0}|..\ThemeSample\ThemeSample.csproj|Themes|False,{39685CDF-0CB4-424F-BD0A-100AA220CB79}|..\Experiments\Experiments.csproj|Experiments|False,{A9A30F66-5957-4467-B206-3AC96714EAB8}|..\WeatherWidget\WeatherWidget.csproj|Weather|False,{3C606440-9DF0-4A72-A08D-23B3F20F67C4}|..\FlickrTiles\FlickrTiles.csproj|Flickr|False,{6F2D06F0-B548-4D89-8628-A7EB3BE4A8BE}|..\AmazonSearch\AmazonSearch.csproj|Amazon|False,{A8C08DAF-477C-4CEB-9AA8-21C412A06452}|..\AmazonStore\AmazonStore.csproj|Amazon|False,{750026A4-3EA6-4D5F-B6DB-EBECDD3A8D3A}|..\News\News.csproj|News|False,{DB259CE6-96A8-4F59-A0D5-A3F6815F4732}|..\TwitFaves\TwitFaves.csproj|TwitFaves|False</SilverlightApplicationList>
+ <SilverlightApplicationList>{AC2DE467-846C-4621-AFEC-FF35DA1F8062}|..\EffectsSample\EffectsSample.csproj|Effects|False,{E333259B-1F2E-473E-90D4-7306D3E283B4}|..\EffectControl\EffectControl.csproj|Effects|False,{750026A3-3EA6-4D5F-B6DB-EBECDD3A8D3A}|..\TaskList\TaskList.csproj|TaskList|False,{783F6A15-E472-41A9-903C-105DC10F9BF0}|..\ThemeSample\ThemeSample.csproj|Themes|False,{39685CDF-0CB4-424F-BD0A-100AA220CB79}|..\Experiments\Experiments.csproj|Experiments|False,{A9A30F66-5957-4467-B206-3AC96714EAB8}|..\WeatherWidget\WeatherWidget.csproj|Weather|False,{3C606440-9DF0-4A72-A08D-23B3F20F67C4}|..\FlickrTiles\FlickrTiles.csproj|Flickr|False,{6F2D06F0-B548-4D89-8628-A7EB3BE4A8BE}|..\AmazonSearch\AmazonSearch.csproj|Amazon|False,{A8C08DAF-477C-4CEB-9AA8-21C412A06452}|..\AmazonStore\AmazonStore.csproj|Amazon|False,{750026A4-3EA6-4D5F-B6DB-EBECDD3A8D3A}|..\News\News.csproj|News|False,{DB259CE6-96A8-4F59-A0D5-A3F6815F4732}|..\TwitFaves\TwitFaves.csproj|TwitFaves|False,{CDDC7D32-B9D3-4828-B145-933780C87089}|..\Translate\Translate.csproj|Translate|False</SilverlightApplicationList>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -97,6 +97,8 @@
<Content Include="News\NewsWidget.aspx" />
<Content Include="News\NewsWidget.xap" />
<Content Include="TaskList\TaskList.xap" />
+ <Content Include="Translate\Translate.aspx" />
+ <Content Include="Translate\Translate.xap" />
<Content Include="TwitFaves\TwitFaves.aspx" />
<Content Include="TwitFaves\TwitFaves.xap" />
<Content Include="Weather\Images\0.png" />
View
1 samples/Web/web.config
@@ -20,6 +20,7 @@
<add key="amazonSecretKey" value="[Your Amazon Secret Key]" />
<add key="timesNewswireApiKey" value="[Your Times Newswire API Key]" />
<add key="timesSearchApiKey" value="[Your Times Search API Key]" />
+ <add key="msTranslationApiKey" value="[Your Bing/Translation API App ID]" />
</appSettings>
<system.web>
<compilation debug="true">

0 comments on commit 0954426

Please sign in to comment.