Normalizing audio waveforms code implementation (Peak, RMS)
What is the best method to solve this?
  Intuitively, it seems I might need to calculate a local max or average based on a moving window (rather than the entire set) but I'm not entirely sure. Help?
  


What you are describing with your second of these two quoted bullet points is Automatic Gain Control, which eventually will take us to compression. What you might find useful in your case, i.e for visual purposes only, is a simple logarithmic transformation which is very close to what compression is about but without the complex controls it demands.

The most common way to solve such problems in the audio world is to use a compressor. 

The compressor is monitoring the amplitude of the incoming signal. If that amplitude crosses a user-defined threshold it decreases the amplification in an attempt to keep the signal within certain limits. As you can understand, imposing such limitations to a signal without special care could result in annoying audible artifacts. For this purpose, the compressor has an additional set of controls called "Attack" and "Release". These are two parameters that control how fast does the compressor impose its limitation once the threshold has been crossed (Attack) and how fast does the compressor return to the initial amplification of 1:1 after the amplitude of the signal has returned below the predefined threshold. These three parameters, the threshold and attack and release times are what make the compressor "complex" in setting it up properly. Extreme values in these settings can result in more artifacts.

You may have "heard" a compressor working in radio shows. It is the effect that you hear when a speaker suddenly stops talking and after a very brief period of time the background sounds seem to rise in volume. When the speaker starts talking again, the background sounds seem to be diminishing abruptly again and the speaker's voice now dominates the dynamic range of the signal. That's the effect of a compressor.

The main idea here is that the compressor is making soft sounds louder and loud sounds softer.


  Note: The waveform is purely for visual purposes (the audio will not be played back to the user).


If you are not looking to actually apply dynamic range compression and you simply want to make sure that your viewer can see all details within a signal, you can apply a logarithmic transformation, which is very similar to how a compressor / limiter would operate but without the complexity of setting it up.

Given a signal $x(n)$, you can generate a signal $x_{transformed}$ with:

$$ x_{transformed}(n) = c \times log(1+x(n))$$

Where $c$ is a normalisation parameter. Due to its shape the $log(\cdot)$ function will boost small amplitude values and limit high amplitude values. To get a feel about how the waveform might look like, you might want to have a quick look at the way Audacity does its 'dB View' of waveforms.

You might find both the compression and logarithmic transformation concepts useful to what you are trying to achieve.

Hope this helps.