views:

119

answers:

1

From an audio-file I want to be able to expose audio on a webpage, but between specific start and stop times.

Say I have a audio-file that is 45:30, for example, and I want to expose it for streaming and download between 7:25 and 8:30, but also between 6:20 and 9:27.

What do I need in term of special services, Silverlight-controls and maybe some sample-code for this.

Bonus-question: Is there already an online-service for this?

+1  A: 

Seb,

I assume that when you say "expose" that you mean offer audio play controls for those sub-clips.

Here is a suggested step-by-step for building a Silverlight app that plays an audio file between a start and an end point:

Step 1: Create a sample Silverlight application with Visual Studio (File / New Project / Silverlight Application

Step 2: In your newly create project, edit the MainPage.xaml, and place the following code inside the UserControl's Grid:

  <StackPanel>
   <MediaElement x:Name="x_MediaElement" AutoPlay="False" Stretch="Uniform" CacheMode="BitmapCache" 
     MediaOpened="OnMediaOpened" MarkerReached="OnMarkerReached" MediaEnded="OnMediaEnded" CurrentStateChanged="OnMediaCurrentStateChanged"
     Source="http://www.shinedraw.com/wordpress/wp-content/uploads/AudioPlayer/littlewaltz.mp3" />

   <StackPanel Orientation="Horizontal">
    <Button x:Name="x_Play" Click="OnPlayClick" Content="Play" Height="20" Width="40" />
    <Button x:Name="x_Pause" Click="OnPauseClick" Content="Pause" Height="20" Width="40" />
    <Button x:Name="x_Stop" Click="OnStopClick" Content="Stop" Height="20" Width="40" />
    <Slider x:Name="x_Timeline" HorizontalAlignment="Stretch" Width="200" Maximum="1" Value="0" ValueChanged="OnTimelineValueChanged"/>
    <TextBlock x:Name="x_CurrentTime" Height="20" Width="75" TextAlignment="Right" HorizontalAlignment="Right" VerticalAlignment="Center" />
    <TextBlock Text="/" Height="20" VerticalAlignment="Center" />
    <TextBlock x:Name="x_TotalTime" Height="20" Width="75" VerticalAlignment="Center" />

    <ToggleButton x:Name="x_Mute" Click="OnMuteClick" Content="Mute" Height="20" Width="40" IsChecked="false" />

    <Slider x:Name="x_VolumeSlider" HorizontalAlignment="Stretch" Width="50" Maximum="1" 
      Value="{Binding ElementName=x_MediaElement, Mode=TwoWay, Path=Volume, UpdateSourceTrigger=Default}"/>
   </StackPanel>
  </StackPanel>

Step 3: Edit the MainPage.cs, and replace the MainPage class with the following code:

 public partial class MainPage : UserControl
 {
  public MainPage()
  {
   InitializeComponent();
   CompositionTarget.Rendering += OnCompositionTargetRendering;
  }

  private void SetStart(TimeSpan timeStart)
  {
   x_MediaElement.Position = timeStart;
  }

  private void SetEnd(TimeSpan timeEnd)
  {
   if (x_MediaElement.Markers == null || x_MediaElement.Markers.Count == 0)
    x_MediaElement.Markers.Add(new TimelineMarker() { Time = timeEnd });
   else
    x_MediaElement.Markers[0].Time = timeEnd;
  }

  private bool _InTickEvent;

  private void OnPlayClick(object sender, RoutedEventArgs e)
  {
   SetStart(new TimeSpan(0,0,10));
   SetEnd(new TimeSpan(0,0,20));
   x_MediaElement.Play();
  }

  private void OnPauseClick(object sender, RoutedEventArgs e)
  {
   x_MediaElement.Pause();
  }

  private void OnStopClick(object sender, RoutedEventArgs e)
  {
   x_MediaElement.Stop();
  }

  private void OnMuteClick(object sender, RoutedEventArgs e)
  {
   x_MediaElement.IsMuted = (bool)x_Mute.IsChecked;
  }

  private void OnMediaOpened(object sender, RoutedEventArgs e)
  {
   x_TotalTime.Text = TimeSpanToString(x_MediaElement.NaturalDuration.TimeSpan);
  }

  private void OnMarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
  {
   x_MediaElement.Stop();
  }

  private void OnMediaEnded(object sender, RoutedEventArgs e)
  {
   x_MediaElement.Stop();
  }

  private void OnTimelineValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
  {
   if (_InTickEvent)
    return; // throw new Exception("Can't call Seek() now, you'll get an infinite loop");

   double percentComplete = x_Timeline.Value;
   TimeSpan duration = x_MediaElement.NaturalDuration.TimeSpan;
   int newPosition = (int)(duration.TotalSeconds * percentComplete);
   x_MediaElement.Position = new TimeSpan(0, 0, newPosition);
  }

  private void OnCompositionTargetRendering(object sender, EventArgs e)
  {
   _InTickEvent = true;

   TimeSpan duration = x_MediaElement.NaturalDuration.TimeSpan;
   if (duration.TotalSeconds != 0)
   {
    double percentComplete = (x_MediaElement.Position.TotalSeconds / duration.TotalSeconds);
    x_Timeline.Value = percentComplete;
    string text = TimeSpanToString(x_MediaElement.Position);
    if (x_CurrentTime.Text != text)
     x_CurrentTime.Text = text;
   }

   _InTickEvent = false;
  }

  private string TimeSpanToString(TimeSpan time)
  {
   return string.Format("{0:00}:{1:00}", (time.Hours * 60) + time.Minutes, time.Seconds);
  }

  private void OnMediaCurrentStateChanged(object sender, RoutedEventArgs e)
  {
   switch (x_MediaElement.CurrentState)
   {
    case MediaElementState.Buffering:
     break;
    case MediaElementState.Opening:
     break;
    case MediaElementState.Paused:
     break;
    case MediaElementState.Playing:
     break;
    case MediaElementState.Stopped:
     break;
   }
  }
 }

Step 4: Build and Run!

Jim McCurdy