Пример #1
0
static void process_samples(struct example_sink_userdata *u, uint64_t expected_bytes)
{
    pa_assert(u);

    while (u->rendered_bytes < expected_bytes) {
        /* read chunk from every connected sink input, mix them, allocate
         * memblock, fill it with mixed samples, and return it to us.
         */
        pa_memchunk chunk;
        pa_sink_render(u->sink, 0, &chunk);

        /* start reading chunk's memblock */
        const char *buf = pa_memblock_acquire(chunk.memblock);

        /* write samples from memblock to the file */
        ssize_t sz =
            write_samples(u->output_fd, buf + chunk.index, chunk.length);

        if (sz != chunk.length) {
            break;
        }

        u->rendered_bytes += chunk.length;

        /* finish reading memblock */
        pa_memblock_release(chunk.memblock);

        /* return memblock to the pool */
        pa_memblock_unref(chunk.memblock);
    }
}
Пример #2
0
static int genode_run_out(HWVoiceOut *hw)
{
	GenodeVoiceOut * const out = (GenodeVoiceOut *)hw;
	Pcm_out_buffer & pcm_buf   = out->pcm_buf;

	int const live = audio_pcm_hw_get_live_out(&out->hw);
	if (!live)
		return 0;

	int const decr     = audio_MIN(live, out->hw.samples);
	size_t const avail = pcm_buf.read_avail();

	if ((avail / (VBOX_SAMPLE_SIZE*VBOX_CHANNELS)) < decr)
		Genode::error(__func__, ": avail: ", avail, " < decr ", decr);

	char buf[decr*VBOX_SAMPLE_SIZE*VBOX_CHANNELS];
	pcm_buf.read(buf, sizeof(buf), true);

	int const samples = write_samples(out, (int16_t*)buf, decr);
	if (samples == 0) return 0;

	pcm_buf.read_advance(samples * (VBOX_SAMPLE_SIZE*VBOX_CHANNELS));

	out->hw.rpos = (out->hw.rpos + samples) % out->hw.samples;
	return samples;
}
Пример #3
0
int main (int argc, const char *argv[])
{
    CmdArgParser parser(argc, argv);
    parser.setHeader("Archive Benchmark\n");
    parser.setArgumentsInfo("<index>");
    CmdArgFlag old(parser, "old", "Use old directory file");
    CmdArgInt samples(parser, "samples", "<count>",
                      "Number of samples to write");
    CmdArgString channel_name(parser, "channel", "<name>",
                      "Channel Name");
    CmdArgFlag do_read(parser, "read",
                       "Perform read test");
    
    // defaults
    samples.set(100000);
    channel_name.set("fred");

    if (parser.parse() == false)
        return -1;
    if (parser.getArguments().size() != 1)
    {
        parser.usage();
        return -1;
    }
    stdString index_name = parser.getArgument(0);
    size_t count;
    epicsTime start, stop;
    try
    {
        if (do_read)
        {
            start = epicsTime::getCurrent ();
            if (old)
                count = old_read_samples(index_name, channel_name.get());
            else
                count = read_samples(index_name, channel_name.get());
            stop = epicsTime::getCurrent ();
        }
        else
        {
            count = samples.get();
            start = epicsTime::getCurrent ();
            if (old)
                old_write_samples(index_name, channel_name.get(), count);
            else
                write_samples(index_name, channel_name.get(), count);
            stop = epicsTime::getCurrent ();
        }
        double secs = stop - start;
        printf("%zd values in %g seconds: %g vals/sec\n",
               count, secs,
               (double)count / secs);
    }
    catch (GenericException &e)
    {
        fprintf(stderr, "Error:\n%s\n", e.what());
    }
    return 0;
}
Пример #4
0
void end_audio_frame() {
    if (frame_offset == 0)
        // No audio added; blip_end_frame() dislikes being called with an
        // offset of 0
        return;

    assert(!(is_backwards_frame && frame_offset != get_frame_len()));

    // Bring the signal level at the end of the frame to zero as outlined in
    // set_audio_signal_level()
    set_audio_signal_level(0);

    blip_end_frame(blip, frame_offset);

    if (playback_started) {
        // Fudge playback rate by an amount proportional to the difference
        // between the desired and current buffer fill levels to try to steer
        // towards it

        double const fudge_factor = 1.0 + 2*max_adjust*(0.5 - fill_level());
        blip_set_rates(blip, cpu_clock_rate, sample_rate*fudge_factor);
    }
    else {
        if (fill_level() >= 0.5) {
            start_audio_playback();
            playback_started = true;
        }
    }

    int const n_samples = blip_read_samples(blip, blip_samples, ARRAY_LEN(blip_samples), 0);
    // We expect to read all samples from blip_buf. If something goes wrong and
    // we don't, clear the buffer to prevent data piling up in blip_buf's
    // buffer (which lacks bounds checking).
    int const avail = blip_samples_avail(blip);
    if (avail != 0) {
        printf("Warning: didn't read all samples from blip_buf (%d samples remain) - dropping samples\n",
          avail);
        blip_clear(blip);
    }

#ifdef RECORD_MOVIE
    add_movie_audio_frame(blip_samples, n_samples);
#endif

    // Save the samples to the audio ring buffer

    lock_audio();
    write_samples(blip_samples, n_samples);
    unlock_audio();
}
TESTABLE_STATIC int logging_sample(struct logging_status *ls,
                                   LoggerMessage *msg)
{
        /* If we haven't starting logging yet, then don't log (duh!) */
        if (!ls->logging)
                return 0;

        int attempts = 2;
        int rc = WRITE_FAIL;
        while (attempts--) {
                /*
                 * Open the log file if not yet done.  This is good for
                 * both lazy opening and easy recovering of failure as
                 * this method will init the FS.
                 */
                if (WRITING_ACTIVE != ls->writing_status)
                        open_log_file(ls);

                /* Don't try to write if file isn't open */
                if (WRITING_ACTIVE == ls->writing_status) {
                        rc = write_samples(ls, msg);
                        if (0 == rc)
                                break;
                }

                /* If here, then unmount and try attempts more time */
                pr_error("Remounting FS due to write error.\r\n");
                close_log_file(ls);

                /*
                 * We yield here because init/f_open/f_close all involve
                 * locks and can eat up significant resournce.  This ensures
                 * we don't hog resources beyond reason.  Or, you know, you
                 * could keep your damn SD card plugged in.  --Stieg
                 */
                taskYIELD();
        }

        logging_led_toggle();
        return rc;
}
Пример #6
0
/*
	Encode a single frame of audio from 1152 samples
	Audio samples are taken from glopts->buffer
	Encoded bit stream is placed in to parameter bs
	(not intended for use outside the library)
	
	Returns the size of the frame
	or -1 if there is an error
*/
static int encode_frame(twolame_options *glopts, bit_stream *bs)
{
	int nch = glopts->frame.nch;
	int sb, ch, adb, i;
	unsigned long frameBits, initial_bits;
	short sam[2][1056];
// MEANX
        int head1,head2;
        

// /MEANX
	if (!glopts->twolame_init) {
		fprintf (stderr, "Please call twolame_init_params() before starting encoding.\n");
		return -1;
	}
	
	// Scale and mix the input buffer
	scale_and_mix_samples( glopts );
	
	
    // Clear the saved audio buffer
    memset ((char *) sam, 0, sizeof (sam));

	/* Store the number of bits initially in the bit buffer */
	initial_bits = buffer_sstell(bs);

	adb = available_bits ( glopts );

    /* allow the user to reserve some space at the end of the frame
       This will however leave fewer bits for the audio.
       Need to do a sanity check here to see that there are *some* 
       bits left. */
	if (glopts->num_ancillary_bits > 0.6*adb) {
		/* Trying to reserve more than 60% of the frame.
		   0.6 is arbitrary. but since most applications
		   probably only want to reserve a few bytes, this seems fine.
		   Typical frame size is about 800bytes */
		fprintf(stderr,"You're trying to reserve more than 60%% of the mpeg frame for ancillary data\n");
		fprintf(stderr,"This is probably an error. But I'll keep going anyway...\n");
    } 

	adb -= glopts->num_ancillary_bits;


    /* MFC 26 July 2003
       Doing DAB became a bit harder in the reorganisation of the code.
       Now there is no guarantee that there is more than one frame in the bitbuffer.
       But DAB requires that the CRC for the *current* frame be written at the end 
       of the *previous* frame.
       Workaround: Users (Nicholas?) wanting to implement DAB will have to do some work
       in the frontend.
            First: Reserve some bits for yourself (options->num_ancillary_bits)
	    Second: Put the encoder into "single frame mode" i.e. only read 1152 samples
	            per channel. (frontendoptions->singleFrameMode)
	    Third: When you receive each mp2 frame back from the library, you'll have to insert
	           the options->dabCrc[i] values into the end of the frame yourself. (DAB crc calc is 
		   done below)
       The frontend will have to keep the previous frame in memory. 
       As of 26July all that needs to be done is for the frontend to buffer one frame in memory, such that
       the CRC for the next frame can be written in at the end of it.
    */

    {
		int gr, bl, ch;
		/* New polyphase filter
		 Combines windowing and filtering. Ricardo Feb'03 */
		for( gr = 0; gr < 3; gr++ )
		for ( bl = 0; bl < 12; bl++ )
		for ( ch = 0; ch < nch; ch++ )
			window_filter_subband( &glopts->smem, &glopts->buffer[ch][gr * 12 * 32 + 32 * bl], ch,
				 &(*glopts->sb_sample)[ch][gr][bl][0] );
    }

    scalefactor_calc(*glopts->sb_sample, glopts->scalar, nch, glopts->frame.sblimit);
    find_sf_max (glopts, glopts->scalar, glopts->max_sc);
    if (glopts->frame.actual_mode == TWOLAME_JOINT_STEREO) {
		/* this way we calculate more mono than we need */
		/* but it is cheap */
		combine_lr (*glopts->sb_sample, *glopts->j_sample, glopts->frame.sblimit);
		scalefactor_calc (glopts->j_sample, &glopts->j_scale, 1, glopts->frame.sblimit);
    }

    if ((glopts->quickmode == TRUE) && (++glopts->psycount % glopts->quickcount != 0)) {
		/* We're using quick mode, so we're only calculating the model every
		 'quickcount' frames. Otherwise, just copy the old ones across */
		for (ch = 0; ch < nch; ch++) {
			for (sb = 0; sb < SBLIMIT; sb++) {
				glopts->smr[ch][sb] = glopts->smrdef[ch][sb];
			}
		}
	} else {
		/* calculate the psymodel */
		switch (glopts->psymodel) {
			case -1:
				psycho_n1 (glopts, glopts->smr, nch);
			break;
			case 0:	/* Psy Model A */
				psycho_0 (glopts, glopts->smr, glopts->scalar);	
			break;
			case 1:
				psycho_1 (glopts, glopts->buffer, glopts->max_sc, glopts->smr);
			break;
			case 2:
				psycho_2 (glopts, glopts->buffer, sam, glopts->smr );	
			break;
			case 3:
				/* Modified psy model 1 */
				psycho_3 (glopts, glopts->buffer, glopts->max_sc, glopts->smr);
			break;
			case 4:
				psycho_4 (glopts, glopts->buffer, sam, glopts->smr );
			break;	
			default:
				fprintf (stderr, "Invalid psy model specification: %i\n", glopts->psymodel);
				return -1;
			break;
		}

		if (glopts->quickmode == TRUE) {
			/* copy the smr values and reuse them later */
			for (ch = 0; ch < nch; ch++) {
				for (sb = 0; sb < SBLIMIT; sb++) glopts->smrdef[ch][sb] = glopts->smr[ch][sb];
			}
		}
	}


    sf_transmission_pattern (glopts, glopts->scalar, glopts->scfsi);
    main_bit_allocation (glopts, glopts->smr, glopts->scfsi, glopts->bit_alloc, &adb);
#if 0 //MEANX
    if (glopts->error_protection)
      crc_calc (glopts, glopts->bit_alloc, glopts->scfsi, &glopts->crc);
#endif
    write_header (glopts, bs);
	if (glopts->error_protection)
		buffer_putbits (bs, glopts->crc, 16);
    
    head1=write_bit_alloc (glopts, glopts->bit_alloc, bs);

    head2=write_scalefactors(glopts, glopts->bit_alloc, glopts->scfsi, glopts->scalar, bs);


    
   //MEANX  printf("Bits: %d + %d = %d\n",head1,head2,head1+head2);
    subband_quantization (glopts, glopts->scalar, *glopts->sb_sample, glopts->j_scale, *glopts->j_sample, glopts->bit_alloc,
    			  *glopts->subband);
    write_samples(glopts, *glopts->subband, glopts->bit_alloc, bs);

    /* If not all the bits were used, write out a stack of zeros */
    for (i = 0; i < adb; i++)	buffer_put1bit (bs, 0);


    /* MFC July 03 
       Write an extra byte for 16/24/32/48 input when padding is on.
       Something must be going astray with the frame size calcs.
       This fudge works fine for the moment */
    if ((glopts->header.samplerate_idx != 0) && (glopts->padding)) // i.e. not a 44.1 or 22kHz input file
		buffer_putbits (bs, 0, 8);

    if (glopts->do_dab) {
		// Do the CRC calc for DAB stuff if required.
		// It will be up to the frontend to insert it into the end of the 
		// previous frame.
		for (i=glopts->dab_crc_len-1; i>=0; i--) {
			dab_crc_calc (glopts, glopts->bit_alloc, glopts->scfsi, glopts->scalar, &glopts->dab_crc[i], i);
		}
    }


	// Allocate space for the reserved ancillary bits
	for (i=0; i<glopts->num_ancillary_bits;i++) 
		buffer_put1bit(bs, 0);


	// Calulate the number of bits in this frame
    frameBits = buffer_sstell(bs) - initial_bits;
    if (frameBits % 8) {	/* a program failure */
		fprintf (stderr, "Sent %ld bits = %ld slots plus %ld\n", frameBits, frameBits/8, frameBits%8);
		fprintf (stderr, "If you are reading this, the program is broken\n");
		fprintf (stderr, "email %s with the command line arguments and other info\n", PACKAGE_BUGREPORT);
		return -1;
    }

    //fprintf(stdout,"Frame size: %li\n\n",frameBits/8);

	// *** FIXME currently broken njh Sept 04
    if (glopts->do_energy_levels)
    	do_energy_levels(glopts, bs);

  // MEANX: Recompute checksum
  if (glopts->error_protection)
  {
      unsigned char *begin=(initial_bits>>3)+bs->buf;
      int protectedBits=head1+head2;

           CRC_writeheader(protectedBits, begin);
  }
Пример #7
0
int main( int argc, char *argv[] )
{
  int   i;
  char  fn_inspeech[80], fn_outspeech[80];
  FILE  *fin, *fout;
  int   numread, nsamp;
  float temp[MAXSF];
  unsigned long frame_num;
  unsigned long total_frames;
  unsigned long fer_count;
  struct ENCODER_MEM     encoder_memory;
  struct DECODER_MEM     decoder_memory;
  struct PACKET          packet;
  struct CONTROL         control;
  int input_format;
  int output_format;

#if USE_CALLOC
  float *in_speech;
  float *out_speech;
#else
    float   in_speech[FSIZE+LPCSIZE-FSIZE+LPCOFFSET];
    float   out_speech[FSIZE];
#endif

  memset(&encoder_memory, 0, sizeof(encoder_memory));
  memset(&decoder_memory, 0, sizeof(decoder_memory));
  memset(&packet, 0, sizeof(packet));
  memset(&control, 0, sizeof(control));


#if USE_CALLOC
  alloc_mem_for_speech(&in_speech, &out_speech);
#endif

  for(i = 0; i < argc; i++)
    fprintf(stdout, "%s ", argv[i]);
  fprintf(stdout, "\n");

  parse_command_line(argc, argv, fn_inspeech, fn_outspeech, &control);

  initialize_encoder_and_decoder(&encoder_memory, &decoder_memory, 
				 &control);

  print_welcome_message();

  /*** Init TTY/TDD Routines and Varibles ***/

  if( tty_debug_flag )
      tty_debug();

  if( tty_option == TTY_NO_GAIN )
  {
      fprintf(stdout," TTY OPTION = NO GAIN\n");
      init_tty_enc( &tty_enc_char, &tty_enc_header, &tty_enc_baud_rate);
      init_tty_dec();
  }
  else
  {
      tty_option = 0;
      fprintf(stdout," TTY OPTION = OFF\n");
  }

  if( trans_fname != NULL )
  {
      fprintf(stdout,"FER SIMULATOR ON:  seed = %d\n",fer_sim_seed);
  }


  for(i = 0; i < LPCORDER; i++)
    packet.lsp[i] = packet.lpc[i] = 0;

  encoder_memory.frame_num = 0;
  frame_num = 0;
  fer_count = 0;

  if (control.decode_only == YES)
  {
    /* Input is a CELP file */
    switch (control.celp_file_format)
    {
    case FORMAT_PACKET:
      open_binary_input_file(&fin, fn_inspeech);
      total_frames = GetNumFrames(fin, sizeof(short)*WORDS_PER_PACKET);
      input_format = FORMAT_PACKET;
      break;
    case FORMAT_QCP:
      open_qcp_input_file(&fin, fn_inspeech);
      total_frames = get_qcp_packet_count();
      input_format = FORMAT_QCP;
      break;
    default:
      fprintf(stderr, "unsupported decode_only input format %d\n", control.celp_file_format);
      exit(-2);
    }
  }
  else
  {
    /* Input is an audio file */
    open_binary_input_file(&fin, fn_inspeech);
    input_format = FORMAT_RAW_AUDIO;
    total_frames = GetNumFrames(fin, sizeof(short)*FSIZE);
  }

  if ((control.form_res_out == YES)
    || (control.target_after_out == YES)
    || (control.cb_out == YES)
    || (control.pitch_out == YES))
  {
    /* Output is encoder state for debugging */
    open_binary_output_file(&fout, fn_outspeech);
    output_format = FORMAT_DEBUG_OUTPUT;
  }
  else if (control.encode_only == YES)
  {
    /* Output is a CELP file */
    switch (control.celp_file_format)
    {
    case FORMAT_PACKET:
      open_binary_output_file(&fout, fn_outspeech);
      output_format = FORMAT_PACKET;
      break;
    case FORMAT_QCP:
      open_qcp_output_file(&fout, fn_outspeech, total_frames);
      output_format = FORMAT_QCP;
      break;
    default:
      fprintf(stderr, "unsupported encode_only output format %d\n", control.celp_file_format);
      exit(-2);
    }
  }
  else
  {
    /* Output is an audio file */
    open_binary_output_file(&fout, fn_outspeech);
    output_format = FORMAT_RAW_AUDIO;
  }

  if(control.decode_only == NO)
  {
#if 0
    if (read_samples(fin, in_speech, LPCSIZE-FSIZE+LPCOFFSET)
	!=LPCSIZE-FSIZE+LPCOFFSET)
    {
      printf("Not even enough samples for 1 frame!\n");
      usage(&control);
    }
#else
    for( i=0 ; i < LPCSIZE-FSIZE+LPCOFFSET ; i++ )
    {
        in_speech[i] = 0;
    }
#endif
  }



  /*-----------------------------------------------
  *                   Main Loop
  *------------------------------------------------*/

  while( control.num_frames == UNLIMITED || frame_num < control.num_frames )
  {
    fprintf(stderr,"Processing %lu of %lu  FER = %.2f%%\r",
        frame_num, total_frames, 100.0*fer_count/(frame_num+1));

    if (control.decode_only==NO)
    {
        nsamp = read_samples(fin, &in_speech[LPCSIZE-FSIZE+LPCOFFSET], FSIZE);
        if( nsamp <= 0 )
        {
            break;
        }
        else if(nsamp < FSIZE)
        {
            for (i=nsamp; i<FSIZE; i++)
            {
                in_speech[LPCSIZE-FSIZE+LPCOFFSET+i]=0;
            }
        }

        encoder(in_speech, &packet, &control,
                &encoder_memory, out_speech);

        update_snr(ENCODER, in_speech, out_speech, &(control.snr));

    }

    if (control.decode_only==YES)
    {
      if (input_format == FORMAT_QCP)
      {
        numread = read_qcp_packet(fin, packet.data, WORDS_PER_PACKET);
        if (numread == 0) break;
      }
      else
      {
        /* FORMAT_PACKET */
        numread = read_packet(fin, packet.data, WORDS_PER_PACKET);
        if( numread != WORDS_PER_PACKET)
        {
            if(numread != 0)
            {
              fprintf(stderr,
                  "%s: Wrong number of words read: %d\n", argv[0], numread);
            }
            break;
        }
      }
    }

    if(control.encode_only==NO)
    {

        if (control.output_encoder_speech==NO)
        {
            decoder(out_speech, &packet, &control, &decoder_memory);

            if( packet.data[0] == ERASURE )
            {
                fer_count++;
            }

            if(control.decode_only==NO)
            {
                update_snr(DECODER, in_speech, out_speech, &(control.snr));
            }
        }
        i = write_samples(fout,out_speech,FSIZE); 
    }
    else
    {
        if( trans_fname != NULL )
        {
            fer_sim( &(packet.data[0]) );
        }
        if( packet.data[0] == ERASURE )
        {
            fer_count++;
        }

        if (output_format == FORMAT_QCP)
        {
            i = write_qcp_packet(fout, packet.data, WORDS_PER_PACKET);
        }
        else
        {
            i = write_packet(fout, packet.data, WORDS_PER_PACKET);
        }
    }


    /***** Update in_speech buffer ***************/

    for (i=0; i<LPCSIZE-FSIZE+LPCOFFSET; i++)
    {
        in_speech[i]=in_speech[i+FSIZE];
    }

    frame_num++;
    encoder_memory.frame_num = frame_num;

  } /* end main while() */

  if (output_format == FORMAT_QCP)
  {
    finish_qcp_output_file(fout);
  }

  fclose(fin);
  fclose(fout);

  if ((control.encode_only==NO)&&(control.decode_only==NO))
  {
    compute_snr(&(control.snr), &control);
  }
  if( control.decode_only == NO )
  {
      /* calculate the avg. rate for active speech for the entire file */
      temp[0] = (encoder_memory.full_cnt + encoder_memory.full_force +
	     encoder_memory.full_cnt_t + encoder_memory.full_force_t)*14.4+ 
	    (encoder_memory.half_cnt + encoder_memory.half_force +
	     encoder_memory.half_cnt_t + encoder_memory.half_force_t)*7.2+ 
	    (encoder_memory.quarter_cnt + encoder_memory.quarter_cnt_t)*3.6;
      temp[0] /= (encoder_memory.total_speech_frames+
	      (STATWINDOW-encoder_memory.block_cnt));

      if(control.reduced_rate_flag != 0)
      {
          printf("\n The target_snr_threshold at the end of the run was %f",
             encoder_memory.target_snr_thr);

          printf("\n The average rate for the entire file was %f",temp[0]);
          i = STATWINDOW-encoder_memory.block_cnt+encoder_memory.total_speech_frames;
          temp[1] = i;
          printf("\n The # of speech frames in the file is  = %d",i);

          i = encoder_memory.full_cnt+encoder_memory.full_cnt_t;
          printf("\n The percent of frames at 14.4 is %f",100.0*i/temp[1]);
          i = encoder_memory.full_force+encoder_memory.full_force_t;
          printf("\n The percent of frames forced to  14.4 is %f",100.*i/temp[1]);
          i = encoder_memory.half_cnt+encoder_memory.half_cnt_t;
          printf("\n The percent of frames at 7.2 is %f",100.*i/temp[1]);
          i = encoder_memory.half_force+encoder_memory.half_force_t;
          printf("\n The percent of frames forced to  7.2 is %f",100.*i/temp[1]);
          i = encoder_memory.quarter_cnt+encoder_memory.quarter_cnt_t;
          printf("\n The percent of frames coded at 3.6 is %f\n",100.*i/temp[1]);

      }
  }

  if(control.encode_only == NO)
    print_erasure_count();
  free_encoder_and_decoder(&encoder_memory, &decoder_memory);

#if USE_CALLOC
  free((char*) in_speech);
  free((char*) out_speech);
#endif

  print_farewell_message();

  exit(0);

}/* end of main() */
Пример #8
0
/*
	Encode a single frame of audio from 1152 samples
	Audio samples are taken from glopts->buffer
	Encoded bit stream is placed in to parameter bs
	(not intended for use outside the library)

	Returns the size of the frame
	or -1 if there is an error
*/
static int encode_frame(twolame_options * glopts, bit_stream * bs)
{
    int nch = glopts->num_channels_out;
    int sb, ch, adb, i;
    unsigned long frameBits, initial_bits;
    short sam[2][1056];

    if (!glopts->twolame_init) {
        fprintf(stderr, "Please call twolame_init_params() before starting encoding.\n");
        return -1;
    }
    // Scale and mix the input buffer
    scale_and_mix_samples(glopts);


    // Clear the saved audio buffer
    memset((char *) sam, 0, sizeof(sam));

    // Number of bits to calculate CRC on
    glopts->num_crc_bits = 0;

    // Store the number of bits initially in the bit buffer
    initial_bits = buffer_sstell(bs);

    adb = available_bits(glopts);

    /* allow the user to reserve some space at the end of the frame This will however leave fewer
       bits for the audio. Need to do a sanity check here to see that there are *some* bits left. */
    if (glopts->num_ancillary_bits > 0.6 * adb) {
        /* Trying to reserve more than 60% of the frame. 0.6 is arbitrary. but since most
           applications probably only want to reserve a few bytes, this seems fine. Typical frame
           size is about 800bytes */
        fprintf(stderr,
                "You're trying to reserve more than 60%% of the mpeg frame for ancillary data\n");
        fprintf(stderr, "This is probably an error. But I'll keep going anyway...\n");
    }

    adb -= glopts->num_ancillary_bits;


    /* The DAB scf-crc calc is done below. The frontend will have to keep the previous frame in
       memory. As of 09May 2014 all that needs to be done is for the frontend to buffer one frame in
       memory and call twolame_set_DAB_scf_crc */

    {
        int gr, bl, ch;
        /* New polyphase filter Combines windowing and filtering. Ricardo Feb'03 */
        for (gr = 0; gr < 3; gr++)
            for (bl = 0; bl < 12; bl++)
                for (ch = 0; ch < nch; ch++)
                    window_filter_subband(&glopts->smem,
                                          &glopts->buffer[ch][gr * 12 * 32 + 32 * bl], ch,
                                          &(*glopts->sb_sample)[ch][gr][bl][0]);
    }

    scalefactor_calc(*glopts->sb_sample, glopts->scalar, nch, glopts->sblimit);
    find_sf_max(glopts, glopts->scalar, glopts->max_sc);
    if (glopts->mode == TWOLAME_JOINT_STEREO) {
        // this way we calculate more mono than we need but it is cheap
        combine_lr(*glopts->sb_sample, *glopts->j_sample, glopts->sblimit);
        scalefactor_calc(glopts->j_sample, &glopts->j_scale, 1, glopts->sblimit);
    }

    if ((glopts->quickmode == TRUE) && (++glopts->psycount % glopts->quickcount != 0)) {
        /* We're using quick mode, so we're only calculating the model every 'quickcount' frames.
           Otherwise, just copy the old ones across */
        for (ch = 0; ch < nch; ch++) {
            for (sb = 0; sb < SBLIMIT; sb++) {
                glopts->smr[ch][sb] = glopts->smrdef[ch][sb];
            }
        }
    } else {
        // calculate the psymodel
        switch (glopts->psymodel) {
        case -1:
            psycho_n1(glopts, glopts->smr, nch);
            break;
        case 0:                // Psy Model A
            psycho_0(glopts, glopts->smr, glopts->scalar);
            break;
        case 1:
            psycho_1(glopts, glopts->buffer, glopts->max_sc, glopts->smr);
            break;
        case 2:
            psycho_2(glopts, glopts->buffer, sam, glopts->smr);
            break;
        case 3:
            // Modified psy model 1
            psycho_3(glopts, glopts->buffer, glopts->max_sc, glopts->smr);
            break;
        case 4:
            // Modified psy model 2
            psycho_4(glopts, glopts->buffer, sam, glopts->smr);
            break;
        default:
            fprintf(stderr, "Invalid psy model specification: %i\n", glopts->psymodel);
            return -1;
            break;
        }

        if (glopts->quickmode == TRUE) {
            // copy the smr values and reuse them later
            for (ch = 0; ch < nch; ch++) {
                for (sb = 0; sb < SBLIMIT; sb++)
                    glopts->smrdef[ch][sb] = glopts->smr[ch][sb];
            }
        }
    }


    sf_transmission_pattern(glopts, glopts->scalar, glopts->scfsi);
    main_bit_allocation(glopts, glopts->smr, glopts->scfsi, glopts->bit_alloc, &adb);

    write_header(glopts, bs);

    // Leave space for 2 bytes of CRC to be filled in later
    if (glopts->error_protection)
        buffer_putbits(bs, 0, 16);

    write_bit_alloc(glopts, glopts->bit_alloc, bs);
    write_scalefactors(glopts, glopts->bit_alloc, glopts->scfsi, glopts->scalar, bs);

    subband_quantization(glopts, glopts->scalar, *glopts->sb_sample, glopts->j_scale,
                         *glopts->j_sample, glopts->bit_alloc, *glopts->subband);
    write_samples(glopts, *glopts->subband, glopts->bit_alloc, bs);

    // If not all the bits were used, write out a stack of zeros
    for (i = 0; i < adb; i++)
        buffer_put1bit(bs, 0);


    /* MFC July 03 FIXME Write an extra byte for 16/24/32/48 input when padding is on. Something
       must be going astray with the frame size calcs. This fudge works fine for the moment */
    if ((glopts->header.samplerate_idx != 0) && (glopts->padding))  // i.e. not a 44.1 or 22kHz
        // input file
        buffer_putbits(bs, 0, 8);

    if (glopts->do_dab) {
        // Do the CRC calc for DAB stuff if required.
        // It will be up to the frontend to insert it into the end of the
        // previous frame.
        for (i = glopts->dab_crc_len - 1; i >= 0; i--) {
            dab_crc_calc(glopts, glopts->bit_alloc, glopts->scfsi, glopts->scalar,
                         &glopts->dab_crc[i], i);
        }
    }
    // Allocate space for the reserved ancillary bits
    for (i = 0; i < glopts->num_ancillary_bits; i++)
        buffer_put1bit(bs, 0);


    // Calulate the number of bits in this frame
    frameBits = buffer_sstell(bs) - initial_bits;
    if (frameBits % 8) {        /* a program failure */
        fprintf(stderr, "Sent %ld bits = %ld slots plus %ld\n", frameBits, frameBits / 8,
                frameBits % 8);
        fprintf(stderr, "If you are reading this, the program is broken\n");
        fprintf(stderr, "email %s with the command line arguments and other info\n",
                PACKAGE_BUGREPORT);
        return -1;
    }
    // Store the energy levels at the end of the frame
    if (glopts->do_energy_levels)
        do_energy_levels(glopts, bs);

    // MEANX: Recompute checksum from bitstream
    if (glopts->error_protection) {
        unsigned char *frame_ptr = bs->buf + (initial_bits >> 3);
        crc_writeheader(frame_ptr, glopts->num_crc_bits);
    }