Just trying to figure out how to play a simple sin wave...

I’m following this tutorial with the new DynamicSoundEffectsInstance from the latest develop build:

When I try this I get sampling artifacts:


using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace WaterSynth {
    public class WaterSynth : Game {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        private DynamicSoundEffectInstance ds;
        public const int samples = 3000;
        public const int sampleRate = 44100;
        private float[,] buffer;
        private byte[] xBuffer;
        private double timer;

        public WaterSynth() {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        protected override void Initialize() { base.Initialize(); }
        protected override void LoadContent() {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            ds = new DynamicSoundEffectInstance(sampleRate, AudioChannels.Stereo);

            xBuffer = new byte[samples*4];
            buffer = new float[2, samples];


        private void SubmitBuffer() {
            ConvertBuffer(buffer, xBuffer);

        private void FillBuffer() {
            for (int i = 0; i < samples; i++) {
                buffer[0, i] = (float)SineWave(timer, 440);
                buffer[1, i] = (float)SineWave(timer, 440);
                timer += 1f/sampleRate;

        private double SineWave(double time, double frequency) {
            return Math.Sin(time * 2 * Math.PI * frequency);

        private static void ConvertBuffer(float[,] from, IList<byte> to) {

            const int sampleBytes = 2;
            var channels = from.GetLength(0);
            var samplesBuffer = from.GetLength(1);

            for (int i = 0; i < samplesBuffer; i++) {

                for (int j = 0; j < channels; j++) {

                    var floatSample = MathHelper.Clamp(from[j, i], -1.0f, 1.0f);
                    var shortSample =
                        (short) (floatSample >= 0f ? floatSample*short.MaxValue : floatSample*short.MinValue*-1);
                    int index = i*channels*sampleBytes + j*sampleBytes;

                    if (!BitConverter.IsLittleEndian) {
                        to[index] = (byte) (shortSample >> 8);
                        to[index + 1] = (byte) shortSample;
                    else {
                        to[index] = (byte) shortSample;
                        to[index + 1] = (byte) (shortSample >> 8);

        protected override void Update(GameTime gameTime) {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))

            while(ds.PendingBufferCount < 3) SubmitBuffer();


        protected override void Draw(GameTime gameTime) {

Another example…the code from his Tutorial 3 works fine in XNA:


Is choppy in MonoGame:


I’m using the WindowsGL version, since that should be the most compatible with Linux/Mac.

That’s a DynamicSoundEffectInstance bug, tracked in this issue. Your post is a great repro!

Why are you filling the buffer like that? It would make more sense if you used the DynamicSoundEffectInstance.BufferNeeded event like this. That is from a port of SimpleSynth over to FNA so it might work straight away in MonoGame. I havent updated to 3.6 yet though so I cant test.

It can be done either way. DynamicSoundEffectInstance is designed to support event driven or polling. Both ways work just as well as the other.

I went ahead and tried that but it still sounds the same.

Idk if this will work or not, but I’ll try recompiling MG with FNA’s version of the class and see if it works properly with WinGL, then try to identify where the bug might be in the MG version.

Yay, this bug is fixed now with PR #5048 https://github.com/mono/MonoGame/pull/5048