Skip to content

Instantly share code, notes, and snippets.

@bit-hack
Created September 3, 2016 11:50
Show Gist options
  • Save bit-hack/436f7145caafbc5af2c628cfd247e648 to your computer and use it in GitHub Desktop.
Save bit-hack/436f7145caafbc5af2c628cfd247e648 to your computer and use it in GitHub Desktop.
Simple Wave file to AIFF converter
#include "file.h"
#include <memory>
#if !defined(_MSC_VER)
#define PACK__ __attribute__((__packed__))
#else
#define PACK__
#pragma pack(push, 1)
#endif
struct sound_t {
uint32_t length_;
std::unique_ptr<int8_t[]> samples_;
uint32_t sample_rate_;
uint32_t bit_depth_;
uint32_t channels_;
};
namespace {
constexpr uint32_t fourcc(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
return (d<<24)|(c<<16)|(b<<8)|a;
}
template <typename type_t>
type_t endian(type_t in) {
uint8_t * p = reinterpret_cast<uint8_t*>(&in);
const size_t size = sizeof(type_t);
for (int i = 0; i<size/2; ++i) {
uint8_t & a = p[i];
uint8_t & b = p[(size-1)-i];
uint8_t temp = a;
a = b;
b = temp;
}
return in;
}
} // namespace {}
bool load_wav(const char * path, sound_t & out) {
file_reader_t file;
if (!file.open(path)) {
return false;
}
struct PACK__ {
uint32_t chunk_id_;
uint32_t chunk_size_;
uint32_t format_;
} riff;
struct PACK__ {
uint32_t chunk_id_;
uint32_t chunk_size_;
uint16_t format_;
uint16_t channels_;
uint32_t sample_rate_;
uint32_t byte_rate_;
uint16_t block_align_;
uint16_t bit_depth_;
} fmt;
struct PACK__ {
uint32_t chunk_id_;
uint32_t chunk_size_;
/* after starts sample data */
} data;
// read riff header
if (!file.read(riff)) {
return false;
}
if (riff.chunk_id_!=fourcc('R', 'I', 'F', 'F')) {
return false;
}
if (riff.format_!=fourcc('W', 'A', 'V', 'E')) {
return false;
}
// read format chunk
if (!file.read(fmt)) {
return false;
}
if (fmt.chunk_id_!=fourcc('f', 'm', 't', ' ')) {
return false;
}
// read data chunk
if (!file.read(data)) {
return false;
}
if (data.chunk_id_!=fourcc('d', 'a', 't', 'a')) {
return false;
}
// sanity check format
if (fmt.bit_depth_%8 /* multiple of 8 */) {
return false;
}
if (fmt.channels_>2) {
return false;
}
// sanity check on file size
size_t file_size = 0;
if (!file.size(file_size)) {
return false;
}
if (data.chunk_size_>=file_size) {
return false;
}
// read sample data
std::unique_ptr<int8_t[]> buffer;
buffer.reset(new int8_t[data.chunk_size_]);
if (!file.read(buffer.get(), data.chunk_size_)) {
return false;
}
// copy into output structure
out.bit_depth_ = fmt.bit_depth_;
out.sample_rate_ = fmt.sample_rate_;
out.length_ = data.chunk_size_;
out.channels_ = fmt.channels_;
out.samples_.reset(buffer.release());
/* success */
return true;
}
bool save_aif(const char * path, const sound_t & in) {
struct PACK__ {
uint32_t a_;
uint32_t size_;
uint32_t b_;
} header;
struct PACK__ {
uint32_t id_;
uint32_t size_;
uint16_t channels_;
uint32_t frames_;
uint16_t bit_depth_;
uint8_t sample_rate_[10];
} comm;
struct PACK__ {
uint32_t id_;
uint32_t size_;
uint16_t offset_;
uint16_t blocksize_;
} ssnd;
/* open file for writing */
file_writer_t file;
if (!file.open(path)) {
return false;
}
/* write aiff header */
header.a_ = fourcc('F', 'O', 'R', 'M');
header.size_ = endian<uint32_t>(4 + sizeof(comm) + sizeof(ssnd) + in.length_);
header.b_ = fourcc('A', 'I', 'F', 'F');
if (!file.write(header)) {
return false;
}
/* write common header */
comm.id_ = fourcc('C', 'O', 'M', 'M');
comm.size_ = endian<uint32_t>(sizeof(comm)-8);
comm.channels_ = endian<uint16_t>(in.channels_);
comm.frames_ = endian<uint32_t>(in.length_ / ((in.bit_depth_ / 8) * in.channels_));
comm.bit_depth_ = endian<uint16_t>(in.bit_depth_);
const uint8_t C_44100[] = {0x40, 0x0E, 0xAC, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
memcpy_s(&comm.sample_rate_, 10, C_44100, sizeof(C_44100));
if (!file.write(comm)) {
return false;
}
/* write sound chunk header */
ssnd.id_ = fourcc('S', 'S', 'N', 'D');
ssnd.size_ = endian<uint32_t>(sizeof(comm) + in.length_ - 8);
ssnd.offset_ = 0;
ssnd.blocksize_ = 0;
if (!file.write(ssnd)) {
return false;
}
#if 0
/* write sample data */
if (!file.write(in.samples_.get(), in.length_)) {
return false;
}
#else
switch (in.bit_depth_) {
case(8):
for (uint32_t i = 0; i<in.length_; ++i) {
uint8_t sample = in.samples_.get()[i];
sample += 127;
file.write<uint8_t>(sample);
}
break;
default:
return false;
}
#endif
/* success */
return true;
}
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
int main(const int argc, char *args[]) {
if (argc<3) {
printf("%s input.wav output.aiff\n", args[0]);
return 1;
}
sound_t sound;
if (!load_wav(args[1], sound)) {
printf("error loading wave\n");
return 1;
}
if (!save_aif(args[2], sound)) {
printf("error saving aiff\n");
return 1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment