VS 2015, x64, and Code Cleanup

I had a version of Audacity with some local changes to get rid of “rand()” (it is evil) and to use Gaussian white noise in Noise.cpp. Since it had gotten pretty far behind, I decided to update my source tree to match Audacity’s HEAD. This took a little more effort than expected since I no longer had anything but VS 2015 installed and Audacity had switched from SVN to Git since my last update (and perhaps too much free time on my hands to take the obvious step of installing VS 2013). Anyhow, I got Audacity compiling with VS 2015 Community for both x86 and x64 (I used wxWidget’s HEAD for VS 2015 support). The x64 build works well enough to record and play back sound, but I have not tested beyond that.

I still haven’t backported my rand()/Noise.cpp changes, but I did run into a number of things that may be of more general interest. Off the top of my head, here are some of them:

  • Visual C++ has a “stdint.h” implementation, and has had one since VS2008 (?). The conflicting compatibility version causes problems with VS2015 builds.
  • There are lrint()/llrint() implementations declared in “math.h”. Windows and x86-specific inline asm reimplementations of existing library functions don’t need to clutter the code.
  • It is probably a good idea to set /DYNAMICBASE (ASLR) and /NXCOMPAT (DEP) these days.
  • Setting /MP (multi-processor compilation) speeds up the build.
  • The post-build step in portaudio-v19 is a bit hairy and x86-specific; it was replaced by some changes to the vcxproj file to set the s based on the relevant environment variables.

Since it is a non-trivial effort to track down the changes, create, and test pull requests, I thought I should first see if (when?) someone wants to look at them and what such things might be of most interest. Regardless, the kitchen sink can be found here: https://github.com/henricj/audacity/tree/vs2015.

It’s rather melodramatic to call rand() “evil”, and I can’t bring myself to accept comments like “pretty f***ing horrible” as a serious critique. C++ notes that “rand() is not recommended for serious random-number generation needs, like cryptography”. Well we’re not dealing with cryptography, we’re dealing with audio, and rand() performs perfectly adequately in all practical audio applications that I can think of. Perhaps you have a practical example where it doesn’t, or is this just a “religious” crusade? :wink:

Unfortunately I am not able to test your code as it does not build on Linux.

To be clear, are you generating “uniform distribution white noise” or “normal distribution white noise”? For audio use, “white noise” is generally taken to mean uniform distribution (“rectangular” distribution), and that is the meaning in Audacity.

Regarding which version of Visual Studio, the developer guide for Audacity on Windows clearly states:
"Audacity is currently built with Visual Studio 2013 C++ from Download Visual Studio Tools - Install Free for Windows, Mac, Linux. For free versions, use “Express 2013 for Desktop” or the full-featured Community edition (free for non-enterprise use). "
Missing features - Audacity Support
The supported version of VS will no doubt be updated in due course, but at present Visual Studio 2013 C++ is the only version that is officially supported by Audacity and updating to a later version is not the highest priority at this time.

It looks like your use of intptr_t is what has broken building on Linux.

OK, you can fix that by adding to allegro.h and mem.h:

#include "stdint.h"

Is it actually necessary to modify the third party libraries to make it build in VS 2015? Generally we leave the libraries alone unless the library is being updated to a later version. On Linux, the third party libraries in the source tree may or may not be used, depending on whether the library is available on the system or not. Modifying these libraries is therefore best avoided else we have some systems using modified libraries and some using the unmodified version.

Note also that, even when we drop support for PPC Mac, some parts of C++11 are “experimental” or “optional” and may not be supported on all platforms.

Needing to maintain changes in third party libraries (and, ideally, feeding such changes upstream) is decidedly undesirable. Most of the mischief is from Microsoft using 32-bit "long"s for their x64 ABI. Apart from the “stdint.h” stuff, which I think is from conflicts between the compatibility version and the official Microsoft version, most of those changes are in the x64 commit (29a0267). The changes needed to compile with VS2015 (that is, with the v140 compiler) are in the “Switch to VS2015 (v140)” commit (196b80b). I didn’t notice that I had the line endings screwed up until after I pushed the changes to GitHub, so the diffs are unusable there (perhaps a .gitattributes might be helpful?).

With regard to rand()… I don’t know about “religious”, but the Microsoft version only generates 15-bits per call. This is in stdlib.h:

// Maximum value that can be returned by the rand function:
#define RAND_MAX 0x7fff

…and I just hit “Submit” instead of “Preview”… Hopefully what is pending makes some sense.

