Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Skype Voice Changer

In this article I demonstrate how you can create your own audio effects in .NET to manipulate digital audio at the sample level. These effects are used to process MP3 files while they are being played back, and to process the real-time microphone input allowing you to change your voice during a Skype conversation.

Mark Heath, blog

Source Code: Download

Difficulty: Intermediate
Time Required: 8 hours
Cost: Free
Software Needed: Visual Basic or Visual C# Express 2008
Libraries: NAudio, Skype4COM, MEF

image

Audio and the .NET Framework

Playing back audio in a .NET application is not quite as easy as you might hope it would be. The .NET 2.0 Framework introduced the SoundPlayer component, which allows you to play back an existing WAV file. While this may be fine for many scenarios, as soon as you want to do things even slightly more advanced, such as changing the volume, or playing back from a different file-format, or pausing and repositioning, you must resort to writing P/Invoke wrappers for various Windows APIs.

Back in 2002, as I was getting started learning .NET, I create some audio-related classes of my own to compensate for the lack of audio support in the .NET Framework. I focused initially on reading and writing WAV and MIDI files, as well as playing back audio in a way that allowed real-time mixing and manipulation of the audio at a sample level. As time went by, I made this growing collection of audio classes available as an open source project, called NAudio, now hosted at CodePlex.

Audio Playback in NAudio

NAudio works by constructing an audio playback graph. Audio comes in “streams” which can be connected together and modified before eventually they go to a renderer. This might be your soundcard if you are listening to the audio, or it might be to a file on the hard disk.

In NAudio, all streams derive from WaveStream. NAudio comes with a collection of useful WaveStream derived classes such as WaveFileReader to read from WAV files or WaveStreamMixer to sum together multiple audio streams.

Audio mixing and effects are almost always performed with floating point numbers (32 bit is most common), so one of the first steps after reading audio out of a WAV file is to convert it from 16 bit to 32 bit. NAudio includes the Wave16To32ConversionStream class to do this. If the audio wasn't in PCM in the first place, for example it is MP3, then we make use of a combination of the Mp3FileReaderStream, WaveFormatConversionStream and BlockAlignmentReductionStream to read the audio out and get it into just the format we want. Here's an example showing how to create a WaveStream ready for playback.

