How to create a .WAV file from scratch.

Hello, all.

I wish to code a program that can create a .WAV file using nothing but information either I provide or the program calculates.

I have the specification, but I am not sure how to go about building the file. I do not want to use libraries or prewritten classes. I would like to learn how to do this myself before relying on any pre written tools. I will use a library or class after though, for perfomance, of course.

Thank you for your time and if I need to give more info, I will do so as soon as I can.
You basically have the tools to do it. The only tripping point is that the first chunk "contains" or "wraps" all the remaining chunks.

The main trick is that you must open the file in binary mode and write the exact bytes necessary for the file format.

Writing the strings ("RIFF", "WAVE", "fmt ", etc) to file is easy.

Just make sure you write the numbers to file properly. Having some functions to do that are really useful. Like these: http://www.cplusplus.com/forum/beginner/31584/#msg171056

Also, a hint: Write a dummy value to the RIFF chunk size. Then, after you have written everything to file, use f.tellp() to get the file size, then f.seekp(4) and write the file size in bytes - 8 to that position.

Hope this helps.
Thanks for the reply. Imma try and create a simple, minimal .WAV file. I have never messed with endianness at all.
Well, you'll have to pay attention to it. Wave files are little-endian.
Ok. I have tried several methods to create a wave file, but nothing seems to be working. I have yet to find a tutorial that covers the .wav file in enough detail for a novice to do. Does anyone know of any books or online sources that cover .wav creation in C++?

I am not asking for code, I just want to learn. I was able to make something that opens in VLC, but it never truly works.
Well, that book was a no go. It is a great read if you are making hardware or programming to read or edit .wavs, but not one mention of how to create them. It never even mentioned little endian at all.

Imma still looking though.

Seems everybody has code to read/convert/edit/mix/etc .wavs, but nothing on created them.
Sorry it took so long to get back to you, but here's an example to get you going.

It's a C4 tone fading from left to right for 2.5 seconds. You can see in the code how all these numbers work.

The wave file generated is a standard PCM, 16-bit, stereo file. (Everything that claims to play wave files should be able to play that.)

The waveform itself is a simple sine wave.

Remember, you have to know something about waveforms to generate sounds. This example is exceedingly primitive -- if you want to generate, say, music, you'll need to know how to play with sampled waveform data!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <cmath>
#include <fstream>
#include <iostream>
using namespace std;

namespace little_endian_io
{
  template <typename Word>
  std::ostream& write_word( std::ostream& outs, Word value, unsigned size = sizeof( Word ) )
  {
    for (; size; --size, value >>= 8)
      outs.put( static_cast <char> (value & 0xFF) );
    return outs;
  }
}
using namespace little_endian_io;

int main()
{
  ofstream f( "example.wav", ios::binary );

  // Write the file headers
  f << "RIFF----WAVEfmt ";     // (chunk size to be filled in later)
  write_word( f,     16, 4 );  // no extension data
  write_word( f,      1, 2 );  // PCM - integer samples
  write_word( f,      2, 2 );  // two channels (stereo file)
  write_word( f,  44100, 4 );  // samples per second (Hz)
  write_word( f, 176400, 4 );  // (Sample Rate * BitsPerSample * Channels) / 8
  write_word( f,      4, 2 );  // data block size (size of two integer samples, one for each channel, in bytes)
  write_word( f,     16, 2 );  // number of bits per sample (use a multiple of 8)

  // Write the data chunk header
  size_t data_chunk_pos = f.tellp();
  f << "data----";  // (chunk size to be filled in later)
  
  // Write the audio samples
  // (We'll generate a single C4 note with a sine wave, fading from left to right)
  constexpr double two_pi = 6.283185307179586476925286766559;
  constexpr double max_amplitude = 32760;  // "volume"

  double hz        = 44100;    // samples per second
  double frequency = 261.626;  // middle C
  double seconds   = 2.5;      // time

  int N = hz * seconds;  // total number of samples
  for (int n = 0; n < N; n++)
  {
    double amplitude = (double)n / N * max_amplitude;
    double value     = sin( (two_pi * n * frequency) / hz );
    write_word( f, (int)(                 amplitude  * value), 2 );
    write_word( f, (int)((max_amplitude - amplitude) * value), 2 );
  }
  
  // (We'll need the final file size to fix the chunk sizes above)
  size_t file_length = f.tellp();

  // Fix the data chunk header to contain the data size
  f.seekp( data_chunk_pos + 4 );
  write_word( f, file_length - data_chunk_pos + 8 );

  // Fix the file header to contain the proper RIFF chunk size, which is (file size - 8) bytes
  f.seekp( 0 + 4 );
  write_word( f, file_length - 8, 4 ); 
}

Hope this helps.
Topic archived. No new replies allowed.