I was blabbing about “rand()”. I think it is fine on Linux and FreeBSD, and I suspect OS X as well. It is the Windows version that is really troubling. Microsoft recommends against using it: rand() Considered Harmful.

With regard to white noise, that is just (IIRC from school) noise with a flat power spectrum. If one takes tape hiss, radio static, or most random physical processes and take a look at a histogram of the samples, one tends to get something that looks much more like a Gaussian/normal distribution than a uniform distribution. Load a WAV or record some line-in data with nothing connected and load it up in MATLAB or Octave, or do a “Sample Data Export” from Audacity into CSV and pull it up in Excel. A histogram of the samples should look something like a bell curve (did I miss some way to show the same inside Audacity?). The signals propeller heads tend to model noise as Gaussian (AWGN… additive white Gaussian noise). I’m not saying Audacity shouldn’t do uniform white noise, but it seems likely that those of us not from the audio community will assume otherwise unspecified “white noise” is Gaussian.

With 2.1.2 just released, we have dropped support for PPC Mac.


Gale

Plot Spectrum: Audacity Manual

I really don’t have time to listen to a half hour lecture about why rand() is evil, but if you can present one real-world practical audio example that demonstrates the inadequacy of Audacity’s white noise generator, then you have my attention :slight_smile:

As far as I can see, that is all in the frequency domain. What I meant was a histogram of the time-domain samples. The attached has three different kinds of white noise that all look the same on the “Plot Spectrum” page. They also sound alike to my tin ears, but they look very, very different in the time domain (zoom in or look at a histogram). Note that the “Binary” track only has two different amplitudes, with a 4:1 bias towards one of the values.

The abstract pretty much covers it: Microsoft says to not use rand(), particularly their implementation. Quite apart from the philosophical “is it random enough” stuff, the MS rand() call only returns values from 0 to 32767. Since there are only 2^15 such values, there is no way the Noise generator can generate more than 1/512 of the possible values for 24-bit PCM or float (roughly) waveforms. Does the Tone generator use a 15-bit integer sine wave? Unless one is only working with 8-bit PCM tracks, that seems a bit coarse.
White Noise.zip (1.55 MB)

I wasn’t aware that the Windows version was quite as “bad” as it is, though to put this into proportion, it is only one bit worse than “CD quality”.

Are you certain that Noise.cpp is using std::rand() and not a WxWidgets version of rand()?
I can’t find any documentation for there being a wx version, but I’ve just tested the “white noise”, with amplitude 1.0 (0 dB) on a Windows machine, and the samples appear to be 24-bit values (and 30-bit on Linux).

Yes, we could have any number of options for different statistical distributions. I don’t think that there is sufficient demand to include such options in the standard release version of Audacity, though it could be interesting as an optional plug-in.

My opinion is the same as Henric’s. White Gaussian noise should definitely be included as it is a better model for real world noise than uniformly distributed one.
Also, the Rms is much lower, ever made a jump out of your seat because of accidentely hitting play on a 0 dB noise track?
I always try to use Gaussian noise for plugin testing, by summing up 20 noise signals.
See also http://www.dspguru.com/dsp/howtos/how-to-generate-white-gaussian-noise.

There’s also some code here on the forum that renders the distribution of sample values into an audible histogram (left to right panning) - perhaps in the topic “Study in pink”.

Robert

As long as one has the right C++11 features available, generating uniform or Gaussian noise is trivial. I used the kGaussian case below, added to src/effects/Noise.cpp, to generate the attachment in my earlier post. std::normal_distribution<> is part of the standard library.

#include <random>
...
   std::mt19937 rng;
...
   case kGaussian:
   {
      // The variance of our uniform distribution is (-mAmp - mAmp)^2 / 12.
      // Adjust the amplitude to to give the same RMS ( (-1 - 1)^2 / 12 = 4/12 = 1/3).
      const double uniformToNormal = sqrt(1 / 3.0);

      std::normal_distribution<float> gaussian(0, mAmp * uniformToNormal);

      for (sampleCount i = 0; i < size; i++)
      {
         buffer[i] = gaussian(rng);
      }

      break;
   }

This would generate a uniform distribution with the same Mersenne Twister generator.

      std::uniform_real_distribution<float> uniform{ float(-mAmp), float(mAmp) };

      for (sampleCount i = 0; i < size; i++)
      {
         buffer[i] = uniform(rng);
      }

We’re not yet using C++11, though that will come eventually.

Have you checked to see if the White noise generated on Windows really is only 15-bit?

