Under Linux, the simplest way is to open a pipe toward programs like aplay or pacat (or opening a file toward "/dev/dsp"), and sending raw data, either with PRINT # or with PUT. So, raw PCM sound can be achieved even from the simplest code, and even scripting languages can do that. My idea is just to mimic this simple syntax: a SoundSet command to define the sampling frequency, the number of channels (mono or stereo), and the bit depth (8 or 16), and a PlayBuffer command, to send the number of samples and a pointer to the raw data, that could be in a simple numeric array, or in an UDT type (just like a graphic buffer: GET and PUT can use a specific image type, but also a simple byte array)
The command PlayBuffer could be used more than once, stacking more and more samples: the program would keep running, and if the command is used before the last buffer has finished being played, the new samples would just be queued (something similar, although much more primitive, happened even in the original QBASIC with the PLAY command). A SoundQueue() function could return how many samples are still to be played: when it runs too low, it's time to submit new samples, or the sound will stop.
So, a simple loader could be used to prepare a buffer from a WAV file (besides a small header, a WAV file consists just in raw data), and that buffer could be played with a single command. There would be no need to expose callback: if someone wants to play the same sound over and over, the only thing they would need is to check in the main loop when SoundQueue() is too low, and submit the sample again. This would allow both to play the same WAV file over and over, and to create sounds on the fly (simulating some PSG chip, mixing sound samples with DSP algorithm... or even running a .MP3 decoding library). Implementing support for other sound formats over a similar driver would be pretty easy, and portable.
About multiple channels: it could be done under ALSA, and under Windows Sound System, it would be more troublesome under DOS and under Open Sound System, so, to make the code portable, it would be easier not to include it, and letting the application taking care of the mixing, if needed (also, how would you deal with mixing an 8 bit mono sound with a 16 bit stereo one, with different sampling rate? It would make the library overcomplicated, to add a feature that might not even be used)
Do you intend to create and modify sounds in memory only or with realtime playback?
I intend to create sounds with realtime playback, to save memory, and to provide an experience closer to the classic basic sound command. Of course, it would be possible to send the created sound to a buffer, instead of playing it, and then play that buffer later, or save it as a new WAV file: the concept would be similar to current graphic commands: LINE, or CIRCLE can be executed immediately, displaying the result, or they can be used on a buffer made with ImageCreate, that can later be displayed, or saved.
MIDI can be very simple as it is. Playing music with the Win32 function midiOutShortMsg is pretty well equivalent to doing SOUND 0,100,10,15 in Atari BASIC
In the past, I have seen some examples to emulate SOUND command using midiOutShortMsg, under windows (the code was by Randy Keeling). It worked... but it was Windows only. Also, midi commands are so simple, and so standard, that perhaps it would be better to use them directly instead of building "wrappers" for them. The issue is to make such a command multiplatform, because under Windows if there is no midi-capable hardware a soft synthesizer is provided by default, under Linux on several distro it isn't, so you would have to install Timidity by hand (and it's a heavy download, if you want good sound fonts). Some sound libraries (allegro, or SDL) solved that issue by adding their own soft synth as fall-back solution if no midi is provided by the sound driver. So, the FreeBasic sound library will have to do the same (I already have ported the source of FMMidi to FreeBasic, and the license is compatible)