WaveStream outStream;
if (fileName.EndsWith(".mp3"))
{
   outStream = new Mp3FileReader(fileName);
}
else if(fileName.EndsWith(".wav"))
{
   outStream = new WaveFileReader(fileName);
}
else
{
   throw new InvalidOperationException("Can't open this type of file");
}                
if (outStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
{
   outStream = WaveFormatConversionStream.CreatePcmStream(outStream);
   outStream = new BlockAlignReductionStream(outStream); // reduces choppiness
}

If we simply want to play back the audio without any extra processing, we would use one of the audio output classes provided by NAudio to create an object that implements IWavePlayer. The options are WaveOut, DirectSoundOut, AsioOut and WasapiOut, each representing a different technology for audio playback in Windows. We will use WaveOut, which is the most universally supported. Here we are opening the default output device with a latency of 300ms, and instructing it to use windowed callbacks.

IWavePlayer player = new WaveOut(0, 300, true);
player.Init(outStream);
player.Play();

WaveOut will now repeatedly call the Read method of the output stream to get the next batch of audio samples to play. All we need to do now is to insert our audio effects into the playback chain.

An Audio Effects Framework

To allow us to process sample level audio more simply, I have create a new WaveStream derived class called EffectStream. EffectStream will simply pass each audio sample to one or more audio effects before returning the modified audio in its Read method. The reason I have chosen to host all the effects in a single EffectSteam rather than creating one WaveStream derived class is that I want to avoid the performance penalty of converting between arrays of bytes and arrays of floating point numbers at every step. Some types of effect, particularly those involving Fourier transforms can be processor intensive, so anything we can do to speed up performance will help.

As well as the EffectStream class, we need a base Effect class, from which all of our effects can derive. Here's a simplified version of the base Effect class (minus a whole load of helper mathematical functions):

public abstract class Effect
{
    private List<Slider> sliders;
    public float SampleRate { get; set; }
    public float Tempo { get; set; }
    public bool Enabled { get; set; }

    public Effect()
    {
        sliders = new List<Slider>();
        Enabled = true;
        Tempo = 120;
        SampleRate = 44100;
    }

    public IList<Slider> Sliders { get { return sliders; } }

    public Slider AddSlider(float defaultValue, float minimum, 
            float maximum, float increment, string description)
    {
        Slider slider = new Slider(defaultValue, minimum, 
            maximum, increment, description);
        sliders.Add(slider);
        return slider;
    }

    /// <summary>
    /// Should be called on effect load, 
    /// sample rate changes, and start of playback
    /// </summary>
    public virtual void Init()
    {}

    /// <summary>
    /// will be called when a slider value has been changed
    /// </summary>
    public abstract void Slider();

    /// <summary>
    /// called before each block is processed
    /// </summary>
    public virtual void Block()
    { }

    /// <summary>
    /// called for each sample
    /// </summary>
    public abstract void Sample(ref float spl0, ref float spl1);
}

The bulk of the work of the effect should be done in the overridden Sample method. The spl0 and spl1 parameters contain the current sample values to be modified for the left and right channels respectively. For example, to lower the volume we could halve the amplitude of every sample with the following code:

public override void Sample(ref float spl0, ref float spl1)
{
    spl0 *= 0.5f;
    spl1 *= 0.5f;
}

The Effect class contains Tempo and SampleRate values which are useful for certain types of effect. It also contains a concept of ‘Sliders' for each effect. These are the effect parameters, which allow real-time modification of the effect. So if we wanted to control the volume using a slider, we could write the following code (although bear in mind that normally volume sliders should be logarithmic not linear – see the Volume effect in the sample code for an example of how to do this):

public override void Sample(ref float spl0, ref float spl1)
{
    spl0 *= slider1;
    spl1 *= slider1;
}

To simplify the task of adding, removing and re-ordering effects, I created an EffectChain class, which is a simple wrapper around a List<Effect>. The EffectStream class has an EffectChain that contains all the effects it needs to run. Here is the code for the EffectStream:

public class EffectStream : WaveStream
{
    private EffectChain effects;
    public WaveStream source;
    private object effectLock = new object();
    private object sourceLock = new object();

    public EffectStream(EffectChain effects, WaveStream sourceStream)
    {
        this.effects = effects;
        this.source = sourceStream;
        foreach (Effect effect in effects)
        {
            InitialiseEffect(effect);
        }

    }

    public EffectStream(WaveStream sourceStream)
        : this(new EffectChain(), sourceStream)
    {        
    }

    public EffectStream(Effect effect, WaveStream sourceStream)
        : this(sourceStream)
    {
        AddEffect(effect);
    }

    public override WaveFormat WaveFormat
    {
        get { return source.WaveFormat; }
    }

    public override long Length
    {
        get { return source.Length; }
    }

    public override long Position
    {
        get { return source.Position; }
        set { lock (sourceLock) { source.Position = value; } }
    }        

    public override int Read(byte[] buffer, int offset, int count)
    {
        int read;
        lock(sourceLock)
        {
            read = source.Read(buffer, offset, count);
        }
        if (WaveFormat.BitsPerSample == 16)
        {
            lock (effectLock)
            {
                Process16Bit(buffer, offset, read);
            }
        }
        return read;
    }

    private void Process16Bit(byte[] buffer, int offset, int count)
    {
        foreach (Effect effect in effects)
        {
            if (effect.Enabled)
            {
                effect.Block();
            }
        }

        for(int sample = 0; sample < count/2; sample++)
        {
            // get the sample(s)
            int x = offset + sample * 2;
            short sample16Left = BitConverter.ToInt16(buffer, x);
            short sample16Right = sample16Left;
            if(WaveFormat.Channels == 2)
            {                    
                sample16Right = BitConverter.ToInt16(buffer, x + 2);
                sample++;
            }
           
            // run these samples through the effects
            float sample64Left = sample16Left / 32768.0f;
            float sample64Right = sample16Right / 32768.0f;
            foreach (Effect effect in effects)
            {
                if (effect.Enabled)
                {
                    effect.Sample(ref sample64Left, ref sample64Right);
                }
            }

            sample16Left = (short)(sample64Left * 32768.0f);
            sample16Right = (short)(sample64Right * 32768.0f);

            // put them back
            buffer[x] = (byte)(sample16Left & 0xFF);
            buffer[x + 1] = (byte)((sample16Left >> 8) & 0xFF); 

            if(WaveFormat.Channels == 2)    
            {
                buffer[x + 2] = (byte)(sample16Right & 0xFF);
                buffer[x + 3] = (byte)((sample16Right >> 8) & 0xFF);
            }
        }
    }


    public bool MoveUp(Effect effect)
    {
        lock (effectLock)
        {
            return effects.MoveUp(effect);
        }
    }

    public bool MoveDown(Effect effect)
    {
        lock (effectLock)
        {
            return effects.MoveDown(effect);
        }
    }

    public void AddEffect(Effect effect)
    {
        InitialiseEffect(effect);
        lock (effectLock)
        {
            this.effects.Add(effect);
        }
    }

    private void InitialiseEffect(Effect effect)
    {
        effect.SampleRate = WaveFormat.SampleRate;
        effect.Init();
        effect.Slider();
    }

    public bool RemoveEffect(Effect effect)
    {
        lock (effectLock)
        {
            return this.effects.Remove(effect);
        }
    }
}

When the Read method on EffectStream is called, we first read the requested number of bytes from our source WaveStream. This might be from a WAV or MP3 file, or from a microphone. Then, we convert it from 16 bit to 32 bit floating point audio. 16 bit audio is stored as integers going from -32,768 to 32,767, and 32 bit audio uses the range -1.0 to 1.0 to represent this range. This means we have plenty of headroom to mix together multiple signals without distorting. It is important though to remember that no samples should be greater than 1.0 before converting back to 16 bit.

Porting Effects to .NET

Now we have a basic effect framework, it is time to create some real effects to use. There are many sources of algorithms for digital signal processing (DSP) (try musicdsp.org for a good starting point), but I have chosen to base my effects model on that provided by the REAPER digital audio workstation (DAW). This impressive application, masterminded by legendary software developer Justin Frankel, includes a text-based effects framework. These effects, known as JS effects, allow the use of a C-like syntax to quickly write your own effects. I have modelled my Effect class on the JS syntax, allowing me to quickly port effects across.

public class Tremolo : Effect
{
    public Tremolo()
    {
        AddSlider(4,0,100,1,"frequency (Hz)");
        AddSlider(-6,-60,0,1,"amount (dB)");
        AddSlider(0, 0, 1, 0.1f, "stereo separation (0..1)");
    }

    float adv, sep, amount, sc, pos;

    public override void Slider()
    {
        adv=PI*2*slider1/SampleRate;
        sep=slider3*PI;
        amount=pow(2,slider2/6);
        sc=0.5f*amount; amount=1-amount;
    }

    public override void Sample(ref float spl0, ref float spl1)
    {
        spl0 = spl0 * ((cos(pos) + 1) * sc + amount);
        spl1 = spl1 * ((cos(pos + sep) + 1) * sc + amount);
        pos += adv;
    }
}

Some members in the Effect base class such as cos and slider1 allow me to keep the ported syntax as similar to the original JS script as possible.

REAPER ships with well over 100 of these JS Effects, so I chose about 15 of them and ported them to .NET. They are available in the download that accompanies this article. With some of them, for example pitch shifting effects, you will immediately notice the effect on the sound, while others, such as compressors, require some knowledge of how to adjust the parameters to get good results.

The Test Harness

Obviously we need a way to pass audio through our effects, so our next task is to create a test harness that will allow us to load in audio files and listen to them with the effects applied. For this purpose I created a simple Windows Forms application that allows you to select a WAV or MP3 file to play back. After being converted into PCM using various classes from the NAudio library, the resulting WaveStream is passed through an EffectStream before being passed to the soundcard for playback. The use of an EffectChain allows us to modify the effects loaded, and their order during playback.

To make the loading of effects simpler, I used the Managed Extensibility Framework (MEF), to [DF1] make each effect a “plugin” to the test harness. Each effect is decorated with an Export attribute to indicate that it is a plugin:

[Export(typeof(Effect))]
public class SuperPitch : Effect

Then I can request that MEF auto-populates a property with all the exported effects it can find:

[Import]
public ICollection<Effect> Effects { get; set; }

When the user selects an effect from the list of available effects, we create a new instance of it. This is because you might want to put the same effect into the effect chain more than once:

EffectSelectorForm effectSelectorForm = new EffectSelectorForm(Effects);
if (effectSelectorForm.ShowDialog(this) == DialogResult.OK)
{
    // create a new instance of the selected effect 
    // as we may want multiple copies of one effect
    Effect effect = (Effect)Activator.CreateInstance(
       effectSelectorForm.SelectedEffect.GetType());
    audioGraph.AddEffect(effect);
    checkedListBox1.Items.Add(effect, true);
}

To allow real-time modification of the effect parameters, I created two user controls. The first, EffectSliderPanel allows you to hook up a Windows Forms TrackBar to one of our effect's sliders and manages the minimum, maximum and granularity settings. The second user control, EffectPanel takes an Effect and creates one EffectSliderPanel for each slider in that effect. It also is responsible for calling the Slider method on the Effect whenever the user moves one of the sliders. Here's an example of what it looks like:

image

Now we are able to test our effects by listening to WAV files and playing them with real-time control over their parameters.

Intercepting Skype Audio

There are many interesting uses for audio effects, but it was suggested to me that I create a “voice changer” for Skype as the example program for this article. At first I didn't think that this would be possible, as you would need access to the audio samples from the microphone before Skype transmitted them over the network.

However, it turns out that Skype has a full featured SDK to allow all kinds of third-party add-ons and enhancements. The Skype API can be used in .NET via a COM object, called Skype4Com. Skype plugins are not loaded directly by the Skype application but attach to it via network sockets. The Skype4Com COM object hides much of this complexity from the user.

Having added Skype4Com as a reference to our application, we then need to connect to Skype. This is achieved by using the following code:

const int Protocol = 8;
skype = new Skype();
_ISkypeEvents_Event events = (_ISkypeEvents_Event)skype;
events.AttachmentStatus += OnSkypeAttachmentStatus;            
skype.CallStatus += OnSkypeCallStatus;
skype.Attach(Protocol, false);

In the CallStatus event handler, we tell Skype that we wish to ‘capture' the microphone. This will cause it to send us the raw audio data from the microphone via a TCP socket. Then we tell it that we will send the audio to be transmitted using another TCP socket.

void OnSkypeCallStatus(Call call, TCallStatus status)
{
    log.Info("SkypeCallStatus: {0}", status);
    if (status == TCallStatus.clsInProgress)
    {
        this.call = call;                  
        call.set_CaptureMicDevice(
        TCallIoDeviceType.callIoDeviceTypePort, MicPort.ToString());
        call.set_InputDevice(
        TCallIoDeviceType.callIoDeviceTypeSoundcard, "");
        call.set_InputDevice(
        TCallIoDeviceType.callIoDeviceTypePort, OutPort.ToString());
    }
    else if (status == TCallStatus.clsFinished)
    {
        call = null;
        packetSize = 0;
    }
}

I found an example Delphi application on the Skype developer website which shows how to intercept the microphone signal to boost the signal level. I used this sample as the starting point for creating my own application to intercept audio samples in Skype. The Delphi application made use of an object called TIdTCPServer, which is a multi-threaded socket server. I created a very simple .NET implementation of this class (without the multi-threading as we will only have one connection at a time):

class TcpServer : IDisposable
{
    TcpListener listener;
    public event EventHandler<ConnectedEventArgs> Connect;
    public event EventHandler Disconnect;
    public event EventHandler<DataReceivedEventArgs> DataReceived;
    
    public TcpServer(int port)
    {
        listener = new TcpListener(IPAddress.Loopback, port);
        listener.Start();
        ThreadPool.QueueUserWorkItem(Listen);
    }

    private void Listen(object state)
    {
        while (true)
        {
            using (TcpClient client = listener.AcceptTcpClient())
            {
                AcceptClient(client);
            }
        }
    }

    private void AcceptClient(TcpClient client)
    {
        using (NetworkStream inStream = client.GetStream())
        {
            OnConnect(inStream);
            while (client.Connected)
            {
                int available = client.Available;
                if (available > 0)
                {
                    byte[] buffer = new byte[available];
                    int read = inStream.Read(buffer, 0, available);
                    Debug.Assert(read == available);
                    OnDataReceived(buffer);
                }
                else
                {
                    Thread.Sleep(50);
                }
            }
        }
        OnDisconnect();
    }

    private void OnConnect(NetworkStream stream)
    {
        var connect = Connect;
        if (connect != null)
        {
            connect(this, new ConnectedEventArgs() { Stream = stream });
        }
    }

    private void OnDisconnect()
    {
        var disconnect = Disconnect;
        if (disconnect != null)
        {
            disconnect(this, EventArgs.Empty);
        }
    }

    private void OnDataReceived(byte[] buffer)
    {
        var execute = DataReceived;
        if (execute != null)
        {
            execute(this, new DataReceivedEventArgs() { Buffer = buffer });
        }
    }

    #region IDisposable Members

    public void Dispose()
    {
        listener.Stop();
    }

    #endregion
}

public class DataReceivedEventArgs : EventArgs
{
    public byte[] Buffer { get; set; }
}

public class ConnectedEventArgs : EventArgs
{
    public NetworkStream Stream { get; set; }
}

Once Skype has been told the port numbers on which to connect, it will attempt to open sockets to our TcpListener classes (one for audio in, and one for audio out). We now simply need to pass the audio through our effect chain. But EffectStream needs a WaveStream derived class for its input, so I created SkypeBufferStream to which we pass the raw data received on the microphone in socket, and it returns it in its Read method. One difficulty I encountered was that Skype offers no way of querying what the sample rate of the incoming data is. On my PC it seems to be 44.1kHz, but I do not know if this is guaranteed on all computers.

class SkypeBufferStream : WaveStream
{
    byte[] latestInBuffer;
    WaveFormat waveFormat;

    public SkypeBufferStream(int sampleRate)
    {
        waveFormat = new WaveFormat(sampleRate, 16, 1);
    }

    public override WaveFormat WaveFormat
    {
        get { return waveFormat; }
    }

    public override long Length
    {
        get { return 0; }
    }

    public override long Position
    {
        get
        {
            return 0;
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public void SetLatestInBuffer(byte[] buffer)
    {
        latestInBuffer = buffer;
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        if (offset != 0)
            throw new ArgumentOutOfRangeException("offset");
        if (buffer != latestInBuffer)
            Array.Copy(latestInBuffer, buffer, count);
        return count;
    }
}

Now when we receive any data from the microphone socket, we pass it through the SkypeBufferStream which in turn passes it through the EffectStream and finally out on the output socket's data stream. Here's the relevant code (found in the MicInterceptor class):

NetworkStream outStream;
SkypeBufferStream bufferStream;
WaveStream outputStream;

void OnOutServerConnect(object sender, ConnectedEventArgs e)
{
    log.Info("OutServer Connected");
    outStream = e.Stream;
}

void OnMicServerExecute(object sender, DataReceivedEventArgs args)
{
    // log.Info("Got {0} bytes", args.Buffer.Length);
    if (outStream != null)
    {
        // give the input audio to the beginning of our audio graph
        bufferStream.SetLatestInBuffer(args.Buffer);
        // process it out through the effects
        outputStream.Read(args.Buffer, 0, args.Buffer.Length);
        // play it back
        outStream.Write(args.Buffer, 0, args.Buffer.Length);
    }
}

When you run your application for the first time, you will need to grant it permission from within Skype:

image

image

To test that the effects are working in Skype is a little tricky as you will not hear the effected sound on your end of the conversation. One good way of checking the effects are working as expected is to use the Skype test call service. This is a number you can dial and it will record what you say and play it back to you.

image

It is a good idea to test your effect first using a local audio file, as you will not easily be able to determine whether glitches and other audio artifacts were caused by your effect, or simply due to poor network conditions.

There are a few things you should be aware of when selecting effects for use with Skype. First, the audio is mono, so there is no point using any effects such as stereo delay. Second, the audio is almost certainly down-sampled to a much lower sample rate before being transmitted to save on network bandwidth. This means any high frequency components of your sound will be lost. Third, internet telephony applications often have built in echo-suppression, so using delay-based effects might not work quite as well as you were hoping.

For silly voice effects, the most effective is pitch shifting (try the SuperPitch effect and shift either up or down about five semitones). FlangeBaby or Chorus can be used for more subtle voice changing effects. Or if you just want to be annoying, load up a Delay. Feel free to experiment with the other included effects, but bear in mind that many of them are designed with more musical uses in mind, so may not be relevant for internet telephony.

The Sample Code

The source code for all the effects, the EffectStream and the Skype connection code described in this article is available in the provided download. It uses a recent unreleased build of NAudio, so you will also need to visit the NAudio CodePlex site if you want to get access to the full source code. The EffectStream and Effect classes will eventually be made part of the NAudio framework, once I have refined their design a bit.

image

How to use Effect Tester sample app:

image

Click this icon to attach to Skype and await a call. Click it again to disconnect, allowing you to test your effects using audio files instead. The textbox in the top right corner keeps you updated with the status of the connection to Skype

image

Click this icon to load a WAV or MP3 file for playback. Files at 44.1kHz work best.

image

Rewind, Play, Pause or Stop the current WAV or MP3 file.

image

Brings up the effect selector dialog to add a new instance of an effect to the current Effect chain. Loaded effects appear in the CheckedListBox on the left.

image

Removes the currently selected effect from the effect chain

image

Move the currently selected effects up or down in the signal chain

image

Use the checkboxes to enable or disable effects in the effect chain on the fly.

image

Use the sliders to adjust the effect parameters in real-time

About the Author

Mark Heath is a .NET developer based in Southampton, UK. When he's not writing .NET audio applications for fun, he enjoys home studio recording, playing football, reading theology books and sword fighting with his four small children. His development blog can be found at http://mark-dot-net.blogspot.com

Tags:

Follow the Discussion

  • fchopinfchopin

    great genius stuff.. but! whenever i connect it to skype the tester effect box tells me that there is a problem with the software and that the program has stopped! why is that? can somebody explain it to me?

  • Clint RutkasClint I'm a "developer"

    @fchopin, I think you need Skype already on then click the "Skype" button the application.

  • Vetle SVetle S

    It doesn't seem to run on x64 Windows. I am getting what pepito got, Error: CLSID {830690FC-BF2F-47A6-AC2D-330BCB402664} failed with error 80040154.

    Not a developer, Windows 7 HP x64 running Skype x86.

  • markheathmarkheath

    I'm in the process of updating NAudio to properly support x64. For now, set the compile options on Skype Voice Changer to target x86 and this should fix it.

  • MattMatt

    Can this work on Windows 7 64-bit?

  • Clint RutkasClint I'm a "developer"

    @Matt, you'll have to recompile based on Mark's comment above

  • Clint RutkasClint I'm a "developer"

    @James, doing a quick glance, I think if you just use EffectStream, that should do it.

  • JamesJames

    Hi,

    Great stuff, I am trying to create a ligh version that will just take the microphone stream and the effect that, but i am stuggling.

    Do you have a simple code block to intercept the mic and then effect it?

    Thanks

  • John MangamJohn Mangam

    Hi,

    In addition to my earlier query, could you please tell me on what basis and at what intervals does this DataRecieved event get triggered (Data from the microphone)?

    Thanks for your help.

  • John MangamJohn Mangam

    Hi Mark,

    In addition to my earlier queries, could you please answer the below query as well soon?

    I see that the micServer's data recieved i.e., byte[] has values from 0 - 255. How could I determine that a word is spoken taking the byte[] into consideration?

    Could you please help me soon?

    Thanks for your help.

  • John MangamJohn Mangam

    Hi Heath,

    I need to manipulate the incoming sound. Lets say I get a child voice I would like to change it to adult voice.

    And in respective places, I have added the code:

    InPort ="3756"

    call.set_OutputDevice(TCallIoDeviceType.callIoDeviceTypePort, InPort.ToString());

    // initialized inServer

    inServer = new TcpServer(InPort);

    inServer.DataReceived += inServer_DataReceived;

    // In dataReceived event I tried playing a wav file

    args.Buffer //Lets say I have applied some manipulation inStream.Write(args.Buffer, 0, args.Buffer.Length);

    I seem to have a problem to manipulate the incoming audio and then play it at my end.

    Please help me soon Smiley

    Thanks a lot.

  • Clint RutkasClint I'm a "developer"

    @John Mangam I've forwarded the question to Mark, the author of this article.  He hopefully knows where to look for this hook-in, if one exists.

  • John MangamJohn Mangam

    Hi Heath,

    Thanks for moderating my query. It would be great if you could answer it soon. I have been waiting Smiley

    Thanks,

    John

  • John MangamJohn Mangam

    Hi Heath,

    Thanks for your contribution. It's great. Could you please tell me how I could manipulate the skype incoming audio from an external call?

    Thanks,

    John

  • markheathmarkheath

    Hi John,

    I think it should be possible to do, but I haven't done it myself. I used Skype4Com (developer.skype.com/accessories), which exposes all the Skype API, so it would be worth having a look at that to see if it is possible

  • Clint RutkasClint I'm a "developer"

    @Bittarman looking into it if it still works with newest skype, the apps C4F builds can't provide long term support.  If an external application changes their API model, our stuff will break.

    This sample also came out before Visual Studio 2010 was released.  VS 2010 will automatically update the solution so it will work and it should "just work".  Coding4Fun has a large sum of samples and articles, updating each one becomes a very large task.

  • BittarmanBittarman

    @Dear Experts,

    This is almost Aug, 2010.

    I cant run your example or do nothing with Skype latest verison.

    Would be kind to update a this blog?? With visual studio 2010 express?

    Best regards

  • linda dawsonlinda dawson

    please help me i dont know how to use dis program  thanks

  • Clint RutkasClint I'm a "developer"

    @linda, check out the later part of the article, basically when it goes to: "When you run your application for the first time, you will need to grant it permission from within Skype"

  • NicNic

    I was able to run this program like 2 or 3 times, but since then it seems to crash, and now I can't open it at all. Event type: clr20r3, code: 0xe0434f4d. Seems to be related to .Net, I have 2.0 and up to 4.0 installed. Is there a solution?

  • RaquelRaquel

    very good

  • Clint RutkasClint I'm a "developer"

    @Nic looking into it right now.  Wondering if Skype updated something that caused us to break.

  • NicNic

    I deleted all my custom fonts and scripts I use for graphic design from my Windows folder, and now the program works fine. I have another issue though. When I use SuperPitch, I like to use default settings except I move octave to 0 and semitones to 2. However, there always seems to be an echo. None of the other settings I've tried have an echo, just SuperPitch.

  • MarkMark

    @Nic - glad you got it working, although it seems unlikely that fonts would be the cause. As for your super-pitch issue, ensure that you use it 100% wet (dry mix slider should be at minimum)

  • NicNic

    Thanks for the response, Mark. I have it at 100% wet but I still get the echo effect. I've played with moving all the other bars around but the echo is still there.

  • criscris

    gostei mto

  • eliraneliran






























    Skype voice distortion software

  • marisa.villaverde.iglesiasmarisa.​villaverde.​iglesias

    ola

  • marisa.villaverde.iglesiasmarisa.​villaverde.​iglesias

    ola

  • andrezaandreza

    quero ter o skype

  • andrezaandreza

    quero ter o skype

  • andrezaandreza

    quero ter o skype

  • clovislimaclovislima

    quero ter o skype
     

  • emersonemerson

    sem comentarios

  • rosanarosana

    reoio

  • deisedeise

    sou de Macaé RJ e gosto muito de ler

  • CleberCleber

    gsfshahsajkkadgkscgcv

  • Letícia Letícia

    ^^

  • olá

  • Joao Pedro PelegrinoJoao Pedro Pelegrino

    Skype e tudo que preciso no meu pc

  • Hipolito Andrade da CostaHipolito Andrade da Costa

    Preciso muito do skype

  • andreandre

    sou homem

  • CarolinaCarolina

    Oii

  • ArifArif

    very good software

  • valeriavaleria

    oiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii

  • joaquimjoaquim

    olá pessoal olha viver com deus no coração é a melhor coisa do mundo nós vivemos pra eles em quanto estive vivo ele ex-tara conosco a onde quem que seja que deus nos proteja e muito obrigado a todos ficar com deus no coração de cada um de vocês chau

  • melina ribeiromelina ribeiro

    qero sar logo...

  • jose carlos fernandesjose carlos fernandes

    Eu gotaria muito de ter o skype,p/manter mais conectado.grato

  • Denise Elvira de OliveiraDenise Elvira de Oliveira

    Gostaria de me conectar com atravez do skype.

  • vagner roberto gomes de abreuvagner roberto gomes de abreu

    bom

  • BlackTwiinBlackTwiin

    Olha..
    Eu curti esse skype ae..
    To com ele no PC !
    muito massa...
    Quando eu vo jogar algum jogo com meus amigos..
    "NOIS" entra em "CONF" todo mundo... é "LOCO"

    Obs: Conf = Conferencia

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.