For those interested in using the raw audio samples, I can let you know that using a winamp dsp plugin is a working soultion.Fair enough, it is a good workaround while we're waiting for Steven Mayall (the creator of MusicBee) finally adding an API function to get raw samples data (which can have any number of channels, samplerate can be anything, and it is in floating-point format unlike Winamp DSP plugins or the FLAC format) for parity with foobar2000's get_chunk_absolute() function (which is used by oscilloscope components and certain spectrum visualizations like foo_enhanced_spectrum_analyzer)
There are several technical limitations such as: buffer size (which depends on the audio device) and maximal frequency and bit depth (which are limited to 44100khz, 16bit).
I have done a proof of concept to implement this, but before I spend more time implementing a proper solution is there anyone who is going to make use of this?Not only useful for oscilloscope/vectorscope-type visualizations but also certain spectrum analyzers (especially when it uses custom FFT routine or even ditches the FFT entirely like ones that uses IIR filter bank), loudness (LUFS), and even true peak meters (basically peakmeter but sinc-interpolated to detect possible intersample peak clipping)
Is using a Winamp DSP plugin just for working around the MB API currently not having a feature to get sample data, worth risking unintentionally "adulterating" (albeit inaudibly except on extreme bass boosted songs, assuming it is a float32 export in which there are peaks above 0dBFS line as the result of bass boosting process) the audio output by "transcoding" into int16 format (the very same reason behind the transcode warnings I've get on some WAVs when I've try converting uncompressed PCM into FLAC using foobar2000), so that the Windows' built-in audio peak limiter (that only appears when not using WASAPI exclusive output in any supported players) won't kick in because it was hardclipped to 0dB anyway?True. But when you put a float32 WAVs (e.g. coming from bass boosted exports of any audio file including MP3 and other lossy sources, which contains +0dBFS peaks when decoded even before processing) while these Winamp DSPs aren't enabled, the output are limited rather than clipped/distorted right?
I'll have to dig deeper into the topic in future, but for now the float32s are transcoded into 16bits with the DSP (lesser bit depth). So is my understanding, and so is the behavior for the sample file you've prepared.
Also, both - dsp and bass - return values beyond the 0db. Whether limited in some way or not, I currently don't know. But the visual clipping to 0db comes from the CEN plugin.
though hopefully, MusicBee API adds a feature to get raw samples data, which makes the Winamp DSP as a workaround obsoleteall i said in the previous post above, i want someone to state that they will make use of it before I do the work to make it available
I have done a proof of concept to implement this, but before I spend more time implementing a proper solution is there anyone who is going to make use of this?
And if so, would you use C++ or C# ? (I recommend C++ for this type thing)
Your plugin would provide a function that MB directly supplies the raw PCM data to, post any DSP modifications, in real time
all i said in the previous post above, i want someone to state that they will make use of it before I do the work to make it availableI cannot say that the need for such an API is existential, but it unlocks the possibility for a bit more quality for the plugins in the future. Again from my experience with the CEN plugin, this would mean more suitable Fourier transformations for the specific purpose - spectrograms, vu-meters, etc. which brings a bit more quality to the visualizations and expands the options for diverse algorithms.
__declspec(dllexport) void GetPCMRawData(float*, int);
// called in real time with a copy of current playing stream data, but MB calls this function in a separate thread to protect MB from potential interference from the plugin.
void GetPCMRawData(float* data, int length) {
}
I'll report back when I test the whole dynamics of my plugin and the actual data values.BTW, are "proper" Mid/Side (M/S) mode only possible with new API to get raw samples data, or it is already done with built-in function to get spectrum data?
the link has been updated
https://www.mediafire.com/file/sl0k311vrbbs66j/MusicBeeBass.dll/file
for the first 2 issues, the link has been updatedYour statement that bass doesn't do any additional resampling is enough for me at the moment. I'll try to run standard FFT to verify that, but it will take some time. Up to now I only compared the sizes of the data streams per second and used a frequency band transformation to check the spectrum structure visually. The latter might not be the ultimate proof for resampling or cut off frequencies, that I am suspecting, but here is how it looks like for a 48khz audio file:
https://www.mediafire.com/file/sl0k311vrbbs66j/MusicBeeBass.dll/file
and also
https://getmusicbee.com/patches/MusicBee36_Patched.zip
I dont get your statements about resampling. MB is just intercepting the DSP chain from bass after it has decoded the raw data and before the data is sent to the output device. Unless you have the "resample to" option ticked in the player preferences, I dont see why bass would resample anything ie. the data you receive should be the sample rate from the source file. However there was a bug in MusicBeeBass.dll now fixed which i guess might somehow have affected what you were seeing.
If he's mistakenly using Wasapi-shared he would end up with output resampled by Windows to whatever the Windows Mixer was set to, no matter what he set/didn't set in MusicBee, correct? Wasapi-exclusive needs to be used.We are comparing the audio data before being passed to the output driver/device. I mixed up WSAPI and ASIO during the testing, because it changes the data chunk size on each RawData or DSP function call.
Also: the updated MusicBeeBass.dll was not contained in the MusicBee36_Patched.zip in the same post--does this mean others should hold off on replacing the DLL yet?
2)Changing the device output also works, but there is some regress. If I use the player next/previous track controls or select a song other than the played on startup, the RawData function never gets called again... unless I change the output settings!this should work
Yes, it works!2)Changing the device output also works, but there is some regress. If I use the player next/previous track controls or select a song other than the played on startup, the RawData function never gets called again... unless I change the output settings!this should work
https://www.mediafire.com/file/sl0k311vrbbs66j/MusicBeeBass.dll/file
This allows me to test it for a while and fix my own plugin issues around it.Good, though it is not complete without replacing the built-in FFT method with a custom FFT routine that permit non-power of two sample lengths and even makes Mid/Side representations possible (if built-in method of getting spectrum data doesn't support Mid/Side mode)
4) A DSP plugin does not work anymore after disabling/enabling in "Equalizer/DSP Settings" using the checkbox. To work again I should disable/enable the menu entry "Control->DSP Effects" or restart MB. This seems to be a 3.6 bug, 3.5 was working correctly with thatI noticed this too just a day ago testing settings for possible effects on VU meters--unchecking the VST in the settings box in real-time does disable its effect on the audio, but re-checking it does not re-enable it until MB is restarted. Did not happen with 3.5, which would re-enable live as soon as the plugin was re-checked.
During the testing I noticed two more small bugs:should work now:
4) A DSP plugin does not work anymore after disabling/enabling in "Equalizer/DSP Settings" using the checkbox. To work again I should disable/enable the menu entry "Control->DSP Effects" or restart MB. This seems to be a 3.6 bug, 3.5 was working correctly with that.
5) When an automatic change between two tracks in a playlist with different sample rates occurs, then the DSP and RAW streams remain at the sample rate of the first track. It works correctly again if I manually change the track.
I don't know if anyone else needs the pre vs post levels and if they would use it.The sole reason why I raised this matter was that with ReplayGain active, the needle only travels a small part of the scale, not making use of the available space at all.
The only thing I personally care about (a lot) is that ReplayGain values are ignored.
Its also post any user volume slider adjustment.Both DSP and RawAPI samples are disregarding the volume slider adjustments. Only replaygain, the preamp and equalizer are applied to both.
for wasapi exclusive it will be applying the volume sliderIts also post any user volume slider adjustment.Both DSP and RawAPI samples are disregarding the volume slider adjustments. Only replaygain, the preamp and equalizer are applied to both.
for wasapi exclusive it will be applying the volume slider
if its useful i am happy to add an api call to get/notify the volume adjustment being applied to the current stream
if its useful i am happy to add an api call to get/notify the volume adjustment being applied to the current stream
[StructLayout(LayoutKind.Sequential)]
public struct StreamInfo
{
public int OutputApi;
public int ChannelCount;
public int SampleRate;
public long Length;
public double Volume;
public double PreAmp;
public double ReplayGain;
}
public void GetStreamInformation(IntPtr ptr)
{
StreamInfo info = (StreamInfo)Marshal.PtrToStructure(ptr, typeof(StreamInfo));
}
OutputApi has these values:
WasapiShared = 1
Asio = 2
WasapiExclusive = 3
__declspec(dllexport) void GetStreamInformation(StreamInfo*);
struct StreamInfo
{
int OutputApi;
int ChannelCount;
int SampleRate;
long long Length;
double Volume;
double PreAmp;
double ReplayGain;
};
void GetStreamInformation(StreamInfo* info)
{
}
Both DSP and RawAPI samples are disregarding the volume slider adjustments. Only replaygain, the preamp and equalizer are applied to both.On the unrelated note, visualization data (both waveform and spectrum) on foobar2000 are gathered after all DSP effects but before the volume slider
Codestruct StreamInfo
{
int OutputApi;
int ChannelCount;
int SampleRate;
long long Length;
double Volume;
double PreAmp;
double ReplayGain;
};
[StructLayout(LayoutKind.Sequential)]
public struct SoundStreamInfo
{
public int OutputApi;
public int OutputChannelCount;
public int OutputSampleRate;
public int SourceChannelCount;
public int SourceSampleRate;
public int SourceDsdRate;
public int SourceBitsPerSample;
public long Length;
public double Volume;
public double PreAmp;
public double ReplayGain;
}
public struct SoundStreamInfo
{
public int OutputApi; // always 0, previously worked well
public int OutputChannelCount; // always 0
public int OutputSampleRate; // always 0
public int SourceChannelCount; // works very well
public int SourceSampleRate; // works very well
public int SourceDsdRate; // works very well
public int SourceBitsPerSample; // works very well
// the rest is unchanged -> works
public long Length;
public double Volume;
public double PreAmp;
public double ReplayGain;
}
I liked the split output/source sample rate and channel count, but even with the new bass dll, I have some problems:
tested with the C# interface and should work now for bothGetStreamInformation does not get called at all for c++ and c#.
https://getmusicbee.com/patches/MusicBee36_Patched.zip
GetStreamInformation does not get called at all for c++ and c#.its also working for me. Is your plugin enabled? I changed it so an explicit check is done before calling the function
actually it wont get called if you dont also have GetPCMRawData exported. I will fix that tonightYour guess and the following fix did the trick. I'm very much happy with how it works!
both should be fixed now, updated musicbeebass.dll is included in this zip
https://getmusicbee.com/patches/MusicBee36_Patched.zip
the first required significant changes which I have tested
public void GetStreamInformation(IntPtr ptr)
{
streamInfo = (SoundStreamInfo)Marshal.PtrToStructure(ptr, typeof(SoundStreamInfo));
}
preamp is only applied if the equaliser is enabled
Anomaly just noticed: when using RawAPI 4K, occasionally there is a "blip" of small spectrum at the extreme right end of the kHz scale which seems unrelated to the source freqencies, i.e. not just an occasional very high frequency actually from the source. This disappears when changing to MusicBee Native Fourier. Using Linear for scale and interpolation, Normal dB, Time 75ms/60fps Two shots from bars and regular:I think you've found something important.
(https://i.imgur.com/m1HESk6.png) (https://i.imgur.com/iPvrh3l.png)
To test it further I set the resemple setting of the MB output to 96khz of a normal 48khz audio file. Then I observed the same artifacts in the zone above 24khz (where there isn't any audio). The artifacts are not present on the DSP source, although the same algorithm pipeline is used for both.
Here are the screenshots (first RAW API, then DSP):
(https://i.imgur.com/tySV38W.png)
(https://i.imgur.com/BJFyri2.png)
It seems to me that the RAW API can have some kind of synchronization problem. But I'm speculating here. Maybe Steven has more to say on that.
Good idea. I couldn't use the test bass, because it crashes for some reason, when I click play.kamen, will you be releasing an incremental update to CoolEdit Nostalgia 5 soon, with those fixes to the RawAPI Bridge mode in place? The artifacts the error produces in the spectrum, albeit slight, get distracting once you know they are there!
Through debugging, I've isolated the problem to a floating point rounding issue, which presents very small fractional numbers as 0.
For the silent signal part of the FFT spectrogram the values for rawapi are about e-10 and some occasional zeros, where for the the DSP e-5 and no zeros (due to the higher silence level).
Those zeros then convert into the decibel scale improperly as blips.
So it is in the end a conversion error on my side.
Should it have been a threading problem, some artifacts should be visible also elsewhere on the spectrum (not only the silent part).
kamen, will you be releasing an incremental update to CoolEdit Nostalgia 5 soon, with those fixes to the RawAPI Bridge mode in place? The artifacts the error produces in the spectrum, albeit slight, get distracting once you know they are there!Yes, I want to make a small update together with some other things I'm currently testing. I'll write about it on the plugin's thread when ready.
BTW, the RawAPI thing is not complete without an oscilloscope or even a realtime LUFS meter as visualization plugin for MBLooks cool. But these features, are they something that you wish to incorporate into a new MusicBee plugin that you are currently developing?
Looks cool. But these features, are they something that you wish to incorporate into a new MusicBee plugin that you are currently developing?An API to get raw sample data with arbitrary length should be enough to implement almost anything other than oscilloscope visualization, something like an LUFS meter
If so, what specific info are you looking to get from the MB API that you cannot currently access?
or are they something that you'd like to see in one of the existing MB plugins (I'm guessing Kamen and BoringName's add-ons)?Perhaps either kamen or BoringName (or even someone else who interested in developing plugins for MB and have some needed expertise on DSP especially the LUFS metering) could implement either the realtime LUFS meter (with a reasonable amount of accuracy and compliance with ITU-R BS.1770 standard), the oscilloscope visualization (of course with multichannel support to visualize waveforms of surround sound), or even both
If the latter, then you'd first have to check with those developers to see if it's something they are interested in building to their plugins.
If they wouldn't be interested, I don't think it'd be reasonable to ask Steven to spend his limited time enhancing API calls that no user has plans to make use of.Yeah, what I meant is that an API to get raw samples data is more than enough and adding a realtime LUFS metering capabilities should be left to plugin developers rather than an API function to fetch LUFS of currently-playing song, which isn't needed as it can be done just by using the waveform data and transform into something that makes sense
note that if the processing on side is too slow it will cause playback to stutter and if you modify the values in the data array it will change what is sent to the output deviceThank you for that. It turns out the processing time of my callback + any time jitter (due to MB thread, windows, etc.) is about 5-6ms, which obviously becomes critical to maintain at below 512 samples.
__declspec(dllexport) void (__stdcall GetPCMRawData(float*, int));
void __stdcall GetPCMRawData(float* data, int length)
With __stdcall the function does not get called at all and for me it makes sense.its working fine here as long as you use __stdcall in the GetPCMRawData definition
All functions that MB calls from the plugin are __cdecl - such as SaveSettings, Close, Uninstall... GetPCMRawData too. (callbacks)
All functions that the plugin calls from MB are __stdcall - such as Player_GetPosition, Player_GetVolume, etc. (the api interface functions)
if you still have issues with the test files, i can have a look if you send me a zipThis is how I use it. (https://www.mediafire.com/file/1j8fnog63e2n365/test_raw_api_041124_151146.zip/file)
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) void GetPCMRawData(float*, int);
__declspec(dllexport) void GetStreamInformation(SoundStreamInfo*);
#ifdef __cplusplus
}
#endif
1) The raw api skips chunks/calls when the output device uses chunks less than 512 samples ( roughly 20% of the chunks are missing). The DSP however works well, and the sound isn't affected. I used FlexASIO for the tests, as it has configurable latency.let me know how the test version goes. I would prefer to keep the api calls in a separate thread
Sorry, my formulation above was misleading. This (https://www.mediafire.com/file/1j8fnog63e2n365/test_raw_api_041124_151146.zip) test project crashes with your test MusicBeeBass.dll. Please advise me on how to change it.if you still have issues with the test files, i can have a look if you send me a zipThis is how I use it. (https://www.mediafire.com/file/1j8fnog63e2n365/test_raw_api_041124_151146.zip/file)
Basically what works for me (without the test projectexcept for yor test MusicBeeBass.dll !) is this:Code#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) void GetPCMRawData(float*, int);
__declspec(dllexport) void GetStreamInformation(SoundStreamInfo*);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef __cplusplus
}
#endif
// working
__declspec(dllexport) PluginInfo* Initialise(MusicBeeApiInterface* apiInterface);
__declspec(dllexport) int Configure(void*);
__declspec(dllexport) void SaveSettings();
__declspec(dllexport) void Close(PluginCloseReason reason);
__declspec(dllexport) void Uninstall();
__declspec(dllexport) void ReceiveNotification(LPCWSTR sourceFileUrl, NotificationType type);
__declspec(dllexport) LPCWSTR* GetProviders();
__declspec(dllexport) LPCWSTR RetrieveLyrics(LPCWSTR sourceFileUrl, LPCWSTR artist, LPCWSTR trackTitle, LPCWSTR album, bool synchronisedPreferred, LPCWSTR provider);
__declspec(dllexport) LPCWSTR RetrieveArtwork(LPCWSTR sourceFileUrl, LPCWSTR albumArtist, LPCWSTR album, LPCWSTR provider);
// storage plugin only:
__declspec(dllexport) void Refresh();
__declspec(dllexport) bool IsReady();
__declspec(dllexport) void* GetIcon();
__declspec(dllexport) bool FolderExists(LPCWSTR path);
__declspec(dllexport) LPCWSTR* GetFolders(LPCWSTR path);
__declspec(dllexport) void* GetFiles(LPCWSTR path);
__declspec(dllexport) bool FileExists(LPCWSTR url);
__declspec(dllexport) void* GetFile(LPCWSTR url);
__declspec(dllexport) void* GetFileArtwork(LPCWSTR url);
__declspec(dllexport) void* GetPlaylists();
__declspec(dllexport) void* GetPlaylistFiles(LPCWSTR id);
__declspec(dllexport) void* GetStream(LPCWSTR url);
__declspec(dllexport) void* GetError();
__declspec(dllexport) void (__stdcall GetPCMRawData(float*, int));
__declspec(dllexport) void GetStreamInformation(SoundStreamInfo*);
GetError @21
GetPCMRawData @22
GetError @21
GetPCMRawData @22
GetStreamInformation @23
1) The raw api skips chunks/calls when the output device uses chunks less than 512 samples ( roughly 20% of the chunks are missing). The DSP however works well, and the sound isn't affected. I used FlexASIO for the tests, as it has configurable latency.let me know how the test version goes. I would prefer to keep the api calls in a separate thread
MB just passes through the data that bass sends it. However there is some inter-thread interaction so as a temporary testing thing, this version passes the data directly from the bass callback and not via a separate thread. So if it still has unexpected behavior then its not MB
musicbeebass.dll test file:
https://mega.nz/file/00dkTSTB#6VpGC9YPu2JGKhUhxH_71xefu_7BvMR3EhXoyKC2gT8
if processing in the plugin takes too long then data will get skipped as the implementation prioritizes the playback experience to the user rather than waiting for the plugin to complete its processing.