I am currently working on mp3 decoding with javalayer 1.1.
So I want to receive the raw PCM data from my 44100 Hz, 16bit, Mp3s.
It is perfectly working fine with stereo mp3s, but i have strange issues with mono mp3s.
Here some code.
InputStream data = c.getResources().openRawResource(resId);
Bitstream bitstream = new Bitstream(data);
Decoder decoder = new Decoder();
while(thereIsData) {
Head frameHeader = bitstream.readFrame();
SampleBuffer buffer = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);
short[] pcmBuffer = buffer.getBuffer();
// Do some stuff with pcm (For example creating a wav file )
bitstream.closeFrame();
}
buffer.getChannelCount() == 1,
buffer.getFrequency() == 41000
So... The Problem is. If I create a 44100 Hz, mono Channel, 16-bit WaveFile and put it in Audacity to see the waves. The sound is periodically 0,like: (200ms Sound)...(200ms NoSound)...(200ms Sound)...(200ms NoSound)
This goes also for the pcm data before writing to .wav... (Yeahi syso all the stuff)
So one may think, well there got to be zero-frames or sth. in there... So I cut off all frames with only 0 values in it. This results in slighty shorter zero breaks in the wav file. Means to me, there must be partial zero frames.
So I cut ALL zero values from the pcm data... And as weird as it seems, this worked. The file sounds OK.
But this cant be the solution. I still dont know why there are these false zero values. And I need silence in my mp3's as well.
I'd appreciate every explanation hint. Thanks
I got it working, converting to byte[], using this code:
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
int divider = 1;
if (SAMPLE_RATE < 44100) divider *= 2;
if (CHANNELS == 1) divider *= 2;
[...]
short[] pcmBuffer = buffer.getBuffer();
for (int i=0; i<pcm.length/divider; i++) {
outStream.write(pcm[i] & 0xff);
outStream.write((pcm[i] >> 8 ) & 0xff);
}
The key was the divider parameter, that is 1 in stereo-44, 2 in mono-44 and 4 in mono-22. Didn't try yet other combinations.
Hm... My answer comes a bit late.. Sorry for that.
I completly solved the issue.
JLayer did some weird stuff.
If the input mp3 is Stereo, the values in the pcmbuffer are encoded like this:
leftchannel, rightchannel, leftchannel, ...
This is how it should be.
But if the input mp3 is Mono the I get the same amount of samples in the pcmbuffer.
But its not like:
monochannel, 0, monochannel, 0
The whole data is in the first half of the pcmbuffer and the second half is all 0. So you just need to cut off the second half.
Related
I'm using FFmpe's swr_convert to convert AV_SAMPLE_FMT_FLTP audio. I've been successful converting to a different sample format (e.g. AV_SAMPLE_FMT_FLT and AV_SAMPLE_FMT_S16), but I'm running into trouble when I'm trying to keep the AV_SAMPLE_FMT_FLTP sample format but change the sample rate.
When converting AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_FLTP, swr_convert attempts to write to an empty buffer.
I'm using swr_convert to convert from 22050 Hz AV_SAMPLE_FMT_FLTP to 16000 Hz AV_SAMPLE_FMT_FLTP.
I initialized SwrContext like so:
if (swr_alloc_set_opts2(
&resample_context,
&pAVContext->ch_layout, AV_SAMPLE_FMT_FLTP, 16000,
&pAVContext->ch_layout, AV_SAMPLE_FMT_FLTP, 22050, 0, NULL) < 0)
return ERR_SWR_INIT_FAIL;
if(swr_init(resample_context) < 0)
return ERR_SWR_INIT_FAIL;
and when I call it like this, the program tries to write to a null buffer and crashes.
samples_decoded = swr_convert(ctx->pSwrContext,
&pDecodedAudio, numOutSamples,
(const uint8_t**)&pDecodedFrame->data, pDecodedFrame->nb_samples);
So far I've traced the problem to swr_convert_internal
if(s->int_sample_fmt == s->out_sample_fmt && s->out.planar
&& !(s->out_sample_fmt==AV_SAMPLE_FMT_S32P && (s->dither.output_sample_bits&31))){
//Sample format is planar and input format is same as output format
if(preout==in){
out_count= FFMIN(out_count, in_count);
av_assert0(s->in.planar);
copy(out, in, out_count);
return out_count;
}
else if(preout==postin) preout= midbuf= postin= out;
else if(preout==midbuf) preout= midbuf= out;
else preout= out;
}
That if bit of code assigns out to preout, but out's data is unitialized. Later on FFmpeg tries to write to the uninitialized block.
I've tested this in 5.1 and in the snapshot build, and it crashes both of them.
So, am I doing something wrong, or is this a bug?
I was doing something wrong. Packet audio is a contiguous block of memory and can be referenced by one pointer, but planar audio has a different pointer to each channel. To fix this, I got two pointers to my pDecodedAudio block.
uint8_t* convertedData [2] = {
pDecodedAudio ,
pDecodedAudio + (numOutSamples * ctx->output_sample_size)
};
samples_decoded = swr_convert(ctx->pSwrContext,
convertedData, numOutSamples,
pDecodedFrame->data, pDecodedFrame->nb_samples);
See the comments in AVFrame.
/*
* For planar audio, each channel has a separate data pointer, and
* linesize[0] contains the size of each channel buffer.
* For packed audio, there is just one data pointer, and linesize[0]
* contains the total size of the buffer for all channels.
*
* Note: Both data and extended_data should always be set in a valid frame,
* but for planar audio with more channels that can fit in data,
* extended_data must be used in order to access all channels.
*/
uint8_t **extended_data;
I tried to encrypt image file with c++ with XOR encryption .
it worked well but when i decrypt it with the same code i can't open the image , i assume they are not the same but in XOR encryption they must be the same
here is the code
void xor_encrypt(std::string const& path) {
char key[65] = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08";
std::ifstream input{ path,std::ios::binary };
std::ofstream output;
output = std::ofstream{ path + ".hafnium", /*added*/ std::ios::binary };
char buffer[64];
while (input.read(buffer, 64)) {
for (size_t i = 0; i < 64; i++) {
buffer[i] ^= key[i];
}
output.write(buffer,/*added*/ input.gcount());
}
input.close();
std::remove(path.c_str());
}
and here the 3 files : original image , encrypted image and encrypted 2 times image
[1] original image : https://i.stack.imgur.com/VKHKU.jpg
[2] image encrypted 1 time : https://mega.nz/file/BUMG2I7K#G3PsUeYCwtTCOj2cYSH47t67_WafRZQsRHyIims-EW0
[3] image encrypted 2 times with xor : https://mega.nz/file/FUMywI5I#mvI6Ge2nEw19fDfTEVso7hKMFSggRJcGJ7_g9178LMQ
the only difference between files i see is that they hasn't the same size
why image encrypted 2 times with xor don't yield the same file ?
thanks for answers
EDIT : thanks for answers , it worked well for the image file but when i take other file like a video , it don't work anymore :
original video : https://mega.nz/file/BYU3hQJI#JugOnHZ6_ajnRqHqc18j_j54MqFoIXAUHITSMxbAo48
encrypted video : https://mega.nz/file/JAMFXCRK#DxYqKAvCqda18oC47qOH0Wiec1bmJ7hSlmypczS9LXE
encrypted 2 times video : https://mega.nz/file/VVUT1KiA#f0vf43PkEssAmoHuPIcY722kd1p7nvQheIlIwFkmrzk
This is actually some kind of buffer underflow.
The end of the file is the problem.
You read using input.read(buffer, 64) and the last time you execute this, it will likely read less than 64 chars but less.
Then, you still write 64 characters (you just write 64 chars from the array, with the content from before).
Use the following code that writes as much as you read:
while (input.read(buffer, 64)) {
for (size_t i = 0; i < 64; i++) {
buffer[i] ^= key[i];
}
output.write(buffer, input.gcount());
}
It uses gcount in order to count the number of characters read.
I would also recommand you writing binary if you have binary input, too.
output = std::ofstream{ path + ".hafnium",std::ios::binary };
dan1st already found the issue of not taking into account the actual number of bytes read, and the mention that you need to process both files in binary mode.
It's not a recommendation, if you expect the program to work properly on Windows, you need to do that (you might get away if only handling text, but then an odd file will come and bite you). However, I wanted to note three things.
The first issue I see is that the original file doesn't match. the imgur link doesn't provide the file you used (imgur may have reprocessed it).
Second, the encrypted files are losing bytes. The error of not counting the number of bytes read would make some of your files bigger (they would be padded to 64 bytes, with some plaintext bytes). I suspect this may have been caused by not using binary mode.
And third, you are using the hexadecimal key of 64 characters is doing what you expected. Your key is formed by the characters '9','f','8','6'... You are only xoring a few bits of the file. What you probably wanted to do is to xor with {0x9f, 0x86, 0xd0, 0x81, 0x88...}, i.e. you should be converting the hexadecimal string into bytes and xoring those. It could still be broken quite easily, but it would be the proper way to use this 256 bit-key.
I have to use Opus Codec to encode & decode audio datas in C++ and I have to encapsulate the functions.
So I try to send a floats array to try to encode it and I decode the result of the Opus encoding function. Unfortunately, the result is not the same and I get a table that contains no value from the initial table.
Here is my code.
Encapsulation:
std::vector<float> codec::OpusPlugin::decode(packet_t &packet) {
std::vector<float> out(BUFFER_SIZE * NB_CHANNELS);
int ret = 0;
if (!this->decoder)
throw Exception("Can't decode since there is no decoder.");
ret = opus_decode_float(this->decoder, packet.data.data(), packet.size, reinterpret_cast<float*>(out.data()), FRAME_SIZE, 0);
if (ret < 0)
throw Exception("Error while decoding compressed data.");
return out;
}
// ENCODER
packet_t codec::OpusPlugin::encode(std::vector<float> to_encode) {
std::vector<unsigned char> data(BUFFER_SIZE * NB_CHANNELS * 2);
packet_t packet;
int ret = 0;
if (!this->encoder)
throw Exception("Can't encode since there is no decoder.");
ret = opus_encode_float(this->encoder, reinterpret_cast<float const*>(to_encode.data()), FRAME_SIZE, data.data(), data.size());
if (ret < 0)
throw Exception("Error while encoding data.");
packet.size = ret;
packet.data = data;
return packet;
}
And there is the call of the functions:
packet_t packet;
std::vector<float> floats = {0.23, 0, -0.312, 0.401230, 0.1234, -0.1543};
packet = CodecPlugin->encode(floats);
std::cout << "packet size: " << packet.size << std::endl;
std::vector<float> output = CodecPlugin->decode(packet);
for (int i = 0; i < 10; i++) {
std::cout << output.data()[i] << " ";
}
Here is the packet_t structure, where I stock the return value of encode and the unsigned char array (encoded value)
typedef struct packet_s {
int size;
std::vector<unsigned char> data;
} packet_t;
The output of the program is
*-1.44487e-15 9.3872e-16 -1.42993e-14 7.31834e-15 -5.09662e-14 1.53629e-14 -8.36825e-14 3.9531e-14 -8.72754e-14 1.0791e-13 which is not the array I initialize at the beginning.
I read a lot of times the documentation and code examples but I don't know where I did a mistake.
I hope you will be able to help me.
Thanks :)
We don't see how you initialize your encoder and decoder so we don't know what their sample rate, complexity or number of channels is. No matter how you have initialized them you are still going to have the following problems:
First Opus encoding doesn't support arbitrary frame sizes but instead 2.5ms, 5ms, 10ms, 20, 40ms or 60ms RFC 6716 - Definition of the Opus Audio Codec relevant section 2.1.4. Moreover opus supports only 8kHz, 12kHz, 16kHz, 24kHz or 48kHz sample rates. No matter which of those you have chosen your array of 10 elements doesn't correspond to any of the supported frame sizes.
Secondly Opus codec is a lossy audio codec. This means that after you encode any signal you will never (probably except some edge cases) be able to reconstruct the original signal after decoding the encoded opus frame. The best way to test if your encoder and decoder work is with a real audio sample. Opus encoding preserves the perceptual quality of the audio files. Therefore if you try to test it with arbitrary data you might not get the expected results back even if you implemented the encoding and decoding functions correctly.
What you can easily do is to make a sine function of 2000Hz(there are multiple examples on the internet) for 20ms. This means 160 array elements at a sample rate of 8000Hz if you wish to use 8kHz. A sine wave of 2kHz is within the human hearing range so the encoder is going to preserve it. Then decode it back and see whether the elements of the input and output array are similar as we've already established that it is unlikely that they are the same.
I am not good in C++ so I can't help you with code examples but the problems above hold true no matter what language is used.
Hey all, I'm writing an application which records microphone input to a WAV file. Previously, I had written this to fill a buffer of a specified size and that worked fine. Now, I'd like to be able to record to an arbitrary length. Here's what I'm trying to do:
Set up 32 small audio buffers (circular buffering)
Start a WAV file with ofstream -- write the header with PCM length set to 0
Add a buffer to input
When a buffer completes, append its data to the WAV file and update the header; recycle the buffer
When the user hits "stop", write the remaining buffers to file and close
It kind of works in that the files are coming out to the correct length (header and file size and are correct). However, the data is wonky as hell. I can make out a semblance of what I said -- and the timing is correct -- but there's this repetitive block of distortion. It basically sounds like only half the data is getting into the file.
Here are some variables the code uses (in header)
// File writing
ofstream mFile;
WAVFILEHEADER mFileHeader;
int16_t * mPcmBuffer;
int32_t mPcmBufferPosition;
int32_t mPcmBufferSize;
uint32_t mPcmTotalSize;
bool mRecording;
Here is the code that prepares the file:
// Start recording audio
void CaptureApp::startRecording()
{
// Set flag
mRecording = true;
// Set size values
mPcmBufferPosition = 0;
mPcmTotalSize = 0;
// Open file for streaming
mFile.open("c:\my.wav", ios::binary|ios::trunc);
}
Here's the code that receives the buffer. This assumes the incoming data is correct -- it should be, but I haven't ruled out that it isn't.
// Append file buffer to output WAV
void CaptureApp::writeData()
{
// Update header with new PCM length
mPcmBufferPosition *= sizeof(int16_t);
mPcmTotalSize += mPcmBufferPosition;
mFileHeader.bytes = mPcmTotalSize + sizeof(WAVFILEHEADER);
mFileHeader.pcmbytes = mPcmTotalSize;
mFile.seekp(0);
mFile.write(reinterpret_cast<char *>(&mFileHeader), sizeof(mFileHeader));
// Append PCM data
if (mPcmBufferPosition > 0)
{
mFile.seekp(mPcmTotalSize - mPcmBufferPosition + sizeof(WAVFILEHEADER));
mFile.write(reinterpret_cast<char *>(&mPcmBuffer), mPcmBufferPosition);
}
// Reset file buffer position
mPcmBufferPosition = 0;
}
And this is the code that closes the file:
// Stop recording
void CaptureApp::stopRecording()
{
// Save remaining data
if (mPcmBufferSize > 0)
writeData();
// Close file
if (mFile.is_open())
{
mFile.flush();
mFile.close();
}
// Turn off recording flag
mRecording = false;
}
If there's anything here that looks like it would result in bad data getting appended to the file, please let me know. If not, I'll triple check the input data (in the callback). This data should be good, because it works if I copy it to a larger buffer (eg, two minutes) and then save that out.
I am just wondering, how
void CaptureApp::writeData()
{
mPcmBufferPosition *= sizeof(int16_t); // mPcmBufferPosition = 0, so 0*2 = 0;
// (...)
mPcmBufferPosition = 0;
}
works (btw. sizeof int16_t is always 2). Are you setting mPcmBufferPosition somewhere else?
void CaptureApp::writeData()
{
// Update header with new PCM length
long pos = mFile.tellp();
mPcmBufferBytesToWrite *= 2;
mPcmTotalSize += mPcmBufferBytesToWrite;
mFileHeader.bytes = mPcmTotalSize + sizeof(WAVFILEHEADER);
mFileHeader.pcmbytes = mPcmTotalSize;
mFile.seekp(0);
mFile.write(reinterpret_cast<char *>(&mFileHeader), sizeof(mFileHeader));
mFile.seekp(pos);
// Append PCM data
if (mPcmBufferBytesToWrite > 0)
mFile.write(reinterpret_cast<char *>(mPcmBuffer), mPcmBufferBytesToWrite);
}
Also mPcmBuffer is a pointer, so don't know why you use & in write.
The most likely reason is you're writing from the address of the pointer to your buffer, not from the buffer itself. Ditch the "&" in the final mFile.write. (It may have some good data in it if your buffer is allocated nearby and you happen to grab a chunk of it, but that's just luck that your write hapens to overlap your buffer)
In general, if you find yourself in this sort of situation, you could try to think how you can test this code in isolation from the recording code: Set up a buffer that has the values 0..255 in it, and then set your "chunk size" to 16 and see if it writes out a continuous sequence of 0..255 across 16 separate write operations. That will quickly verify if your buffering code is working or not.
I won't debug your code, but will try to give you checklist of the things you can try to check and determine where's the error:
always have referent recorder or player handy. It can be something as simple as Windows Sound Recorder, or Audacity, or Adobe Audition. Have a recorder/player that you are CERTAIN that will record and play files correctly.
record the file with your app and try to play it with reference player. Working?
try to record the file with reference recorder, and play it with your player. Working?
when you write SOUND data to the WAV file in your recorder, write it to one extra file. Open that file in RAW mode with the player (Windows Sound Recorder won't be enough here). Does it play correctly?
when playing the file in your player, and writing to the soundcard, write output to the RAW file, to see if you are playing the data correctly at all or you have soundcars issues. Does it play correctly?
Try all this, and you'll have much better idea of where something went wrong.
Shoot, sorry -- had a late night of work and am a bit off today. I forgot to show y'all the actual callback. This is it:
// Called when buffer is full
void CaptureApp::onData(float * data, int32_t & size)
{
// Check recording flag and buffer size
if (mRecording && size <= BUFFER_LENGTH)
{
// Save the PCM data to file and reset the array if we
// don't have room for this buffer
if (mPcmBufferPosition + size >= mPcmBufferSize)
writeData();
// Copy PCM data to file buffer
copy(mAudioInput.getData(), mAudioInput.getData() + size, mPcmBuffer + mPcmBufferPosition);
// Update PCM position
mPcmBufferPosition += size;
}
}
Will try y'alls advice and report.
I have several Gb of sample data captured 'in-the-field' at 48ksps using an NI Data Acquisition module. I would like to create a WAV file from this data.
I have done this previously using MATLAB to load the data, normalise it to the 16bit PCM range, and then write it out as a WAV file. However MATLAB baulks at the file size as it does everything 'in-memory'.
I would ideally do this in C++ or C, (C# is an option), or if there is an existing utility I'd use that. Is there a simple way (i.e. an existing library) to take a raw PCM buffer, specify the sample rate, bit depth, and package it into a WAV file?
To handle the large data set, it would need to be able to append data in chunks as it would not necessarily be possible to read the whole set into memory.
I understand that I could do this from scratch using the format specification, but I do not want to re-invent the wheel, or spend time fixing bugs on this if I can help it.
Interesting, I have found a bug on stackoverflow parse of code, it dont support the \ character at the end of the line like you see below, sad
//stolen from OGG Vorbis pcm to wav conversion rountines, sorry
#define VERSIONSTRING "OggDec 1.0\n"
static int quiet = 0;
static int bits = 16;
static int endian = 0;
static int raw = 0;
static int sign = 1;
unsigned char headbuf[44]; /* The whole buffer */
#define WRITE_U32(buf, x) *(buf) = (unsigned char)((x)&0xff);\
*((buf)+1) = (unsigned char)(((x)>>8)&0xff);\
*((buf)+2) = (unsigned char)(((x)>>16)&0xff);\
*((buf)+3) = (unsigned char)(((x)>>24)&0xff);
#define WRITE_U16(buf, x) *(buf) = (unsigned char)((x)&0xff);\
*((buf)+1) = (unsigned char)(((x)>>8)&0xff);
/*
* Some of this based on ao/src/ao_wav.c
*/
static int
write_prelim_header (FILE * out, int channels, int samplerate)
{
int knownlength = 0;
unsigned int size = 0x7fffffff;
// int channels = 2;
// int samplerate = 44100;//change this to 48000
int bytespersec = channels * samplerate * bits / 8;
int align = channels * bits / 8;
int samplesize = bits;
if (knownlength)
size = (unsigned int) knownlength;
memcpy (headbuf, "RIFF", 4);
WRITE_U32 (headbuf + 4, size - 8);
memcpy (headbuf + 8, "WAVE", 4);
memcpy (headbuf + 12, "fmt ", 4);
WRITE_U32 (headbuf + 16, 16);
WRITE_U16 (headbuf + 20, 1); /* format */
WRITE_U16 (headbuf + 22, channels);
WRITE_U32 (headbuf + 24, samplerate);
WRITE_U32 (headbuf + 28, bytespersec);
WRITE_U16 (headbuf + 32, align);
WRITE_U16 (headbuf + 34, samplesize);
memcpy (headbuf + 36, "data", 4);
WRITE_U32 (headbuf + 40, size - 44);
if (fwrite (headbuf, 1, 44, out) != 44)
{
printf ("ERROR: Failed to write wav header: %s\n", strerror (errno));
return 1;
}
return 0;
}
static int
rewrite_header (FILE * out, unsigned int written)
{
unsigned int length = written;
length += 44;
WRITE_U32 (headbuf + 4, length - 8);
WRITE_U32 (headbuf + 40, length - 44);
if (fseek (out, 0, SEEK_SET) != 0)
{
printf ("ERROR: Failed to seek on seekable file: %s\n",
strerror (errno));
return 1;
}
if (fwrite (headbuf, 1, 44, out) != 44)
{
printf ("ERROR: Failed to write wav header: %s\n", strerror (errno));
return 1;
}
return 0;
}
I think you can use libsox for this.
I came across a function called WAVAPPEND on Mathworks' File Exchange site a while ago. I never got around to using it, so I'm not sure if it works or is appropriate for what you're trying to do, but perhaps it'll be useful to you.
Okay... I'm 5 years late here... but I just did this for myself and wanted to put the solution out there!
I had the same issue with running out of memory while writing large wav files in matlab. I got around this by editing the matlab wavwrite function so it pulls data from your harddrive using memmap instead of variables stored on the RAM, then saving it as a new function. This will save you a lot of trouble, as you don't have to worry about dealing with headers when writing the wav file from scratch, and you wont need any external applications.
1) type edit wavwriteto see the code for the function, then save a copy of it as a new function.
2) I modified the y variable in the wavwrite function from an array containing the wav data to a cell array with strings pointing to the locations for the data of each channel saved on my harddrive. Use fwrite to store your wav data on the harddrive first of course. At the beginning of the function I transformed the file locations stored in y into memmap variables and defined the number of channels and samples like so:
replace these lines:
% If input is a vector, force it to be a column:
if ndims(y) > 2,
error(message('MATLAB:audiovideo:wavwrite:invalidInputFormat'));
end
if size(y,1)==1,
y = y(:);
end
[samples, channels] = size(y);
with this:
% get num of channels
channels = length(y);
%Convert y from strings pointing to wav data to mammap variables allowing access to the data
for i = 1:length(y)
y{i} = memmapfile(y{i},'Writable',false,'Format','int16');
end
samples = length(y{1}.Data);
3) Now you can edit the private function write_wavedat(fid,fmt). This is the function that writes the wav data. Turn it into a nested function so that it can read your y memmap variable as a global variable, instead of passing the value to the function and eating up your RAM, then you can make some changes like this:
replace the lines which write the wav data:
if (fwrite(fid, reshape(data',total_samples,1), dtype) ~= total_samples),
error(message('MATLAB:audiovideo:wavewrite:failedToWriteSamples'));
end
with this:
%Divide data into smaller packets for writing
packetSize = 30*(5e5); %n*5e5 = n Mb of space required
packets = ceil(samples/packetSize);
% Write data to file!
for i=1:length(y)
for j=1:packets
if j == packets
fwrite(fid, y{i}.Data(((j-1)*packetSize)+1:end), dtype);
else
fwrite(fid, y{i}.Data(((j-1)*packetSize)+1:j*packetSize), dtype);
end
disp(['...' num2str(floor(100*((i-1)*packets + j)/(packets*channels))) '% done writing file...']);
end
end
This will incrementally copy the data from each memmap variable into the wavfile
4) That should be it! You can leave the rest of the code as is, as it'll write the headers for you. Heres an example of how you'd write a large 2 channel wav file with this function:
wavwriteModified({'c:\wavFileinputCh1' 'c:\wavFileinputCh2'},44100,16,'c:\output2ChanWavFile');
I can verify this approach works, as I just wrote a 800mB 4 channel wav file with my edited wavwrite function, when matlab usually throws an out of memmory error for writing wav files larger then 200mb for me.
C# would be a good choice for this. FileStreams are easy to work with, and could be used for reading and writing the data in chunks. Also, reading WAV file headers is a relatively complicated task (you have to search for RIFF chunks and so on), but writing them is cake (you just fill out a header structure and write it at the beginning of the file).
There are a number of libraries that do conversions like this, but I'm not sure they can handle the huge data sizes you're talking about. Even if they do, you would probably still have to do some programming work to feed smaller chunks of raw data to these libraries.
For writing your own method, normalization isn't difficult, and even resampling from 48ksps to 44.1ksps is relatively simple (assuming you don't mind linear interpolation). You would also presumably have greater control over the output, so it would be easier to create a set of smaller WAV files, instead of one gigantic one.
The current Windows SDK audio capture samples capture data from the microphone and save the captured data to a .WAV file. The code is far from optimal but it should work.
Note that RIFF files (.WAV files are RIFF files) are limited to 4G in size.