chromium/chromecast/media/audio/wav_header.h

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMECAST_MEDIA_AUDIO_WAV_HEADER_H_
#define CHROMECAST_MEDIA_AUDIO_WAV_HEADER_H_

#include <stdint.h>

namespace chromecast {
namespace media {

// This is a header for a .wav file. It can be written directly to file (e.g.
// with reinterpret_cast<char*>) after SetDataSize(), SetNumChannels(), and
// SetSampleRate() have been called. It defaults to contain float-point data.
// From http://soundfile.sapp.org/doc/WaveFormat/ and
// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
struct __attribute__((packed)) WavHeader {
  const char riff[4] = {'R', 'I', 'F', 'F'};
  uint32_t chunk_size;  // size of file - 8
  const char wave[4] = {'W', 'A', 'V', 'E'};
  const char fmt[4] = {'f', 'm', 't', ' '};
  const uint32_t subchunk_size = 18;
  uint16_t audio_format = 3;  // FLOAT
  uint16_t num_channels;
  uint32_t sample_rate;
  uint32_t byte_rate;    // sample_rate * num_channels * bytes per sample
  uint16_t block_align;  // num_channels * bytes per sample
  uint16_t bits_per_sample = 32;
  uint16_t extension_size = 0;
  const char data[4] = {'d', 'a', 't', 'a'};
  uint32_t subchunk_2_size;  // bytes in the data

  enum AudioFormat { kInteger8, kInteger16, kInteger32, kFloat32 };

  WavHeader();
  ~WavHeader() = default;

  void SetAudioFormat(AudioFormat audio_format_in) {
    switch (audio_format_in) {
      case kInteger8:
        audio_format = 1;
        bits_per_sample = 8;
        break;
      case kInteger16:
        audio_format = 1;
        bits_per_sample = 16;
        break;
      case kInteger32:
        audio_format = 1;
        bits_per_sample = 32;
        break;
      case kFloat32:
        audio_format = 3;
        bits_per_sample = 32;
        break;
    }
    byte_rate = sample_rate * num_channels * bits_per_sample / 8;
    block_align = num_channels * bits_per_sample / 8;
  }

  void SetDataSize(int size_bytes) {
    chunk_size = 36 + size_bytes;
    subchunk_2_size = size_bytes;
  }

  void SetNumChannels(int num_channels_in) {
    num_channels = num_channels_in;
    byte_rate = sample_rate * num_channels * bits_per_sample / 8;
    block_align = num_channels * bits_per_sample / 8;
  }

  void SetSampleRate(int sample_rate_in) {
    sample_rate = sample_rate_in;
    byte_rate = sample_rate * num_channels * bits_per_sample / 8;
  }
};

inline WavHeader::WavHeader() = default;

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_AUDIO_WAV_HEADER_H_