Sign in to follow this  

[SOLVED] Prevent clipping artifacts while performing fast repetitive audio playback

This topic is 4248 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Some games, usually within the arcade/FPS genre, often has to play a certain sound in a quick repetetive manner. One obvious example would be when the player fires an automatic weapon. Since the firing sound lasts longer than the time between two rounds, the sound has to be clipped in some way. I wonder in what way your audio managers handles this, to avoid clipping artifacts when "interupting" an already plaing sound? I have two solutions, which both seems a little awkward to implement: 1. Keep copies of the firing sound, and use many sound buffers for the same sound. This way no clipping with be needed, instead there will be two firing sounds playing at the same time. 2. Do some sort of real-time manipulation of the data at the point where the clipping occurs. I guess this would requre a slight delay in the playback, but I don't think it would be hearable. Any other suggestions on how to fix this? Thanks! [Edited by - Enselic on April 29, 2006 2:22:16 PM]

Share this post


Link to post
Share on other sites
Yeah, no 1 worked fine. And it wasn't very awkward.

Here's my solution in case anyone is interested.


// +---------------------------------------------------------------------------+
//
// Copyright © 2006 Martin Nordholts. All rights reserved.
// Website: http://www.chromecode.com
//
//
// File: AudioManager.cs
// Created: 2005-06-13
//
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// +---------------------------------------------------------------------------+

using Microsoft.DirectX.DirectSound;

using System;
using System.Windows.Forms;
using System.Collections.Generic;

namespace Chrocodile
{
/// <remarks>
/// This is the sound manager. This is implemented as a static class
/// since there isn't something that needs to be done continualy, i.e.
/// there there is no "task" to solve.
/// </remarks>
public static class AudioManager
{
/// <summary>
/// Initializes the sound manager.
/// </summary>
/// <param name="owner">Owner control.</param>
/// <param name="path">the path where the audio is located</param>
public static void Init(Control owner, string path)
{
device = new Device();
device.SetCooperativeLevel(owner, CooperativeLevel.Priority);

AudioManager.path = path;
}

/// <summary>
/// Loads a sound into the manager
/// </summary>
/// <param name="name">the name of the file (which is located in the path
/// specified at initialization</param>
public static void LoadSound(string name)
{
// If we don't set ControlEffects to false, the loader will throw an expception
// if we use too small .wav files.
BufferDescription bd = new BufferDescription();
bd.ControlEffects = false;

SecondaryBuffer originalBuffer = new SecondaryBuffer(path + "\\" + name, bd, device);

SecondaryBuffer[] buffers = new SecondaryBuffer[NumBufferCopies];
for (int i = 0; i < NumBufferCopies; i++) {
buffers[i] = originalBuffer.Clone(device);
}

soundDictionary.Add(name, buffers);
}

/// <summary>
/// Plays a sound
/// </summary>
/// <param name="name">the name of the soundfile</param>
public static void PlaySound(string name)
{
if (!soundOn) {
return;
}

SecondaryBuffer[] buffers;
soundDictionary.TryGetValue(name, out buffers);

foreach (SecondaryBuffer buffer in buffers) {
if (!buffer.Status.Playing) {
buffer.Play(0, BufferPlayFlags.Default);
break;
}
}
}

/// <summary>
/// Unloads a sound.
/// </summary>
/// <param name="name">Name of the sound file.</param>
public static void UnloadSound(string name)
{
SecondaryBuffer[] buffers;
soundDictionary.TryGetValue(name, out buffers);

foreach (SecondaryBuffer buffer in buffers) {
buffer.Dispose();
}

soundDictionary.Remove(name);
}

/// <summary>
/// Unloads all sounds.
/// </summary>
public static void Deinitialize()
{
soundDictionary.Clear();
}

/// <summary>
/// Sets sound on/off
/// </summary>
public static bool SoundOn
{
get { return soundOn; }
set { soundOn = value; }
}

/// <summary>
/// For each sound we load, we keep these many copies.
/// We do this so we can play the same sound at the same time.
/// </summary>
private const int NumBufferCopies = 10;

private static string path;

private static Dictionary<string, SecondaryBuffer[]> soundDictionary = new Dictionary<string, SecondaryBuffer[]>();

private static bool soundOn = true;

private static Device device;
}
}


Share this post


Link to post
Share on other sites

This topic is 4248 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this