#This work is licensed under the
#Creative Commons Attribution-Share Alike 3.0 United States License.
#To view a copy of this license, visit
#http://creativecommons.org/licenses/by-sa/3.0/us/ or send a letter to
#Creative Commons,
#171 Second Street, Suite 300,
#San Francisco, California, 94105, USA.

INPUT encoding_parameters, bits_per_sample, sample, sample_count;
OUTPUT "a FLAC subframe and its size in bits";
VAR encoding_parameters "encoding parameters";
VAR samples "samples";
VAR bits_per_sample "bits-per-sample";
VAR all_samples_same "all samples are the same";
VAR verbatim_subframe_length "VERBATIM length";
VAR fixed_subframe "FIXED subframe";
VAR fixed_subframe_length "FIXED length";
VAR fixed_subframe_order "FIXED order";
VAR max_lpc_order "maximum LPC order";
VAR lpc_subframe "LPC subframe";
VAR lpc_subframe_length "LPC length";
VAR lpc_subframe_order "LPC order";
VAR wasted_BPS "wasted BPS";
VAR sample_count "sample count";
VAR sample "sample";
VAR header_length "subframe header length";
VAR subframe "FLAC subframe";
VAR subframe_length "FLAC subframe length (including subframe header)";
FUNC encode_fixed_subframe "encode FIXED subframe" "flac:encode_fixed_subframe";
FUNC encode_lpc_subframe "encode LPC subframe" "flac:encode_lpc_subframe";
FUNC calculate_wasted "calculated wasted bits" "flac:calculate_wasted_bps";
FUNC write_subframe_header "write subframe header" "flac:write_subframe_header";
max_lpc_order <- encoding_parameters;
if all_samples_same /*encode CONSTANT subframe*/ {
    write_subframe_header(0, 0);
    sample[0] -> write bits_per_sample signed;
} else {
    wasted_BPS <- calculate_wasted(sample, sample_count);
    if wasted_BPS > 0 {
        for i <- 0 to sample_count {
            sample[i] <- sample[i] / 2 ^ wasted_BPS;
        }
    }
    verbatim_subframe_length <- sample_count * (bits_per_sample - wasted_BPS);
    fixed_subframe,fixed_subframe_length,fixed_subframe_order <-
    encode_fixed_subframe(encoding_parameters,
                          sample,
                          sample_count,
                          bits_per_sample - wasted_BPS);
    if (max_lpc_order > 0) {
        lpc_subframe,lpc_subframe_length,lpc_subframe_order <-
        encode_lpc_subframe(encoding_parameters,
                            sample,
                            sample_count,
                            bits_per_sample - wasted_BPS);
        if (lpc_subframe_length < fixed_subframe_length) and
           (lpc_subframe_length < verbatim_subframe_length) {
            write_subframe_header(31 + lpc_subframe_order,
                                  wasted_BPS);
            lpc_subframe -> write lpc_subframe_length unsigned;
        } elif fixed_subframe_length < verbatim_subframe_length {
            write_subframe_header(8 + fixed_subframe_order,
                                  wasted_BPS);
            fixed_subframe -> write fixed_subframe_length unsigned;
        } else /*encode VERBATIM subframe*/ {
            write_subframe_header(1, wasted_BPS);
            for i <- 0 to sample_count {
                sample[i] -> write (bits_per_sample - wasted_BPS) signed;
            }
        }
    } elif fixed_subframe_length < verbatim_subframe_length {
        write_subframe_header(8 + fixed_subframe_order,
                              wasted_BPS);
        fixed_subframe -> write fixed_subframe_length unsigned;
    } else /*encode VERBATIM subframe*/ {
        write_subframe_header(1, wasted_BPS);
        for i <- 0 to sample_count {
            sample[i] -> write (bits_per_sample - wasted_BPS) signed;
        }
    }
}
return subframe,subframe_length;
