Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Conversion of WAV file to MP3 using LAME.
- #include <iostream>
- #include <fstream>
- #include <string>
- #include <vector>
- #include "lame.h"
- int main()
- {
- std::streampos size; // stream pointer
- char* memblock; // memory to store file bytes
- // Open with pointer at end of file
- std::ifstream file("C:\\jana\\csound\\projects\\building_csd_classes_output_files\\test.wav", std::ios::in | std::ios::binary | std::ios::ate);
- // for LAME
- std::vector<short int> data_left_channel;
- std::vector<short int> data_right_channel;
- short int* left_ptr = NULL;
- short int* right_ptr = NULL;
- int samples_per_channel = 0;
- int buffer_size = 0;
- std::vector<unsigned char> mp3_frame_vector;
- unsigned char* mp3_frames_ptr = NULL;
- if (file.is_open())
- {
- size = file.tellg(); // pointer at end is the number of bytes in the file
- std::cout << "This file is " << size << " bytes." << std::endl;
- memblock = new char[size];
- file.seekg(0);
- file.read(memblock, size);
- std::cout << "File container format: " << memblock[0] << memblock[1] << memblock[2] << memblock[3] << std::endl;
- int read_int = int((unsigned char)(memblock[7]) << 24 | // little endian
- (unsigned char)(memblock[6]) << 16 |
- (unsigned char)(memblock[5]) << 8 |
- (unsigned char)(memblock[4]));
- std::cout << "Number of bytes remaining in the file: " << read_int << std::endl;
- std::cout << "Data format: " << memblock[8] << memblock[9] << memblock[10] << memblock[11] << std::endl;
- std::cout << "Format tag: " << memblock[12] << memblock[13] << memblock[14] << memblock[15] << std::endl; // last should be a pad byte.
- read_int = int((unsigned char)(memblock[19]) << 24 | // little endian
- (unsigned char)(memblock[18]) << 16 |
- (unsigned char)(memblock[17]) << 8 |
- (unsigned char)(memblock[16]));
- std::cout << "The format information is " << read_int << " bytes." << std::endl;
- read_int = int((unsigned char)(memblock[21]) << 8 |
- (unsigned char)(memblock[20]));
- if (read_int == 1) std::cout << "Audio format is PCM." << std::endl; else { std::cout << "Throw unsupported format exception here: 'The data format doesn't appear to be PCM. This is the only supported format.'"; }
- read_int = int((unsigned char)(memblock[23]) << 8 |
- (unsigned char)(memblock[22]));
- std::string mono_or_stereo;
- if (read_int == 1) mono_or_stereo = "Mono";
- else if (read_int == 2) mono_or_stereo = "Stereo";
- else { std::cout << "Throw unsupported number of channels exception here: 'This audio file doesn't appear to be mono or stereo. These are the only supported types of audio file.'"; }
- std::cout << "Mono or stereo: " << mono_or_stereo << "." << std::endl;
- read_int = int((unsigned char)(memblock[27]) << 24 | // little endian
- (unsigned char)(memblock[26]) << 16 |
- (unsigned char)(memblock[25]) << 8 |
- (unsigned char)(memblock[24]));
- std::cout << "Sample rate: " << read_int << " Hz." << std::endl;
- read_int = int((unsigned char)(memblock[31]) << 24 | // little endian
- (unsigned char)(memblock[30]) << 16 |
- (unsigned char)(memblock[29]) << 8 |
- (unsigned char)(memblock[28]));
- std::cout << "Byte rate: " << read_int << " bytes/sec." << std::endl;
- read_int = int((unsigned char)(memblock[33]) << 8 |
- (unsigned char)(memblock[32]));
- std::cout << "Block align: " << read_int << "." << std::endl;
- read_int = int((unsigned char)(memblock[35]) << 8 |
- (unsigned char)(memblock[34]));
- std::cout << "Bits per sample: " << read_int << "." << std::endl;
- std::cout << "Data tag: " << memblock[36] << memblock[37] << memblock[38] << memblock[39] << std::endl;
- read_int = int((unsigned char)(memblock[43]) << 24 | // little endian
- (unsigned char)(memblock[42]) << 16 |
- (unsigned char)(memblock[41]) << 8 |
- (unsigned char)(memblock[40]));
- std::cout << "Size of audio data: " << read_int << " bytes." << std::endl;
- // For LAME, I need:
- // the left and right channel data in separate short int c arrays
- // int number of samples per channel
- // char* buffer, suggested size in bytes = 1.25 * num_samples + 7200
- // int size of buffer
- file.seekg(44); // beginning of the audio data
- int ctr = 44;
- std::vector<char> sample_left_channel; // a 2-byte sample
- short int current_sample = 0;
- while (file.tellg() < size) // Get the audio data for the left channel.
- {
- sample_left_channel.clear();
- sample_left_channel.push_back(file.get());
- file.seekg(++ctr);
- sample_left_channel.push_back(file.get());
- ctr += 3;
- file.seekg(ctr);
- current_sample = short int((unsigned char)(sample_left_channel[1]) << 8 | // little endian
- (unsigned char)(sample_left_channel[0]));
- data_left_channel.push_back(current_sample);
- }
- file.seekg(46);
- ctr = 46;
- std::vector<char> sample_right_channel; // a 2-byte sample
- while (file.tellg() < size) // Get the audio data for the right channel.
- {
- sample_right_channel.clear();
- sample_right_channel.push_back(file.get());
- file.seekg(++ctr);
- sample_right_channel.push_back(file.get());
- ctr += 3;
- file.seekg(ctr);
- current_sample = short int((unsigned char)(sample_right_channel[1]) << 8 | // little endian
- (unsigned char)(sample_right_channel[0]));
- data_right_channel.push_back(current_sample);
- }
- file.close();
- delete[] memblock;
- // arguments for lame_encode_buffer()
- left_ptr = data_left_channel.data();
- right_ptr = data_right_channel.data();
- samples_per_channel = data_right_channel.size();
- buffer_size = (1.25 * samples_per_channel) + 7200; // Suggested safe buffer size, from API.
- mp3_frame_vector.resize(buffer_size); // Create a vector the right size so I can get the array inside.
- mp3_frames_ptr = mp3_frame_vector.data();
- std::cout << std::endl << "Arguments done." << std::endl;
- }
- else std::cout << "File opening failed." << std::endl;
- // Initialize LAME.
- lame_global_flags* gfp;
- gfp = lame_init();
- lame_set_bWriteVbrTag(gfp, 0); // because I'm not writing the Xing VBR/INFO tag to the mp3 file (see after flush below)
- int init_result = lame_init_params(gfp);
- if (init_result >= 0)
- std::cout << "LAME initialization ok." << std::endl;
- // Encode the PCM data.
- int result = lame_encode_buffer(gfp, // global pointer
- left_ptr, right_ptr, // arrays of short int for left and right channels
- samples_per_channel, mp3_frames_ptr, buffer_size); // samples/channel, the encoded mp3 frames, size of mp3 buffer
- if (result >= 0) std::cout << "LAME output " << result << " bytes to mp3 buffer." << std::endl;
- else std::cout << "Something went wrong during encoding. LAME error code: " << result << std::endl;
- // The size of the buffer was calculated using a very safe calculation, mostly likely much more space than was needed.
- // Now removing any empty space at the end.
- std::cout << "Removing extra space at the end of the buffer ..." << std::endl;
- std::vector<unsigned char> smaller_buffer(result);
- unsigned char* mp3_frames_no_extra_space_ptr = smaller_buffer.data();
- for (int x = 0; x < result; ++x)
- {
- *(mp3_frames_no_extra_space_ptr + x) = *(mp3_frames_ptr + x); // Copy only mp3 frames to new buffer, omitting extra space.
- }
- std::cout << "Smaller buffer done." << std::endl;
- // Write the encoded data to disk.
- std::cout << "Writing mp3 data to disk ..." << std::endl;
- std::ofstream mp3_frames("mp3_test_output.mp3", std::ios::out | std::ios::binary);
- mp3_frames.write((char*)mp3_frames_no_extra_space_ptr, result); // mp3_frames.write((char*)mp3_frames_ptr, buffer_size);
- // Flush the buffer.
- int flush_result = lame_encode_flush(gfp, mp3_frames_no_extra_space_ptr, result);
- std::cout << "LAME flushed buffer and output an additional " << flush_result << " bytes to mp3 file." << std::endl;
- std::cout << "Finishing up ... " << std::endl;
- // Not writing the Xing VBR/INFO tag to the mp3 file. See initialization for call that goes with this one.
- lame_mp3_tags_fid(gfp, NULL);
- // Free data structures.
- lame_close(gfp);
- std::cout << "MP3 file complete." << std::endl;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement