cog/Frameworks/libsidplay/sidplay-residfp-code/.svn/pristine/68/68def4aa35dd4a40d71da7e9f4c...

199 lines
5.3 KiB
Plaintext
Raw Normal View History

/*
* This file is part of sidplayfp, a SID player.
*
* Copyright 2011-2016 Leandro Nini <drfiemost@users.sourceforge.net>
* Copyright 2007-2010 Antti Lankila
* Copyright 2000-2004 Simon White
* Copyright 2000 Michael Schwendt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "WavFile.h"
#include <vector>
#include <iomanip>
#include <fstream>
#include <new>
// Get the lo byte (8 bit) in a dword (32 bit)
inline uint8_t endian_32lo8 (uint_least32_t dword)
{
return (uint8_t) dword;
}
// Get the hi byte (8 bit) in a dword (32 bit)
inline uint8_t endian_32hi8 (uint_least32_t dword)
{
return (uint8_t) (dword >> 8);
}
// Get the hi word (16bit) in a dword (32 bit)
inline uint_least16_t endian_32hi16 (uint_least32_t dword)
{
return (uint_least16_t) (dword >> 16);
}
// Get the lo byte (8 bit) in a word (16 bit)
inline uint8_t endian_16lo8 (uint_least16_t word)
{
return (uint8_t) word;
}
// Set the hi byte (8 bit) in a word (16 bit)
inline uint8_t endian_16hi8 (uint_least16_t word)
{
return (uint8_t) (word >> 8);
}
// Write a little-endian 16-bit word to two bytes in memory.
inline void endian_little16 (uint8_t ptr[2], uint_least16_t word)
{
ptr[0] = endian_16lo8 (word);
ptr[1] = endian_16hi8 (word);
}
// Write a little-endian 32-bit word to four bytes in memory.
inline void endian_little32 (uint8_t ptr[4], uint_least32_t dword)
{
uint_least16_t word = 0;
ptr[0] = endian_32lo8 (dword);
ptr[1] = endian_32hi8 (dword);
word = endian_32hi16 (dword);
ptr[2] = endian_16lo8 (word);
ptr[3] = endian_16hi8 (word);
}
const wavHeader WavFile::defaultWavHdr = {
// ASCII keywords are hex-ified.
{0x52,0x49,0x46,0x46}, {0,0,0,0}, {0x57,0x41,0x56,0x45},
{0x66,0x6d,0x74,0x20}, {16,0,0,0},
{1,0}, {0,0}, {0,0,0,0}, {0,0,0,0}, {0,0}, {0,0},
{0x64,0x61,0x74,0x61}, {0,0,0,0}
};
WavFile::WavFile(const std::string &name) :
AudioBase("WAVFILE"),
name(name),
wavHdr(defaultWavHdr),
file(nullptr),
headerWritten(false),
precision(32)
{}
bool WavFile::open(AudioConfig &cfg)
{
precision = cfg.precision;
unsigned short bits = precision;
unsigned short format = (precision == 16 ) ? 1 : 3;
unsigned short channels = cfg.channels;
unsigned long freq = cfg.frequency;
unsigned short blockAlign = (bits>>3)*channels;
unsigned long bufSize = freq * blockAlign;
cfg.bufSize = bufSize;
if (name.empty())
return false;
if (file && !file->fail())
close();
byteCount = 0;
// We need to make a buffer for the user
try
{
_sampleBuffer = new short[bufSize];
}
catch (std::bad_alloc const &ba)
{
setError("Unable to allocate memory for sample buffers.");
return false;
}
// Fill in header with parameters and expected file size.
endian_little32(wavHdr.length, sizeof(wavHeader)-8);
endian_little16(wavHdr.channels, channels);
endian_little16(wavHdr.format, format);
endian_little32(wavHdr.sampleFreq, freq);
endian_little32(wavHdr.bytesPerSec, freq*blockAlign);
endian_little16(wavHdr.blockAlign, blockAlign);
endian_little16(wavHdr.bitsPerSample, bits);
endian_little32(wavHdr.dataChunkLen, 0);
if (name.compare("-") == 0)
{
file = &std::cout;
}
else
{
file = new std::ofstream(name.c_str(), std::ios::out|std::ios::binary|std::ios::trunc);
}
_settings = cfg;
return true;
}
bool WavFile::write()
{
if (file && !file->fail())
{
unsigned long int bytes = _settings.bufSize;
if (!headerWritten)
{
file->write((char*)&wavHdr,sizeof(wavHeader));
headerWritten = true;
}
/* XXX endianness... */
if (precision == 16)
{
bytes *= 2;
file->write((char*)_sampleBuffer, bytes);
}
else
{
std::vector<float> buffer(_settings.bufSize);
bytes *= 4;
for (unsigned long i=0;i<_settings.bufSize;i++)
{
buffer[i] = ((float)_sampleBuffer[i])/32768.f;
}
file->write((char*)&buffer.front(), bytes);
}
byteCount += bytes;
}
return true;
}
void WavFile::close()
{
if (file && !file->fail())
{
endian_little32(wavHdr.length, byteCount+sizeof(wavHeader)-8);
endian_little32(wavHdr.dataChunkLen, byteCount);
if (file != &std::cout)
{
file->seekp(0, std::ios::beg);
file->write((char*)&wavHdr, sizeof(wavHeader));
delete file;
}
file = nullptr;
delete[] _sampleBuffer;
}
}