Chapter 30. Cowbell

image

image

Cowbell is a simple musical instrument app. With it, you can tap the screen in any rhythm, and the app makes a cowbell noise with each tap. You can even play along with songs from your music library by switching to the Music + Videos hub, starting a song or playlist, and then switching back to Cowbell. The important aspect of Cowbell is that its sole purpose is to play sound effects.

Of all the musical instruments out there, why choose a cowbell? Many people find the idea of playing a cowbell entertaining thanks to a Saturday Night Live skit in 2000 with Will Ferrell and Christopher Walken. In it, Christopher Walken repeatedly asks for “more cowbell” while Will Ferrell plays it to Blue Öyster Cult’s “(Don’t Fear) The Reaper.” With this song in your music library and this app on your phone, you can re-create the famous skit!

Playing Sound Effects

On Windows Phone, Silverlight has only one way to play audio and video: the MediaElement element. However, this element is too heavyweight for playing sound effects. When it plays, it stops any other media playback on the phone (e.g. music playing in the background from the Music + Videos hub). It can be okay to use for background music, and you must use it for playing inline video (the topic of Chapter 33, “Subservient Cat”), but do not use it for short or medium-length sounds. Instead, you should leverage XNA’s support for playing sound effects. As you saw in Chapter 2, “Flashlight,” Silverlight apps can use several APIs from XNA.

The relevant XNA class is called SoundEffect, and it lives in the Microsoft.Xna.Framework.Audio namespace. To use it, you must add a reference to the Microsoft.Xna.Framework assembly in your project. In this chapter, you’ll see how to load a sound effect from an audio file and how to play it. The SoundEffect class provides additional richness, but the use of extra features is saved for the next chapter.

The User Interface

Cowbell has a main page, an instructions page, and an about page. The latter two pages aren’t interesting and therefore aren’t shown in this chapter, but Listing 30.1 contains the XAML for the main page.

Listing 30.1 MainPage.xaml—The User Interface for Cowbell’s Main Page


<phone:PhoneApplicationPage
    x:Class="WindowsPhoneApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    SupportedOrientations="Portrait">

  <!-- The application bar, with one button and one menu item -->
  <phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar Opacity=".5">
      <shell:ApplicationBarIconButton Text="instructions"
                IconUri="/Shared/Images/appbar.instructions.png"
                Click="InstructionsButton_Click"/>
      <shell:ApplicationBar.MenuItems>
        <shell:ApplicationBarMenuItem Text="about" Click="AboutMenuItem_Click"/>
      </shell:ApplicationBar.MenuItems>
    </shell:ApplicationBar>
  </phone:PhoneApplicationPage.ApplicationBar>

  <!-- Just an image in a grid -->
  <Grid Background="Black" MouseLeftButtonDown="Grid_MouseLeftButtonDown">
    <Image Source="Images/cowbell.png" Stretch="None"/>
  </Grid>
</phone:PhoneApplicationPage>


This is a simple page with an application bar and a grid with a cowbell image that handles taps with its MouseLeftButtonDown handler. For the sake of the cowbell image that has white edges, the grid is given a hard-coded black background. Therefore, this page looks the same under both themes except for the half-opaque application bar, as seen in Figure 30.1.

Figure 30.1 The main page looks identical on both dark and light themes, except for the application bar.

image

The Code-Behind

Listing 30.2 contains the code-behind for the main page. This is where all the sound-effect logic resides.

Listing 30.2 MainPage.xaml.cs—The Code-Behind for Cowbell’s Main Page


using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Windows.Resources;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Xna.Framework.Audio; // For SoundEffect

namespace WindowsPhoneApp
{
  public partial class MainPage : PhoneApplicationPage
  {
    SoundEffect cowbell;

    public MainPage()
    {
      InitializeComponent();

      // Load the sound file
      StreamResourceInfo info = Application.GetResourceStream(
        new Uri("Audio/cowbell.wav", UriKind.Relative));

      // Create an XNA sound effect from the stream
      cowbell = SoundEffect.FromStream(info.Stream);

      // Subscribe to a per-frame callback
      CompositionTarget.Rendering += CompositionTarget_Rendering;

      // Required for XNA sound effects to work
      Microsoft.Xna.Framework.FrameworkDispatcher.Update();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
      base.OnNavigatedTo(e);

      // Don't let the screen auto-lock in the middle of a musical performance!
      PhoneApplicationService.Current.UserIdleDetectionMode =
        IdleDetectionMode.Disabled;
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
      base.OnNavigatedFrom(e);

      // Restore the ability for the screen to auto-lock when on other pages
      PhoneApplicationService.Current.UserIdleDetectionMode =
        IdleDetectionMode.Enabled;
    }

    void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
      // The screen was tapped, so play the sound
      cowbell.Play();
    }

    void CompositionTarget_Rendering(object sender, EventArgs e)
    {
      // Required for XNA sound effects to work.
      // Call this every frame.
      Microsoft.Xna.Framework.FrameworkDispatcher.Update();
    }

    // Application bar handlers

    void InstructionsButton_Click(object sender, EventArgs e)
    {
      this.NavigationService.Navigate(new Uri("/InstructionsPage.xaml",
        UriKind.Relative));
    }

    void AboutMenuItem_Click(object sender, EventArgs e)
    {
      this.NavigationService.Navigate(new Uri("/AboutPage.xaml",
        UriKind.Relative));
    }
  }
}

Notes:

→ In the constructor, the stream for this app’s .wav audio file is obtained with the static Application.GetResourceStream method. This method was first seen in Chapter 24, “Baby Name Eliminator.” The cowbell.wav file is included in the project with a Build Action of Content, enabling the simple relative URI to be used. The stream is then sent to the static SoundEffect.FromStream method, which constructs an appropriate SoundEffect instance and returns it.

→ The use of the CompositionTarget.Rendering event is required for sound effects to work properly. This is explained in the following warning sidebar.

→ The code in OnNavigatedTo and OnNavigatedFrom exists to ensure that the screen doesn’t auto-lock. If the cowbell player has a long break during a performance, it would be very annoying if the screen automatically locked. And tapping the screen to keep it active isn’t a good option, because that would make an unwanted cowbell noise!

→ The sound effect is played with a simple call to SoundEffect.Play in Grid_MouseLeftButtonDown. If Play is called before the sound effect finishes playing from a previous call, the sounds overlap.

The Finished Product

image

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.148.104.3