0

I'm making an app for my drum classes and to make it cross-platform I've chosen Urho.Sharp, because it has low level Sound API as well as rich graphics capabilities.

As a first step I'm making a metronome app and for that I'm working with BufferedSoundStream adding here audio and then needed silence, as described here: https://github.com/xamarin/urho-samples/blob/master/FeatureSamples/Core/29_SoundSynthesis/SoundSynthesis.cs

But the resulting sound is not a sound at all, like random bits got into buffered stream.

This is my code:

///
/// this code initialize sound subsystem
///
void CreateSound()
{
   // Sound source needs a node so that it is considered enabled
   node = new Node();
   SoundSource source = node.CreateComponent<SoundSource>();

   soundStream = new BufferedSoundStream();
   // Set format: 44100 Hz, sixteen bit, stereo
   soundStream.SetFormat(44100, true, true);

   // Start playback. We don't have data in the stream yet, but the 
   SoundSource will wait until there is data,
   // as the stream is by default in the "don't stop at end" mode
   source.Play(soundStream);
}

///
/// this code preload all sound resources
///
readonly Dictionary<PointSoundType, string> SoundsMapping = new Dictionary<PointSoundType, string>
{
    {PointSoundType.beat, "wav/beat.wav"},               
    {PointSoundType.click, "wav/click.wav"},
    {PointSoundType.click_accent, "wav/click_accent.wav"},
    {PointSoundType.crash, "wav/crash.wav"},
    {PointSoundType.foot_hh, "wav/foot_hh.wav"},
    {PointSoundType.hh, "wav/hh.wav"},
    {PointSoundType.open_hh, "wav/open_hh.wav"},
    {PointSoundType.ride, "wav/ride.wav"},
    {PointSoundType.snare, "wav/snare.wav"},
    {PointSoundType.tom_1, "wav/tom_1.wav"},
    {PointSoundType.tom_2, "wav/tom_2.wav"},
};

Dictionary<PointSoundType, Sound> SoundCache = new Dictionary<PointSoundType, Sound>();

private void LoadSoundResources()
{
    // preload all sounds
    foreach (var s in SoundsMapping)
    {
        SoundCache[s.Key] = ResourceCache.GetSound(s.Value);
        Debug.WriteLine("resource loaded: " + s.Value + ", length = " + SoundCache[s.Key].Length);
    }
}

///
/// this code fill up the stream with audio
///
private void UpdateSound()
{
   // Try to keep 1/10 seconds of sound in the buffer, to avoid both dropouts and unnecessary latency
   //float targetLength = 1.0f / 10.0f;

   // temporary increase buffer to 1s
   float targetLength = 1.0f;

   float requiredLength = targetLength - soundStream.BufferLength;
   if (requiredLength < 0.0f)
      return;

   uint numSamples = (uint)(soundStream.Frequency * requiredLength);

   // check if stream is still full
   if (numSamples == 0)
      return;

   var silencePause = new short[44100];

   // iterate and play all sounds 
   SoundCache.All(s =>
   {
      soundStream.AddData(s.Value.Handle, s.Value.DataSize);

      // add silencio
      soundStream.AddData(silencePause, 0, silencePause.Length);

      return true;
   });
}
Roman Nikitin
  • 113
  • 1
  • 1
  • 7

1 Answers1

0

Make sure your wav files are in the resource cache. Then don't play the BufferedSoundStream, but the Urho.Audio.Sound sound. This is just a different override of the same method Urho.Audio.SoundSource.Play(), but it works.

int PlaySound(string sSound)
{
    var cache = Application.Current.ResourceCache;
    Urho.Audio.Sound sound = cache.GetSound(sSound);
    if (sound != null)
    {
        Node soundNode = scene.CreateChild("Sound");
        Urho.Audio.SoundSource soundSource = soundNode.CreateComponent<Urho.Audio.SoundSource>();
        soundSource.Play(sound);
        soundSource.Gain = 0.99f;
        return 1;
    }
    return 0;
}

Since you're using urhosamples, you can start each drum sample from the override update something like this:

public float fRun = 0.0f;
public int iRet = 0;         // keep counting the played sounds
public override void OnUpdate(float timeStep)
{
    fRun = fRun + timeStep;
    int iMS = (int)(10f * fRun);  // tenth of seconds 
    if (iMS == 100) iRet = iRet + PlaySound("wav/hh.wav");
    if (iMS == 120) iRet = iRet + PlaySound("wav/hh.wav");
    if (iMS == 140) iRet = iRet + PlaySound("wav/hh.wav"); 
    if (iMS == 160) iRet = iRet + PlaySound("wav/open_hh.wav"); 
    if (iMS >= 160) fRun = 0.8f;
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Geert Jan
  • 408
  • 1
  • 6
  • 22