///////////////////////////// executable code //////////////////////////////// // This function reads data from the specified stream in search of a valid // WavPack 4.0 audio block. If this fails in 1 megabyte (or an invalid or // unsupported WavPack block is encountered) then an appropriate message is // copied to "error" and NULL is returned, otherwise a pointer to a // WavpackContext structure is returned (which is used to call all other // functions in this module). This can be initiated at the beginning of a // WavPack file, or anywhere inside a WavPack file. To determine the exact // position within the file use WavpackGetSampleIndex(). Also, // this function will not handle "correction" files, plays only the first // two channels of multi-channel files, and is limited in resolution in some // large integer or floating point files (but always provides at least 24 bits // of resolution). public static WavpackContext WavpackOpenFileInput(System.IO.BinaryReader infile) { WavpackContext wpc = new WavpackContext(); WavpackStream wps = wpc.stream; wpc.infile = infile; wpc.total_samples = -1; wpc.norm_offset = 0; wpc.open_flags = 0; // open the source file for reading and store the size while (wps.wphdr.block_samples == 0) { wps.wphdr = read_next_header(wpc.infile, wps.wphdr); if (wps.wphdr.status == 1) { wpc.error_message = "not compatible with this version of WavPack file!"; wpc.error = true; return(wpc); } if (wps.wphdr.block_samples > 0 && wps.wphdr.total_samples != -1) { wpc.total_samples = wps.wphdr.total_samples; } // lets put the stream back in the context wpc.stream = wps; if ((UnpackUtils.unpack_init(wpc)) == Defines.FALSE) { wpc.error = true; return(wpc); } } // end of while wpc.config.flags = wpc.config.flags & ~0xff; wpc.config.flags = wpc.config.flags | (wps.wphdr.flags & 0xff); wpc.config.bytes_per_sample = (int)((wps.wphdr.flags & Defines.BYTES_STORED) + 1); wpc.config.float_norm_exp = wps.float_norm_exp; wpc.config.bits_per_sample = (int)((wpc.config.bytes_per_sample * 8) - ((wps.wphdr.flags & Defines.SHIFT_MASK) >> Defines.SHIFT_LSB)); if ((wpc.config.flags & Defines.FLOAT_DATA) > 0) { wpc.config.bytes_per_sample = 3; wpc.config.bits_per_sample = 24; } if (wpc.config.sample_rate == 0) { if (wps.wphdr.block_samples == 0 || (wps.wphdr.flags & Defines.SRATE_MASK) == Defines.SRATE_MASK) { wpc.config.sample_rate = 44100; } else { wpc.config.sample_rate = sample_rates[(int)((wps.wphdr.flags & Defines.SRATE_MASK) >> Defines.SRATE_LSB)]; } } if (wpc.config.num_channels == 0) { if ((wps.wphdr.flags & Defines.MONO_FLAG) > 0) { wpc.config.num_channels = 1; } else { wpc.config.num_channels = 2; } wpc.config.channel_mask = 0x5 - wpc.config.num_channels; } if ((wps.wphdr.flags & Defines.FINAL_BLOCK) == 0) { if ((wps.wphdr.flags & Defines.MONO_FLAG) != 0) { wpc.reduced_channels = 1; } else { wpc.reduced_channels = 2; } } return(wpc); }
// Unpack the specified number of samples from the current file position. // Note that "samples" here refers to "complete" samples, which would be // 2 longs for stereo files. The audio data is returned right-justified in // 32-bit longs in the endian mode native to the executing processor. So, // if the original data was 16-bit, then the values returned would be // +/-32k. Floating point data will be returned as 24-bit integers (and may // also be clipped). The actual number of samples unpacked is returned, // which should be equal to the number requested unless the end of fle is // encountered or an error occurs. internal static long WavpackUnpackSamples(WavpackContext wpc, int[] buffer, long samples) { WavpackStream wps = wpc.stream; long samples_unpacked = 0, samples_to_unpack; int num_channels = wpc.config.num_channels; int bcounter = 0; int buf_idx = 0; int bytes_returned = 0; while (samples > 0) { if (wps.wphdr.block_samples == 0 || (wps.wphdr.flags & Defines.INITIAL_BLOCK) == 0 || wps.sample_index >= wps.wphdr.block_index + wps.wphdr.block_samples) { wps.wphdr = read_next_header(wpc.infile, wps.wphdr); if (wps.wphdr.status == 1) { break; } if (wps.wphdr.block_samples == 0 || wps.sample_index == wps.wphdr.block_index) { if ((UnpackUtils.unpack_init(wpc)) == Defines.FALSE) { break; } } } if (wps.wphdr.block_samples == 0 || (wps.wphdr.flags & Defines.INITIAL_BLOCK) == 0 || wps.sample_index >= wps.wphdr.block_index + wps.wphdr.block_samples) { continue; } if (wps.sample_index < wps.wphdr.block_index) { samples_to_unpack = wps.wphdr.block_index - wps.sample_index; if (samples_to_unpack > samples) { samples_to_unpack = samples; } wps.sample_index += samples_to_unpack; samples_unpacked += samples_to_unpack; samples -= samples_to_unpack; if (wpc.reduced_channels > 0) { samples_to_unpack *= wpc.reduced_channels; } else { samples_to_unpack *= num_channels; } bcounter = buf_idx; while (samples_to_unpack > 0) { buffer[bcounter] = 0; bcounter++; samples_to_unpack--; } buf_idx = bcounter; continue; } samples_to_unpack = wps.wphdr.block_index + wps.wphdr.block_samples - wps.sample_index; if (samples_to_unpack > samples) { samples_to_unpack = samples; } UnpackUtils.unpack_samples(wpc, buffer, samples_to_unpack, buf_idx); if (wpc.reduced_channels > 0) { bytes_returned = (int)(samples_to_unpack * wpc.reduced_channels); } else { bytes_returned = (int)(samples_to_unpack * num_channels); } buf_idx += bytes_returned; samples_unpacked += samples_to_unpack; samples -= samples_to_unpack; if (wps.sample_index == wps.wphdr.block_index + wps.wphdr.block_samples) { if (UnpackUtils.check_crc_error(wpc) > 0) { wpc.crc_errors++; } } if (wps.sample_index == wpc.total_samples) { break; } } return(samples_unpacked); }