Yes, you’re right. I’d characterize it more as, “borderline and possibly misleading,” than “broken”. Where by “misleading”, I mean that someone using a generated waveform might not expect it to have a bunch of missing codes.

Yes, I was poking about in the guts of things trying to find if “srand()” was getting called (yes it is: DirManager calls it in it’s constructor). You can put a breakpoint on the MS CRT rand() or step into it (you may need to enable the Disassembly window and do the “Step Into” there).

For reference, the Noise.cpp code looks like this:

   float div = ((float)RAND_MAX) / 2.0f;
...
   case kWhite: // white
      for (sampleCount i = 0; i < size; i++)
      {
         buffer[i] = mAmp * ((rand() / div) - 1.0f);
      }
      break;

On Windows, the generator has been the same since the dawn of time and RAND_MAX is 0x7fff (the define in stdlib.h). It looks something like this:

// Returns a pseudorandom number in the range [0,32767].
extern "C" int __cdecl rand()
{
    __acrt_ptd* const ptd = __acrt_getptd();

    ptd->_rand_state = ptd->_rand_state * 214013 + 2531011;
    return (ptd->_rand_state >> 16) & RAND_MAX;
}

In the disassembly, the last thing it does before restoring the stack pointer and returning is:

and         eax,7FFFh

Aside: This is the same generator used in Free Cell.

The code in Noise.cpp scales things from rand()'s 0-32767 to -mAmp to +mAmp, but since there are only 2^15 possible inputs (“rand()” is only called once), there cannot be more than 2^15 possible outputs.

I hear you. I’m not sure much more than Uniform and Normal/Gaussian would be reasonable for a “noise” generator versus a more general syth. The “Binary” track was just there as an example of something that is both “white noise” and useless for any practical purpose. Besides, stray too far from the technical sense of the word “noise” and one starts to intrude on barking dogs and one or another top 40 hit.

Sorry, I’ve been talking about the noise creation in Nyquist.

Using my “Bit-Depth Determination” plug-in, the Audacity noise is reported as 26-bit integer and the Nyquist noise as 32-bit integer.
There is certainly some scaling in the background, but the indication is clear.

You are referring to the noise function? It calls “snd-white”, which is implemented in white.c with,

*out_ptr_reg++ = (sample_type) (rand() * rand_scale - 1.0);

where “rand_scale” is defined as,

#define rand_scale (2.0/RAND_MAX)

in white.h.
This gets us back to our old friend “rand()”.

If one wanted to change this, using a better RNG at least on Windows and adding a new function to do Gaussian noise, the right place to do so would probably be upstream in the original Nyquist library. Adding a “snd-whiten” or “snd-whiteg” function wouldn’t be all that intrusive to the Nyquist code; I think adding a line to sndfnintptrs.h would do it. Still, upstream is better.

There seems to be a distributions.lsp with a “gaussian-dist”, but if it returns a single value at a time, it might be a bit slow for generating a track.

In a white noise plug-in, would it be useful to have a control for variance?
Would it be useful to allow sample values greater than 0 dB?

Do you mean a separate (Nyquist) plug-in?
Variance might be OK, but I wouldn’t allow samples > +/-1.0.
You should at least set the limit for the RMS at -4.8 dB (as with uniformly distributed white noise), I think.

I think that heneric was thinking of C++, which would probably be better for speed unless someone writes a fast primitive for Gaussian noise in Nyquist.

For 32-bit float, values greater than 0 dB are valid. For specialist use cases where uniform distribution white noise is not suitable, values greater than 0 dB may be needed, (though I don’t recall anyone yet giving pracical use cases where Gaussian rather than uniform white noise is actually required).

That begs the question, if you want it to be “like” uniform white noise, why not just stick with uniform white noise?

I’m still intrigued why Audacity’s white noise appears to be much more than 15-bit on Windows when the code suggests that it shouldn’t be. I like to know what’s broken before I start fixing something.

I’m sure there are “scientific” cases where it makes a difference, just like the spectral gaps in white light are important for some purposes (eg photography, artist paintings). On the other hand, modern “display lighting” has improved a lot from the old fluorescent tube lighting and is perfectly adequate for most purposes.

I’m a bit surprised/concerned that we are approaching page 3 of this discussion and still don’t have a compelling use case for why this is necessary,. I agree that “high quality” white noise would be “nice to have” if it can be accomplished without a significant speed penalty. I also agree that Gaussian white noise could be a useful optional extra for some users, though I’m not aware of any demand prior to this discussion with henric.