/* * CINELERRA * Copyright (C) 2008 Adam Williams * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "asset.h" #include "byteorder.h" #include "file.h" #include "filebase.h" int64_t FileBase::samples_to_raw(char *out_buffer, float **in_buffer, int64_t input_len, int bits, int channels, int byte_order, int signed_) { int output_advance; // number of bytes in a sample float *buffer_channel; // channel in input buffer float *buffer_channel_end; int channel; int64_t int_sample, int_sample2; float float_sample; int64_t dither_value, dither_scale = 255; int64_t bytes = input_len * channels * (file->bytes_per_sample(bits)); int machine_byte_order = get_byte_order(); switch(bits) { case BITSLINEAR8: { char *output_ptr, *output_end; output_advance = channels; for(channel = 0; channel < channels; channel++) { output_ptr = out_buffer + channel; buffer_channel = in_buffer[channel]; buffer_channel_end = buffer_channel + input_len; if(dither) { for( ; buffer_channel < buffer_channel_end; buffer_channel++) { float_sample = *buffer_channel * 0x7fff; int_sample = (int64_t)float_sample; if(int_sample > -0x7f00) { dither_value = rand() % dither_scale; int_sample -= dither_value; } int_sample /= 0x100; // rotating bits screws up the signs *output_ptr = int_sample; output_ptr += output_advance; } } else { for( ; buffer_channel < buffer_channel_end; buffer_channel++) { float_sample = *buffer_channel * 0x7f; *output_ptr = (char)float_sample; output_ptr += output_advance; } } } // fix signed if(!signed_) { output_ptr = out_buffer; output_end = out_buffer + bytes; for( ; output_ptr < output_end; output_ptr++) *output_ptr ^= 0x80; } } break; case BITSLINEAR16: { int16_t *output_ptr; output_advance = channels; for(channel = 0; channel < channels; channel++) { output_ptr = (int16_t*)out_buffer + channel; buffer_channel = in_buffer[channel]; buffer_channel_end = buffer_channel + input_len; if(dither) { for( ; buffer_channel < buffer_channel_end; buffer_channel++) { float_sample = *buffer_channel * 0x7fffff; int_sample = (int64_t)float_sample; if(int_sample > -0x7fff00) { dither_value = rand() % dither_scale; int_sample -= dither_value; } int_sample /= 0x100; *output_ptr = int_sample; output_ptr += output_advance; } } else { for( ; buffer_channel < buffer_channel_end; buffer_channel++) { float_sample = *buffer_channel * 0x7fff; *output_ptr = (int16_t)float_sample; output_ptr += output_advance; } } } } break; case BITSLINEAR24: { char *output_ptr; output_advance = asset->channels * 3 - 2; for(channel = 0; channel < channels; channel++) { output_ptr = out_buffer + channel * 3; buffer_channel = in_buffer[channel]; buffer_channel_end = buffer_channel + input_len; // don't bother dithering 24 bits for( ; buffer_channel < buffer_channel_end; buffer_channel++) { float_sample = *buffer_channel * 0x7fffff; int_sample = (int64_t)float_sample; int_sample2 = int_sample & 0xff0000; *output_ptr++ = (int_sample & 0xff); int_sample &= 0xff00; *output_ptr++ = (int_sample >> 8); *output_ptr = (int_sample2 >> 16); output_ptr += output_advance; } } } break; case BITSULAW: { char *output_ptr; output_advance = asset->channels; //printf("FileBase::samples_to_raw 1\n"); generate_ulaw_tables(); //printf("FileBase::samples_to_raw 2\n"); for(channel = 0; channel < channels; channel++) { output_ptr = out_buffer + channel; buffer_channel = in_buffer[channel]; buffer_channel_end = buffer_channel + input_len; for( ; buffer_channel < buffer_channel_end; buffer_channel++) { *output_ptr = floattoulaw(*buffer_channel); output_ptr += output_advance; } } //printf("FileBase::samples_to_raw 3\n"); } break; } // swap bytes if((bits == BITSLINEAR16 && byte_order != machine_byte_order) || (bits == BITSLINEAR24 && !byte_order)) { swap_bytes(file->bytes_per_sample(bits), (unsigned char*)out_buffer, bytes); } return bytes; } #define READ_8_MACRO \ sample = *inbuffer_8; \ sample /= 0x7f; \ inbuffer_8 += input_frame; #define READ_16_MACRO \ sample = *inbuffer_16; \ sample /= 0x7fff; \ inbuffer_16 += input_frame; #define READ_24_MACRO \ sample = (unsigned char)*inbuffer_24++; \ sample_24 = (unsigned char)*inbuffer_24++; \ sample_24 <<= 8; \ sample += sample_24; \ sample_24 = *inbuffer_24; \ sample_24 <<= 16; \ sample += sample_24; \ sample /= 0x7fffff; \ inbuffer_24 += input_frame; \ #define READ_ULAW_MACRO \ sample = ulawtofloat(*inbuffer_8); \ inbuffer_8 += input_frame; #define LFEATHER_MACRO1 \ for(feather_current = 0; feather_current < lfeather_len; \ output_current++, feather_current++) \ { #define LFEATHER_MACRO2 \ current_gain = lfeather_gain + lfeather_slope * feather_current; \ out_buffer[output_current] = out_buffer[output_current] * (1 - current_gain) + sample * current_gain; \ } #define CENTER_MACRO1 \ for(; output_current < samples; \ output_current++) \ { #define CENTER_MACRO2 \ out_buffer[output_current] += sample; \ } int FileBase::raw_to_samples(float *out_buffer, char *in_buffer, int64_t samples, int bits, int channels, int channel, int feather, float lfeather_len, float lfeather_gain, float lfeather_slope) { int64_t output_current = 0; // position in output buffer int64_t input_len = samples; // length of input buffer // The following are floats because they are multiplied by the slope to get the gain. float feather_current; // input position for feather float sample; char *inbuffer_8 = 0; // point to actual byte being read int16_t *inbuffer_16 = 0; char *inbuffer_24 = 0; int sample_24; float current_gain; int input_frame = 0; // amount to advance the input buffer pointer // set up the parameters switch(bits) { case BITSLINEAR8: inbuffer_8 = in_buffer + channel; input_frame = channels; break; case BITSLINEAR16: inbuffer_16 = (int16_t *)in_buffer + channel; input_frame = channels; break; case BITSLINEAR24: inbuffer_24 = in_buffer + channel * 3; input_frame = channels * file->bytes_per_sample(bits) - 2; break; case BITSULAW: generate_ulaw_tables(); inbuffer_8 = in_buffer + channel; input_frame = channels; break; } // read the data // ================== calculate feathering and add to buffer ================ if(feather) { // left feather switch(bits) { case BITSLINEAR8: LFEATHER_MACRO1; READ_8_MACRO; LFEATHER_MACRO2; break; case BITSLINEAR16: LFEATHER_MACRO1; READ_16_MACRO; LFEATHER_MACRO2; break; case BITSLINEAR24: LFEATHER_MACRO1; READ_24_MACRO; LFEATHER_MACRO2; break; case BITSULAW: LFEATHER_MACRO1; READ_ULAW_MACRO; LFEATHER_MACRO2; break; } // central region switch(bits) { case BITSLINEAR8: CENTER_MACRO1; READ_8_MACRO; CENTER_MACRO2; break; case BITSLINEAR16: CENTER_MACRO1; READ_16_MACRO; CENTER_MACRO2; break; case BITSLINEAR24: CENTER_MACRO1; READ_24_MACRO; CENTER_MACRO2; break; case BITSULAW: CENTER_MACRO1; READ_ULAW_MACRO; CENTER_MACRO2; break; } } else // ====================== don't feather and overwrite buffer ================= { switch(bits) { case BITSLINEAR8: for(; output_current < input_len; output_current++) { READ_8_MACRO; out_buffer[output_current] = sample; } break; case BITSLINEAR16: for(; output_current < input_len; output_current++) { READ_16_MACRO; out_buffer[output_current] = sample; } break; case BITSLINEAR24: for(; output_current < input_len; output_current++) { READ_24_MACRO; out_buffer[output_current] = sample; } break; case BITSULAW: for(; output_current < input_len; output_current++) { READ_ULAW_MACRO; out_buffer[output_current] = sample; } break; } } return 0; } int FileBase::overlay_float_buffer(float *out_buffer, float *in_buffer, int64_t samples, float lfeather_len, float lfeather_gain, float lfeather_slope) { int64_t output_current = 0; float sample, current_gain; float feather_current; // input position for feather LFEATHER_MACRO1 sample = in_buffer[output_current]; LFEATHER_MACRO2 CENTER_MACRO1 sample = in_buffer[output_current]; CENTER_MACRO2 return 0; } int FileBase::get_audio_buffer(char **buffer, int64_t len, int64_t bits, int64_t channels) { int64_t bytes = len * channels * (file->bytes_per_sample(bits)); if(*buffer && bytes > prev_bytes) { delete [] *buffer; *buffer = 0; } prev_bytes = bytes; if(!*buffer) *buffer = new char[bytes]; return 0; } int FileBase::get_float_buffer(float **buffer, int64_t len) { if(*buffer && len > prev_len) { delete [] *buffer; *buffer = 0; } prev_len = len; if(!*buffer) *buffer = new float[len]; return 0; }