Basic C++ tone generator I'm trying to learn C++ (with experience in C and Java, inter alia).
I wrote a program to output a waveform of multiple (superimposed) tones, each varying in pitch.

To execute:


Compilation: g++ -W -Wall -pedantic -std=c++11 main.cpp Tone.cpp
Running: ./a.out
Playing: aplay out -r 44100 -f S16_LE (or S16_BE if you're on a big-endian system)


What can I improve in terms of C++ style and idioms?
I tried to use RAII for my streams and collections, and I tried to avoid news and pointers.

A couple specific questions:


In write_sample, are the cast to (char *) and the sizeof divisions okay?
If not, what's the standard C++ way to write binary data to a file?
Is sizeof really even used in C++, or is this a discouraged C artifact?
What should be const vs. constexpr?
I used a C-style array for octaves in main, instead of std::array&lt;double, 7&gt;, because I like the automatic initializer counting and the iteration is easier.
Is this okay? What would be better?
Does C++ use size_t, int16_t, and the like?




Tone.hpp

#ifndef TONE_H
#define TONE_H

class Tone
{
    private:
        const double sampleRate;
        double s; /* current position along the unit sine curve */
        double lastSample;
    public:
        double getSample() const;
        double nextSample(double frequency, double amplitude);
        Tone(double sampleRate);
};

#endif


Tone.cpp

#include &lt;cmath&gt;
#include "Tone.hpp"

Tone::Tone(double sampleRate) : sampleRate(sampleRate), s(0), lastSample(0)
{
}

double Tone::getSample() const
{
    return this-&gt;lastSample;
}

double Tone::nextSample(double frequency, double amplitude)
{
    this-&gt;s += frequency / this-&gt;sampleRate;
    this-&gt;lastSample = amplitude * sin(2*M_PI * this-&gt;s);
    return this-&gt;lastSample;
}


main.cpp

#include &lt;cmath&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include "Tone.hpp"

void write_sample(std::ostream &amp;stream, double sample);

int main()
{
    constexpr double SAMPLE_RATE = 44100;
    std::vector&lt;Tone&gt; tones;

    // Each of these represents a final octave difference from A4
    const double octaves[] = { -2, 0, 4./12, 7./12, 1, 16./12, 19./12 };
    const size_t count = sizeof(octaves) / sizeof(*octaves);

    std::ofstream outfile("out", std::ofstream::binary);

    // Create a tone generator for each
    for (size_t i = 0; i &lt; count; i++)
    {
        tones.push_back(Tone(SAMPLE_RATE));
    }

    // Set parameters for the output sound
    double duration = 4.0;
    double attack = 1.0;
    double decay = 2.5;
    double amplitude = 0.8;

    // Generate the required samples
    for (double t = 0; t &lt; duration; t += 1 / SAMPLE_RATE)
    {
        // Interpolate with sinusoidal easing up to the attack time, then constant
        double interp = t &gt;= attack ? 1 : sin(M_PI/2 * t);

        // Constant until the decay time, then interpolate linearly out
        double strength = t &lt; (duration - decay) ? 1
            : 1 - (t - (duration - decay)) / decay;

        // Superimpose the samples from each tone generator
        double totalSample = 0;
        for (size_t i = 0; i &lt; count; i++)
        {
            double octave = interp * octaves[i];
            double frequency = 440 * pow(2, octave);
            double sample = tones[i].nextSample(frequency, strength * amplitude);
            totalSample += sample;
        }
        totalSample /= count;

        if (outfile.good())
        {
            write_sample(outfile, totalSample);
        }
        else
        {
            return 1;
        }
    }

    return 0;
}

// Writes a sample to the given output stream as a 16-bit signed integer.
void write_sample(std::ostream &amp;stream, double sample)
{
    int16_t output = (int16_t) (0x7FFF * sample);
    stream.write((char *) &amp;output, sizeof(int16_t) / sizeof(char));
}
Overall it looks fine for a newcomer, you've made proper use of const for variables and methods, which is something beginners tend to overlook.

A few points you can still work on:


For such a tiny class like Tone, I would not bother separating declaration from implementation and would have declared it inline in the header file only. That would be less boilerplate and easier to maintain. A word of caution though: Inline code can be better optimized by the compiler and is recommend for small methods (like get/set accessors), but don't overuse it. Too much inlining will increase compile-times and generate bloated executables. I don't recommend it as an optimization either, the gain is in reducing redundant/boilerplate code implicit in the prototype/implementation setup.
Prefixing in-class member access with this-&gt; is very rare in C++. You should only be doing that when, for instance, you need to disambiguate some shadowed member access (but even that is discouraged because shadowing members is a bit of a design flaw; better to uniquely identify your variables).
This is a personal preference, I find it better to declare public members of a class first, followed by protected and then private. My rationale is that the public section should have more emphasis, since it is what readers and users of my code will be interested on most of the time. Private/protected details are of interest for the implementer/maintainer, so they don't need to be visible right at the top of the file.
When using &lt;cmath&gt;, the correct way of referencing its functions, like sin/pow, is thru the std:: namespace. They happen to visible at the global level because on most compilers math.h (the C header) and cmath are implemented as wrappers to the same file. There is no requirement from the C++ Standard that this be implemented is such way, so a C++ compiler is not required to provide sin() outside the std namespace when including cmath.
Avoid using C-style casts. To cast numerical values, C++ provides static_cast. To cast pointers, reinterpret_cast is usually the operator to use. A quick overview on C++ cast operators.
Yes, size_t and int16_t are part of the Standard and are declared in &lt;cstddef&gt; and &lt;cstdint&gt; respectively. For ultimate correctness, they should be accessed from the std namespace, (e.g.: std::size_t, std:int16_t) for the same reasons cited on §4.
Your main() function is too long and doing too much. You should probably have another class, Sample perhaps, that holds the array of Tones. That class should provide methods for processing and have write_sample() as a member.
There is a much simpler way of initializing the tones vector. You can fill it with defaults on declaration using a parameterized constructor and eliminate the loop:

std::vector&lt;Tone&gt; tones(count, Tone(SAMPLE_RATE));

If you use an std::array you gain the size() method that knows the array length, which would remove the need for the sizeof() calculation, which is not the clearest thing you can do. Another way I tend to use for inferring the length of statically allocated arrays, without compromising readability, is by declaring a helper template function:

// Length in elements of type 'T' of statically allocated C++ arrays.
template&lt;class T, std::size_t N&gt;
constexpr std::size_t arrayLength(const T (&amp;)[N])
{
    return N;
}

...

const double octaves[] = { -2, 0, 4./12, 7./12, 1, 16./12, 19./12 };
const auto count = arrayLength(octaves);


constexpr will force the function to be evaluated at compile time, thus making it suitable for use in places a compile-time constant would be required.