Building an FM Radio with RDS Support

Introduction

This article explains how to use the open source USB FM library (written by me) and Windows Presentation Foundation to build a simple yet fully functional radio player with RDS and TMC support.

Background

The USB FM library provides managed interfaces, developed with C# to USB FM receivers that support RDS. WPF (Windows Presentation Foundation) provides an easy-to-use framework to build rich user interfaces with zero time investment. “Blending” those together will bring you an ability to build fully functional applications without a heavy time investment.

Step 1: Building Wireframes

To build a WPF application, you should first build a wireframe. WPF provides you with a rich choice of layout controls. In your case, you’ll use a Grid to mark up areas in the main (and only) application window.


<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=”*”/>
<RowDefinition Height=”35px”/>
<RowDefinition Height=”Auto”/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”Auto”/>
<ColumnDefinition Width=”*”/>
<ColumnDefinition Width=”Auto”/>
</Grid.ColumnDefinitions>
</Grid>

As you can see, you have three rows and three columns. Now, you can start putting your controls into it.

In any radio receiver, you have jogs to control volume level and tune to stations. There is a ready-made jog control, prepared by the Microsoft Expression Blend team, so you’ll use it “as-is.”

To do this, you have to reference the control library and define a namespace of the control within the XAML file of the application body.

xmlns_c="clr-namespace:RotaryControl;assembly=RotaryControl"
...
   <c:RotaryControl Name="Volume" RotationIsConstrained="True"
                    ClockwiseMostAngle="340" Angle="340"/>
   <c:RotaryControl Name="Tune" Grid.Column="2"/>

Also, you’ll add two labels and a list box of preset stations. These will be bound later to the FM device library.

<TextBlock Text="Volume" Grid.Row="1"/>
<TextBlock Text="Tune" Grid.Row="1" Grid.Column="2"/>

<ListBox Name="Presets"
         ItemTemplate="{StaticResource PresetTemplate}"
         Grid.ColumnSpan="3"
         Grid.Row="2"
         Background="Transparent"
         HorizontalAlignment="Center" >
   <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
         <DockPanel Margin="0" IsItemsHost="True"/>
      </ItemsPanelTemplate>
   </ListBox.ItemsPanel>
</ListBox>

The only thing that remains in the XAML markup is to set the display for frequency and program text indicators, mono/stereo icon, and signal strength emitter. To set all those, you’ll create another grid and put everything inside it.

<Grid Grid.Column="1">
   <Grid.RowDefinitions>
      <RowDefinition Height="12px"/>
      <RowDefinition Height="*"/>
      <RowDefinition Height="20px"/>
      <RowDefinition Height="20px"/>
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
      <ColumnDefinition Width=".2*"/>
      <ColumnDefinition Width="*"/>
   </Grid.ColumnDefinitions>
   <TextBlock Name="Freq"
              Grid.Column="1"
              Grid.Row="0"
              Grid.RowSpan="2"
              Style="{StaticResource LargeTextStyle}"/>
   <TextBlock Name="PS" Grid.Column="1" Grid.Row="2"/>
   <TextBlock Name="PTY"
              Grid.Column="1"
              Grid.Row="0"
              Style="{StaticResource PTYTextStyle}"/>
   <Path Name="MonoStereo"
         Stroke="White"
         Fill="White"
         Stretch="Fill"
         Grid.Column="1"
         Grid.Row="0"
         Width="12"
         Height="12"
         HorizontalAlignment="Left"/>
   <Rectangle Grid.RowSpan="4"
              Fill="{StaticResource SignalBrush}"
              Margin="10"/>
   <Rectangle Grid.RowSpan="4"
              Fill="Black"
              Margin="9"
              RenderTransformOrigin="0.5,0">
      <Rectangle.RenderTransform>
         <ScaleTransform x_Name="SignalTransform"
                         ScaleX="1"/>
      </Rectangle.RenderTransform>
   </Rectangle>
   <StackPanel Grid.Column="1"
               Grid.Row="4"
               HorizontalAlignment="Right"
               Orientation="Horizontal">
      <TextBlock Style="{StaticResource IndiStyle}"
                 Text="MS" Name="MS"/>
      <TextBlock Style="{StaticResource IndiStyle}"
                 Text="TA" Name="TA"/>
      <TextBlock Style="{StaticResource IndiStyle}"
                 Text="TP" Name="TP"/>
   </StackPanel>
</Grid>

You are finished wireframing your application. Now, it’s time to make it look better.

More by Author

Must Read