sinshu / meltysynth

A SoundFont MIDI synthesizer for .NET
Other
136 stars 16 forks source link

Provide example showing how to play notes with NAudio #32

Open jeffoulet opened 1 year ago

jeffoulet commented 1 year ago

Hi,

Sorry, my request might sound like a very stupid one, and maybe this is not the correct place to ask, but I'm struggling to actually play the waveform generated by Meltysynth.

What I'm trying to do:

What I've achieved so far:

private static void PlayMeltysynthChord()
        {
            var sampleRate = 44100;
            var synthesizer = new Synthesizer(@"..\Resources\Raw\Abbey-Steinway-D-v1.9.sf2", sampleRate);

            synthesizer.NoteOn(0, 60, 100);
            synthesizer.NoteOn(0, 63, 100);
            synthesizer.NoteOn(0, 66, 100);

            var mono = new float[3 * sampleRate];
            synthesizer.RenderMono(mono);

            var byteArray = new byte[mono.Length * 4];
            Buffer.BlockCopy(mono, 0, byteArray, 0, byteArray.Length); 

            var wav = new WavePcmFormat(byteArray, numChannels: 1, sampleRate: (uint)sampleRate, bitsPerSample: 16);
            var rawDataWithHeader = wav.ToBytesArray();

            var stream = new MemoryStream(rawDataWithHeader);

            var player = new System.Media.SoundPlayer(stream);
            player.Play();
        }

The 'WavePCMFormat' method inserts the .wav header to the data. The result I get is a few seconds of white noise, so I assume there is something wrong in the transformation of the rendered PCM to the .wav stream.

Any help is welcome... Thanks in advance

sinshu commented 1 year ago

You are rendering the waveform to a float array. Since float is 32bit, it's not compatible with bitsPerSample: 16. You should use RenderMonoInt16 and a short array.

By the way, if you want to play a MIDI file, I strongly recommend to use NAudio.Wave.WaveOut or another callback based playback. A fire-and-forget playback like System.Media.SoundPlayer is not suitable for playing a long MIDI file, because it needs a lot of memory to store the whole waveform.

Isn't the existing NAudio example suitable for your application? Is there a special reason to use System.Media.SoundPlayer? If you could be a bit more specific about what you want to do, I might be able to help 🙂

rjjaret commented 1 year ago

You are rendering the waveform to a float array. Since float is 32bit, it's not compatible with bitsPerSample: 16. You should use RenderMonoInt16 and a short array.

By the way, if you want to play a MIDI file, I strongly recommend to use NAudio.Wave.WaveOut or another callback based playback. A fire-and-forget playback like System.Media.SoundPlayer is not suitable for playing a long MIDI file, because it needs a lot of memory to store the whole waveform.

Isn't the existing NAudio example suitable for your application? Is there a special reason to use System.Media.SoundPlayer? If you could be a bit more specific about what you want to do, I might be able to help 🙂

Hello Sinshu,

Since WaveOut is only available for PC, can you recommend a similar approach for Mac?

Thanks!

sinshu commented 1 year ago

@rjjaret If you want to play MIDI files, please try one of the following examples. https://github.com/sinshu/meltysynth#examples

For instance, SFML.Net supports Mac, so I believe it should function on a Mac as well.

rjjaret commented 1 year ago

I want to play a stream, similar to what is being done in the Windows example above. They're originally using System.Media.SoundPlayer, and you suggested WaveOut. But WaveOut is only for PC.

I haven't seen anything quite like that for Mac in the examples, but I'll give another look. Please suggest a place if you know of one.

Alternatively, if there's a way to play a series of midi notes, without saving to file first, that would achieve what I need too.

Thanks! Rob

sinshu commented 1 year ago

@rjjaret Did you try the SFML.Net example?

markheath commented 1 year ago

I have just made a demo showing how to play notes triggered from a MIDI keyboard with NAudio and MeltySynth which I plan to show at my talk about NAudio at the Copenhagen Developer Festival next week. It's the first time I've tried MeltySynth and I have to say it's amazing! Brilliant job, and I was very impressed at how easy it was to integrate with NAudio.

I'll post an example on my blog hopefully in the next week and I'll try to remember to link to it here as well.

sinshu commented 1 year ago

@markheath Very nice! I'm looking forward to the blog post 😎

markheath commented 1 year ago

Blog post is up: https://markheath.net/post/naudio-midi-playback-soundfont-meltysynth Will try to get the sample project onto GitHub as well soon

sinshu commented 1 year ago

@markheath Thank you for sharing information 👍

chaojian-zhang commented 11 months ago

@jeffoulet You can look at my provided code sample for playback MIDI using NAudio below. It's minimalist and fully functional (but consumes lots of memory).

https://github.com/sinshu/meltysynth/issues/41#issuecomment-1761533356