1 /* flac - Command-line FLAC encoder/decoder
2 * Copyright (C) 2000,2001,2002,2003 Josh Coalson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 pair_t buckets[FLAC__MAX_BLOCK_SIZE];
42 static subframe_stats_t all_;
44 static void init_stats(subframe_stats_t *stats);
45 static void update_stats(subframe_stats_t *stats, FLAC__int32 residual, unsigned incr);
46 static void compute_stats(subframe_stats_t *stats);
47 static FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename);
49 void flac__analyze_init(analysis_options aopts)
51 if(aopts.do_residual_gnuplot) {
56 void flac__analyze_frame(const FLAC__Frame *frame, unsigned frame_number, analysis_options aopts, FILE *fout)
58 const unsigned channels = frame->header.channels;
59 char outfilename[1024];
60 subframe_stats_t stats;
63 /* do the human-readable part first */
64 fprintf(fout, "frame=%u\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", frame_number, frame->header.blocksize, frame->header.sample_rate, channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]);
65 for(channel = 0; channel < channels; channel++) {
66 const FLAC__Subframe *subframe = frame->subframes+channel;
67 fprintf(fout, "\tsubframe=%u\twasted_bits=%u\ttype=%s", channel, subframe->wasted_bits, FLAC__SubframeTypeString[subframe->type]);
68 switch(subframe->type) {
69 case FLAC__SUBFRAME_TYPE_CONSTANT:
70 fprintf(fout, "\tvalue=%d\n", subframe->data.constant.value);
72 case FLAC__SUBFRAME_TYPE_FIXED:
73 FLAC__ASSERT(subframe->data.fixed.entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE);
74 fprintf(fout, "\torder=%u\tpartition_order=%u\n", subframe->data.fixed.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order);
75 for(i = 0; i < subframe->data.fixed.order; i++)
76 fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.fixed.warmup[i]);
77 if(aopts.do_residual_text) {
78 const unsigned partitions = (1u << subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order);
79 for(i = 0; i < partitions; i++) {
80 unsigned parameter = subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->parameters[i];
81 if(parameter == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER)
82 fprintf(fout, "\t\tparameter[%u]=ESCAPE, raw_bits=%u\n", i, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents->raw_bits[i]);
84 fprintf(fout, "\t\tparameter[%u]=%u\n", i, parameter);
86 for(i = 0; i < frame->header.blocksize-subframe->data.fixed.order; i++)
87 fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.fixed.residual[i]);
90 case FLAC__SUBFRAME_TYPE_LPC:
91 FLAC__ASSERT(subframe->data.lpc.entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE);
92 fprintf(fout, "\torder=%u\tpartition_order=%u\tqlp_coeff_precision=%u\tquantization_level=%d\n", subframe->data.lpc.order, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order, subframe->data.lpc.qlp_coeff_precision, subframe->data.lpc.quantization_level);
93 for(i = 0; i < subframe->data.lpc.order; i++)
94 fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.lpc.warmup[i]);
95 if(aopts.do_residual_text) {
96 const unsigned partitions = (1u << subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order);
97 for(i = 0; i < partitions; i++) {
98 unsigned parameter = subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->parameters[i];
99 if(parameter == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER)
100 fprintf(fout, "\t\tparameter[%u]=ESCAPE, raw_bits=%u\n", i, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents->raw_bits[i]);
102 fprintf(fout, "\t\tparameter[%u]=%u\n", i, parameter);
104 for(i = 0; i < frame->header.blocksize-subframe->data.lpc.order; i++)
105 fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.lpc.residual[i]);
108 case FLAC__SUBFRAME_TYPE_VERBATIM:
114 /* now do the residual distributions if requested */
115 if(aopts.do_residual_gnuplot) {
116 for(channel = 0; channel < channels; channel++) {
117 const FLAC__Subframe *subframe = frame->subframes+channel;
118 unsigned residual_samples;
122 switch(subframe->type) {
123 case FLAC__SUBFRAME_TYPE_FIXED:
124 residual_samples = frame->header.blocksize - subframe->data.fixed.order;
125 for(i = 0; i < residual_samples; i++)
126 update_stats(&stats, subframe->data.fixed.residual[i], 1);
128 case FLAC__SUBFRAME_TYPE_LPC:
129 residual_samples = frame->header.blocksize - subframe->data.lpc.order;
130 for(i = 0; i < residual_samples; i++)
131 update_stats(&stats, subframe->data.lpc.residual[i], 1);
138 for(i = 0; i < stats.nbuckets; i++) {
139 update_stats(&all_, stats.buckets[i].residual, stats.buckets[i].count);
142 /* write the subframe */
143 sprintf(outfilename, "f%06u.s%u.gp", frame_number, channel);
144 compute_stats(&stats);
146 (void)dump_stats(&stats, outfilename);
151 void flac__analyze_finish(analysis_options aopts)
153 if(aopts.do_residual_gnuplot) {
154 compute_stats(&all_);
155 (void)dump_stats(&all_, "all");
159 void init_stats(subframe_stats_t *stats)
161 stats->peak_index = -1;
168 void update_stats(subframe_stats_t *stats, FLAC__int32 residual, unsigned incr)
171 const double r = (double)residual, a = r*incr;
173 stats->nsamples += incr;
177 for(i = 0; i < stats->nbuckets; i++) {
178 if(stats->buckets[i].residual == residual) {
179 stats->buckets[i].count += incr;
183 /* not found, make a new bucket */
185 stats->buckets[i].residual = residual;
186 stats->buckets[i].count = incr;
189 if(stats->peak_index < 0 || stats->buckets[i].count > stats->buckets[stats->peak_index].count)
190 stats->peak_index = i;
193 void compute_stats(subframe_stats_t *stats)
195 stats->mean = stats->sum / (double)stats->nsamples;
196 stats->variance = (stats->sos - (stats->sum * stats->sum / stats->nsamples)) / stats->nsamples;
197 stats->stddev = sqrt(stats->variance);
200 FLAC__bool dump_stats(const subframe_stats_t *stats, const char *filename)
204 const double m = stats->mean;
205 const double s1 = stats->stddev, s2 = s1*2, s3 = s1*3, s4 = s1*4, s5 = s1*5, s6 = s1*6;
206 const double p = stats->buckets[stats->peak_index].count;
208 outfile = fopen(filename, "w");
211 fprintf(stderr, "ERROR opening %s\n", filename);
215 fprintf(outfile, "plot '-' title 'PDF', '-' title 'mean' with impulses, '-' title '1-stddev' with histeps, '-' title '2-stddev' with histeps, '-' title '3-stddev' with histeps, '-' title '4-stddev' with histeps, '-' title '5-stddev' with histeps, '-' title '6-stddev' with histeps\n");
217 for(i = 0; i < stats->nbuckets; i++) {
218 fprintf(outfile, "%d %u\n", stats->buckets[i].residual, stats->buckets[i].count);
220 fprintf(outfile, "e\n");
222 fprintf(outfile, "%f %f\ne\n", stats->mean, p);
223 fprintf(outfile, "%f %f\n%f %f\ne\n", m-s1, p*0.8, m+s1, p*0.8);
224 fprintf(outfile, "%f %f\n%f %f\ne\n", m-s2, p*0.7, m+s2, p*0.7);
225 fprintf(outfile, "%f %f\n%f %f\ne\n", m-s3, p*0.6, m+s3, p*0.6);
226 fprintf(outfile, "%f %f\n%f %f\ne\n", m-s4, p*0.5, m+s4, p*0.5);
227 fprintf(outfile, "%f %f\n%f %f\ne\n", m-s5, p*0.4, m+s5, p*0.4);
228 fprintf(outfile, "%f %f\n%f %f\ne\n", m-s6, p*0.3, m+s6, p*0.3);
230 fprintf(outfile, "pause -1 'waiting...'\n");