UINT CSoundFile::Read( LPVOID lpBuffer, UINT cbBuffer ) { mpcpplog(); if ( !mod ) { return 0; } mpcpplog(); if ( !lpBuffer ) { return 0; } mpcpplog(); if ( cbBuffer <= 0 ) { return 0; } mpcpplog(); if ( get_samplerate() <= 0 ) { return 0; } mpcpplog(); if ( get_sample_size() != 1 && get_sample_size() != 2 && get_sample_size() != 4 ) { return 0; } mpcpplog(); if ( get_num_channels() != 1 && get_num_channels() != 2 && get_num_channels() != 4 ) { return 0; } mpcpplog(); std::memset( lpBuffer, 0, cbBuffer ); const std::size_t frames_torender = cbBuffer / get_frame_size(); std::int16_t * out = (std::int16_t*)lpBuffer; std::vector<std::int16_t> tmpbuf; if ( get_sample_size() == 1 || get_sample_size() == 4 ) { tmpbuf.resize( frames_torender * get_num_channels() ); out = &tmpbuf[0]; } mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, get_filter_length() ); std::size_t frames_rendered = 0; if ( get_num_channels() == 1 ) { frames_rendered = mod->read( get_samplerate(), frames_torender, out ); } else if ( get_num_channels() == 4 ) { frames_rendered = mod->read_interleaved_quad( get_samplerate(), frames_torender, out ); } else { frames_rendered = mod->read_interleaved_stereo( get_samplerate(), frames_torender, out ); } if ( get_sample_size() == 1 ) { std::uint8_t * dst = (std::uint8_t*)lpBuffer; for ( std::size_t sample = 0; sample < frames_rendered * get_num_channels(); ++sample ) { dst[sample] = ( tmpbuf[sample] / 0x100 ) + 0x80; } } else if ( get_sample_size() == 4 ) { std::int32_t * dst = (std::int32_t*)lpBuffer; for ( std::size_t sample = 0; sample < frames_rendered * get_num_channels(); ++sample ) { dst[sample] = tmpbuf[sample] << (32-16-1-MIXING_ATTENUATION); } } return frames_rendered * get_frame_size(); }
/** * \brief Sets the volume of a channel. * \param channel A channel index. * \param volume The volume to set. */ void ItDecoder::set_channel_volume(int channel, int volume) { const unsigned int num_channels = get_num_channels(); const unsigned int num_patterns = ModPlug_NumPatterns(modplug_file); for (unsigned int pattern = 0; pattern < num_patterns; ++pattern) { unsigned int num_rows; ModPlugNote* notes = ModPlug_GetPattern(modplug_file, pattern, &num_rows); for (unsigned int j = channel; j < num_rows * num_channels; j += num_channels) { notes[j].Volume = volume; } } }
bool c_chls::send_cmd(int argc, char ** argv) { int num_channels = get_num_channels(); if(num_channels < 0){ cerr << "Channel List cannot be enumerated." << endl; return false; } cout << "#Channel List (" << num_channels << ") channels found." << endl; for(int ichannel = 0; ichannel < num_channels; ichannel++){ if(!get_channel_inf(ichannel)){ cerr << "Failed to list channels." << endl; } } return true; }
/** * \brief Returns the volume of a channel. * \param channel A channel index. * \return The volume of this channel. */ int ItDecoder::get_channel_volume(int channel) { const int num_patterns = ModPlug_NumPatterns(modplug_file); Debug::check_assertion(channel >= 0 && channel < get_num_channels(), "Invalid channel number"); if (num_patterns == 0) { return 0; } unsigned int num_rows = 0; ModPlugNote* notes = ModPlug_GetPattern(modplug_file, 0, &num_rows); if (num_rows == 0) { return 0; } return notes[0].Volume; }
GLenum get_suitable_internal_format(const GLenum format, const GLenum type, const bool use_compression) noexcept { const int num_channels = get_num_channels(format); const bool int_format = is_integer_format(format); const bool snorm = is_signed(type); const bool has_s3tc = glewIsSupported("EXT_texture_compression_s3tc"); const bool has_rgtc = glewIsSupported("ARB_texture_compression_rgtc"); const bool has_bptc = glewIsSupported("ARB_texture_compression_bptc"); GLenum internal_format; if (num_channels == 1) { if (use_compression && !int_format && has_rgtc) { internal_format = snorm ? GL_COMPRESSED_SIGNED_RED_RGTC1 : GL_COMPRESSED_RED_RGTC1; } else if (type == GL_FLOAT) { internal_format = GL_R32F; } else if (type == GL_INT) { // GL_R32_SNORM not available! Choose closest. internal_format = int_format ? GL_R32I : GL_R16_SNORM; } else if (type == GL_UNSIGNED_INT) { // GL_R32 not available! Choose closest. internal_format = int_format ? GL_R32UI : GL_R16; } else if (type == GL_SHORT) { internal_format = int_format ? GL_R16I : GL_R16_SNORM; } else if (type == GL_UNSIGNED_SHORT) { internal_format = int_format ? GL_R16UI : GL_R16; } else if (type == GL_BYTE) { internal_format = int_format ? GL_R8I : GL_R8_SNORM; } else { // just use GL_R8 for everything else internal_format = int_format ? GL_R8UI : GL_R8; } } else if (num_channels == 2) { if (use_compression && !int_format && has_rgtc) { internal_format = snorm ? GL_COMPRESSED_SIGNED_RG_RGTC2 : GL_COMPRESSED_RG_RGTC2; } else if (type == GL_FLOAT) { internal_format = GL_RG32F; } else if (type == GL_INT) { // GL_RG32_SNORM not available! Choose closest. internal_format = int_format ? GL_RG32I : GL_RG16_SNORM; } else if (type == GL_UNSIGNED_INT) { // GL_RG32 not available! Choose closest. internal_format = int_format ? GL_RG32UI : GL_RG16; } else if (type == GL_SHORT) { internal_format = int_format ? GL_RG16I : GL_RG16_SNORM; } else if (type == GL_UNSIGNED_SHORT) { internal_format = int_format ? GL_RG16UI : GL_RG16; } else if (type == GL_BYTE) { internal_format = int_format ? GL_RG8I : GL_RG8_SNORM; } else { // just use GL_RG8 for everything else internal_format = int_format ? GL_RG8UI : GL_RG8; } } else if (num_channels == 3) { if (use_compression && !int_format && has_bptc) { internal_format = snorm ? GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT : GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; } else if (use_compression && !int_format && !snorm && has_s3tc) { internal_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; } else if (type == GL_FLOAT) { internal_format = GL_RGB32F; } else if (type == GL_INT) { // GL_RGB32_SNORM not available! Choose closest. internal_format = int_format ? GL_RGB32I : GL_RGB16_SNORM; } else if (type == GL_UNSIGNED_INT) { // GL_RGB32 not available! Choose closest. internal_format = int_format ? GL_RGB32UI : GL_RGB16; } else if (type == GL_SHORT) { internal_format = int_format ? GL_RGB16I : GL_RGB16_SNORM; } else if (type == GL_UNSIGNED_SHORT) { internal_format = int_format ? GL_RGB16UI : GL_RGB16; } else if (type == GL_BYTE) { internal_format = int_format ? GL_RGB8I : GL_RGB8_SNORM; } else { // just use GL_RGB8 for everything else internal_format = int_format ? GL_RGB8UI : GL_RGB8; } } else if (num_channels == 4) { if (use_compression && !int_format && !snorm && (has_bptc || has_s3tc)) { internal_format = has_bptc ? GL_COMPRESSED_RGBA_BPTC_UNORM : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; } else if (type == GL_FLOAT) { internal_format = GL_RGBA32F; } else if (type == GL_INT) { // GL_RGBA32_SNORM not available! Choose closest. internal_format = int_format ? GL_RGBA32I : GL_RGBA16_SNORM; } else if (type == GL_UNSIGNED_INT) { // GL_RGBA32 not available! Choose closest. internal_format = int_format ? GL_RGBA32UI : GL_RGBA16; } else if (type == GL_SHORT) { internal_format = int_format ? GL_RGBA16I : GL_RGBA16_SNORM; } else if (type == GL_UNSIGNED_SHORT) { internal_format = int_format ? GL_RGBA16UI : GL_RGBA16; } else if (type == GL_BYTE) { internal_format = int_format ? GL_RGBA8I : GL_RGBA8_SNORM; } else { // just use GL_RGBA8 for everything else internal_format = int_format ? GL_RGBA8UI : GL_RGBA8; } } else { // should not be reached abort(); } return internal_format; }
static std::size_t get_frame_size() { return get_sample_size() * get_num_channels(); }
/* * This function initialises the PNGImage struct for us in future it may be * a good idea to make use of stdarg.h and add a ... argument that allow us * to specify optional arguments such as image height and width etc. */ bool new_png_image(PNGImage* img, IMGParams* params) { // Check to see if we have been given any parameters if so use those // otherwise just create a blank image if (params != NULL) { img->width = params->width; img->height = params->height; img->color_type = params->color_type; img->bit_depth = 8; // We will only be able to create 8bit images for now int num_channels = get_num_channels(img); if(num_channels == -1) { fprintf(stderr, "[new_image]: Colour type not supported or invalid\n"); return false; } img->num_channels = num_channels; // Now allocate the memory img->row_pointers = (png_bytep*) malloc(img->height * sizeof(png_bytep)); if(!img->row_pointers) { fprintf(stderr, "[new_image]: ERROR: Unable to allocate memory for the image\n"); return false; } unsigned int i = 0; unsigned int j = 0; for(i = 0; i < img->width ; i++) { img->row_pointers[i] = (png_byte*) malloc((img->width * img->num_channels) * sizeof(png_byte)); if(!img->row_pointers[i]) { fprintf(stderr, "[new_image]: ERROR: Unable to allocate memory for the image\n"); for(j = 0; j < i; j++) { free(img->row_pointers[i]); img->row_pointers[i] = NULL; } return false; } } } else { // I think we can just initialise everything to zero img->width = 0; img->height = 0; img->color_type = 0; img->num_channels = 0; img->bit_depth = 0; img->row_pointers = NULL; } img->number_of_passes = 0; // It's good practice to initialise pointers to NULL img->png_ptr = NULL; img->info_ptr = NULL; return true; }
unsigned long operator()( SampleSource &sample_source, InputProperties const &input_properties, void *output, unsigned long const num_output_samples, OutputProperties const &output_properties, unsigned int const volume, unsigned int const max_volume ) { // prerequisites unsigned int num_input_channels = get_num_channels(input_properties); unsigned int num_output_channels = get_num_channels(output_properties); unsigned int input_frequency = get_frequency(input_properties); unsigned int output_frequency = get_frequency(output_properties); if (input_frequency == 0) // if the input frequency is 0, then the sample source can adapt to the output frequency input_frequency = output_frequency; bool frequencies_match = (input_frequency == output_frequency); bool num_channels_match = (num_input_channels == num_output_channels); bool sample_types_match = get_sample_type(input_properties) == get_sample_type(output_properties); // if the properties fully match, no processing is necessary - just transmit the samples directly to the output and exit // do a volume processing if necessary, but otherwise its just one transmission if (frequencies_match && sample_types_match && num_channels_match) { unsigned long num_retrieved_samples = retrieve_samples(sample_source, output, num_output_samples); if (volume != max_volume) { sample_type output_sample_type = get_sample_type(output_properties); for (unsigned long i = 0; i < num_retrieved_samples * num_output_channels; ++i) { set_sample_value( output, i, adjust_sample_volume(get_sample_value(output, i, output_sample_type), volume, max_volume), output_sample_type ); } } return num_retrieved_samples; } unsigned long num_retrieved_samples = 0; uint8_t *resampler_input = 0; sample_type dest_type = sample_unknown; // note that this returns true if the resampler is in an uninitialized state bool resampler_needed_more_input = is_more_input_needed_for(resampler, num_output_samples); // first processing stage: convert samples & mix channels if necessary // also, the resampler input is prepared here // if resampling is necessary, and the resampler has enough input data for now, this stage is bypassed if (frequencies_match || resampler_needed_more_input) { // with the adjusted value from above, retrieve samples from the sample source, and resize the buffer to the number of actually retrieved samples // (since the sample source may have given us less samples than we requested) unsigned long num_samples_to_retrieve = num_output_samples; source_data_buffer.resize(num_samples_to_retrieve * num_input_channels * get_sample_size(get_sample_type(input_properties))); num_retrieved_samples = retrieve_samples(sample_source, &source_data_buffer[0], num_samples_to_retrieve); source_data_buffer.resize(num_retrieved_samples * num_input_channels * get_sample_size(get_sample_type(input_properties))); // here, the dest and dest_type values are set, as well as the resampler input (if necessary) // several optimizations are done here: if the resampler is not necessary, then dest points to the output - any conversion steps will write data directly to the output then // if the resampler is necessary, and the sample types match, then the resampler's input is the source data buffer, otherwise it is the "dest" pointer // the reason for this is: if the sample types match, no conversion step is necessary, and the resampler can pull data directly from the source data buffer; // otherwise, the conversion step needs to convert to an intermediate buffer (the buffer the dest pointer points at), and then the resampler pulls data from this buffer uint8_t *dest; if (frequencies_match) { // frequencies match - dest is set to point at the output, meaning that the next step will directly write to the output dest_type = get_sample_type(output_properties); dest = reinterpret_cast < uint8_t* > (output); } else { // frequencies do not match, resampling is necessary - dest is set to point at an intermediate buffer, which the resampler will use // ask the resampler what resampling input type it needs - this may differ from the output properties' sample type, but this is ok, // since with resampling, an intermediate step between sample type conversion & mixing and actual output is present anyway dest_type = find_compatible_type(resampler, get_sample_type(input_properties)); if (sample_types_match && num_channels_match) { // if the sample types and channel count match, then no conversion step is necessary, and the resampler can pull data from the source data buffer directly resampler_input = &source_data_buffer[0]; dest = 0; } else { // if the sample types and channel count do not match, then the resampler needs to pull data from the intermediate buffer dest points to // the conversion step will write to dest resampling_input_buffer.resize(num_output_samples * num_output_channels * get_sample_size(dest_type)); dest = &resampling_input_buffer[0]; resampler_input = dest; } } // actual mixing and conversion is done here if (num_channels_match) { // channel counts match, no mixing necessary if (!sample_types_match) { assert(dest != 0); // sample types do not match // go through all the input samples, convert them, and write them to dest for (unsigned long i = 0; i < num_retrieved_samples * num_input_channels; ++i) { set_sample_value( dest, i, convert_sample_value( get_sample_value(&source_data_buffer[0], i, get_sample_type(input_properties)), get_sample_type(input_properties), dest_type ), dest_type ); } } // if the sample types match, nothing needs to be done here } else { // channels count do not match - call the mixer mix_channels(&source_data_buffer[0], dest, num_retrieved_samples, get_sample_type(input_properties), dest_type, get_num_channels(input_properties), get_num_channels(output_properties)); } } else { // either resampling is not necessary, or the resampler does not need any new input for now // set number of retrieved samples to number of output samples, and if resampling is necessary, set the dest_type value num_retrieved_samples = num_output_samples; // the dest_type value is set, since the resampler might reset itself if it sees a change in the input type if (!frequencies_match) dest_type = find_compatible_type(resampler, get_sample_type(input_properties)); } // the final stage adjusts the output volume; if the volume equals the max volume, it is unnecessary // this boolean conditionally enables this stage bool do_volume_stage = (volume != max_volume); // second processing stage: resample if necessary (otherwise this stage is bypassed) if (!frequencies_match) { sample_type resampler_input_type = dest_type; // the resampler may have only support for a fixed number of sample types - let it choose a suitable output one sample_type resampler_output_type = find_compatible_type(resampler, resampler_input_type, get_sample_type(output_properties)); sample_type output_type = get_sample_type(output_properties); bool conversion_needed = (resampler_output_type != output_type); uint8_t *resampler_output = reinterpret_cast < uint8_t* > (output); if (conversion_needed) { resampling_output_buffer.resize(num_output_samples * num_output_channels * get_sample_size(resampler_output_type)); resampler_output = &resampling_output_buffer[0]; } // resampler input -can- be zero - sometimes the resampler does not need any more input assert(!resampler_needed_more_input || (resampler_input != 0)); // call the actual resampler, which returns the number of samples that were actually sent to output // if this is the first call since the resampler was reset(), this call internally initializes the resampler // and sets its internal values to the given ones // note that the is_more_input_needed_for() call returns true if the resampler is in such an uninitialized state // if the resampler was initialized already, it may reinitialize itself internally if certain parameters change // (this is entirely implementation-dependent; from the outside, no such reinitialization is noticeable) num_retrieved_samples = resample( resampler, resampler_input, num_retrieved_samples, resampler_output, num_output_samples, input_frequency, output_frequency, resampler_input_type, resampler_output_type, num_output_channels ); // the output type chosen by the resampler may not match the output type given by the output properties, so a final conversion step may be necessary if (conversion_needed) { if (do_volume_stage) { // if the volume stage is required, use the opportunity to do it together with the final conversion step for (unsigned long i = 0; i < num_retrieved_samples * num_output_channels; ++i) { set_sample_value( output, i, adjust_sample_volume( get_sample_value(resampler_output, i, resampler_output_type), volume, max_volume ), output_type ); } // volume adjustment was done in-line in the conversion step above -> no further volume adjustment required do_volume_stage = false; } else { // conversion without volume adjustment for (unsigned long i = 0; i < num_retrieved_samples * num_output_channels; ++i) set_sample_value(output, i, get_sample_value(resampler_output, i, output_type), output_type); } } } // do the volume stage if required if (do_volume_stage) { sample_type output_sample_type = get_sample_type(output_properties); for (unsigned long i = 0; i < num_retrieved_samples * num_output_channels; ++i) { set_sample_value( output, i, adjust_sample_volume(get_sample_value(output, i, output_sample_type), volume, max_volume), output_sample_type ); } } // finally, return the number of retrieved samples, either from the resampler, or from the source directly, // depending on whether or not resampling was necessary return num_retrieved_samples; }