All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.axet.libvorbis.Jvorbis_block Maven / Gradle / Ivy

package com.github.axet.libvorbis;

import com.github.axet.libogg.Jogg_packet;
import com.github.axet.libogg.Joggpack_buffer;

/**
vorbis_block is a single block of data to be processed as part of
the analysis/synthesis stream; it belongs to a specific logical
bitstream, but is independent from other vorbis_blocks belonging to
that logical bitstream.
*/
public final class Jvorbis_block {
	/* used only to control memory
	private class Jalloc_chain {
		private byte[] ptr;
		private Jalloc_chain next;
	}*/
	/* necessary stream state for linking to the framing abstraction */
	/** this is a pointer into local storage */
	float[][] pcm = null;
	final Joggpack_buffer opb = new Joggpack_buffer();

	int lW = 0;
	int W  = 0;
	int nW = 0;
	int pcmend = 0;
	int mode   = 0;

	boolean eofflag = false;
	long granulepos = 0;
	long sequence   = 0;
	/** For read-only access of configuration */
	Jvorbis_dsp_state vd = null;

	/* local storage to avoid remallocing; it's up to the mapping to
	   structure it */
	/* used only to control memory
	private byte[] localstore = null;
	private int localtop   = 0;
	private int localalloc = 0;
	private int totaluse   = 0;
	private Jalloc_chain reap = null;*/

	/* bitmetrics for the frame */
	int glue_bits  = 0;
	int time_bits  = 0;
	int floor_bits = 0;
	int res_bits   = 0;

	/** public void *internal; */
	Jvorbis_block_internal m_internal = null;

	final void clear() {
		pcm = null;
		opb.clear();

		lW     = 0;
		W      = 0;
		nW     = 0;
		pcmend = 0;
		mode   = 0;

		eofflag    = false;
		granulepos = 0;
		sequence   = 0;

		vd = null;
		/*
		localstore = null;
		localtop   = 0;
		localalloc = 0;
		totaluse   = 0;
		reap       = null;
		 */
		/* bitmetrics for the frame */
		glue_bits  = 0;
		time_bits  = 0;
		floor_bits = 0;
		res_bits   = 0;

		m_internal = null;
	}

	/* block abstraction setup *********************************************/
/*
	//#ifndef WORD_ALIGN
	//#define WORD_ALIGN 8
	private static final int WORD_ALIGN = 8;
	//#endif
	final int _vorbis_block_alloc(int bytes) {
		bytes = (bytes + (WORD_ALIGN - 1)) & ~(WORD_ALIGN - 1);
		if( bytes + this.m_localtop > this.m_localalloc ) {
			// can't just _ogg_realloc... there are outstanding pointers
			if( this.m_localstore != null ) {
				Jalloc_chain link = new Jalloc_chain();
				this.m_totaluse += this.m_localtop;
				link.next = this.m_reap;
				//link.ptr = this.m_localstore;
				link.ptr = new byte[ this.m_localtop ];
				System.arraycopy( this.m_localstore, 0, link.ptr, 0, this.m_localtop );
				this.m_reap = link;
			}
			// highly conservative
			this.m_localalloc = bytes;
			this.m_localstore = new byte[this.m_localalloc];
			this.m_localtop = 0;
		}
		{
			//void *ret = (void *)(((char *)vb.localstore) + vb.localtop);
			int ret = this.m_localtop;
			this.m_localtop += bytes;
			return ret;
		}
	}//
*/
	/** reap the chain, pull the ripcord */
	/*final void _vorbis_block_ripcord() {
		// reap the chain
		Jalloc_chain reap = this.m_reap;
		while( reap != null ) {
			Jalloc_chain next = this.m_reap.next;
			//_ogg_free( reap.ptr );
			//memset( reap,0,sizeof(*reap) );
			//_ogg_free( reap );
			reap = next;
		}
		// consolidate storage
		if( this.m_totaluse != 0 ) {
			this.m_localstore = Arrays.copyOf( this.m_localstore, this.m_totaluse + this.m_localalloc );
			this.m_localalloc += this.m_totaluse;
			this.m_totaluse = 0;
		}

		// pull the ripcord
		this.m_localtop = 0;
		this.m_reap = null;
	}
*/
	public final int vorbis_block_clear() {
		//int i;
		//Jvorbis_block_internal vbi = this.m_internal;

		//_vorbis_block_ripcord();
		//this.m_localstore = null;

		//if( vbi != null ) {
		//	for( i = 0; i < Jvorbis_block_internal.PACKETBLOBS; i++ ) {
		//		Joggpack_buffer.oggpack_writeclear( vbi.packetblob[i] );
		//		if( i != Jvorbis_block_internal.PACKETBLOBS / 2 ) vbi.packetblob[i] = null;
		//	}
			//vbi = null;
		//}
		clear();
		return (0);
	}

	// analysis.c
	/** decides between modes, dispatches to the appropriate mapping. */
	public final int vorbis_analysis(final Jogg_packet op) {
		final int ret;
		// final Jvorbis_block_internal vbi = this.m_internal;

		this.glue_bits = 0;
		this.time_bits = 0;
		this.floor_bits = 0;
		this.res_bits = 0;

		/* first things first.  Make sure encode is ready */
		final Joggpack_buffer[] p = this.m_internal.packetblob;// java
		for( int i = 0; i < Jvorbis_info.PACKETBLOBS; i++ ) {
			p[i].oggpack_reset();
		}

		/* we only have one mapping type (0), and we let the mapping code
 		 itself figure out what soft mode to use.  This allows easier
 		 bitrate management */

		if( (ret = Jcodec._mapping_P[0].forward( this )) != 0 ) {
			return (ret);
		}

		if( op != null ) {
			if( vorbis_bitrate_managed() ) {
				/* The app is using a bitmanaged mode... but not using the
 				 bitrate management interface. */
				return (Jcodec.OV_EINVAL);
			}

			op.packet_base = this.opb.oggpack_get_buffer();
			op.packet = 0;
			op.bytes = this.opb.oggpack_bytes();
			op.b_o_s = false;
			op.e_o_s = this.eofflag;
			op.granulepos = this.granulepos;
			op.packetno = this.sequence; /* for sake of completeness */
		}
		return (0);
	}

	// synthesis.c
	public final int vorbis_synthesis(final Jogg_packet op) {
		final Jvorbis_dsp_state vdsp = this.vd;
		final Jprivate_state    b = vdsp != null ? vdsp.backend_state : null;
		final Jvorbis_info      vi = vdsp != null ? vdsp.vi : null;
		final Jcodec_setup_info ci = vi != null ? vi.codec_setup : null;
		final Joggpack_buffer   pb = this.opb;

		if( vdsp == null || b == null || vi == null || ci == null || pb == null ) {
			return Jcodec.OV_EBADPACKET;
		}

		/* first things first.  Make sure decode is ready */
		//Jvorbis_block._vorbis_block_ripcord( vb );
		pb.oggpack_readinit( op.packet_base, op.packet, op.bytes );

		/* Check the packet type */
		if( pb.oggpack_read( 1 ) != 0 ) {
			/* Oops.  This is not an audio data packet */
			return (Jcodec.OV_ENOTAUDIO);
		}

		/* read our mode and pre/post windowsize */
		final int m = pb.oggpack_read( b.modebits );
		if( m == -1 ) {
			return (Jcodec.OV_EBADPACKET);
		}

		this.mode = m;
		final Jvorbis_info_mode mp = ci.mode_param[m];// java
		if( mp == null ) {
			return (Jcodec.OV_EBADPACKET);
		}

		this.W = mp.blockflag;
		if( this.W != 0 ) {

			/* this doesn;t get mapped through mode selection as it's used
		   		only for window selection */
			this.lW = pb.oggpack_read( 1 );
			this.nW = pb.oggpack_read( 1 );
			if( this.nW == -1 ) {
				return (Jcodec.OV_EBADPACKET);
			}
		} else {
			this.lW = 0;
			this.nW = 0;
		}

		/* more setup */
		this.granulepos = op.granulepos;
		this.sequence = op.packetno;
		this.eofflag = op.e_o_s;

		/* alloc pcm passback storage */
		this.pcmend = ci.blocksizes[this.W];
		this.pcm = new float[vi.channels][this.pcmend];

		/* unpack_header enforces range checking */
		final int type = ci.map_type[mp.mapping];

		return (Jcodec._mapping_P[type].inverse( this, ci.map_param[mp.mapping] ) );
	}

	/** used to track pcm position without actually performing decode.
	Useful for sequential 'fast forward' */
	public final int vorbis_synthesis_trackonly(final Jogg_packet op) {
		final Jvorbis_dsp_state vdsp = this.vd;
		final Jprivate_state    b = vdsp.backend_state;
		final Jvorbis_info      vi = vdsp.vi;
		final Jcodec_setup_info ci = vi.codec_setup;
		final Joggpack_buffer   pb = this.opb;

		/* first things first.  Make sure decode is ready */
		//Jvorbis_block._vorbis_block_ripcord( vb );
		pb.oggpack_readinit( op.packet_base, op.packet, op.bytes );

		/* Check the packet type */
		if( pb.oggpack_read( 1 ) != 0 ){
			/* Oops.  This is not an audio data packet */
			return (Jcodec.OV_ENOTAUDIO);
		}

		/* read our mode and pre/post windowsize */
		final int m = pb.oggpack_read( b.modebits );
		if( m == -1 ) {
			return( Jcodec.OV_EBADPACKET );
		}

		this.mode = m;
		if( ci.mode_param[m] == null ) {
			return (Jcodec.OV_EBADPACKET);
		}

		this.W = ci.mode_param[m].blockflag;
		if( this.W != 0 ) {
			this.lW = pb.oggpack_read( 1 );
			this.nW = pb.oggpack_read( 1 );
			if( this.nW == -1 ) {
				return (Jcodec.OV_EBADPACKET);
			}
		} else {
			this.lW = 0;
			this.nW = 0;
		}

		/* more setup */
		this.granulepos = op.granulepos;
		this.sequence = op.packetno;
		this.eofflag = op.e_o_s;

		/* no pcm */
		this.pcmend = 0;
		this.pcm = null;

		return (0);
	}

	// bitrate.c
	final boolean vorbis_bitrate_managed() {
		// final Jvorbis_dsp_state      vd = this.vd;
		// final Jprivate_state          b = vd.backend_state;
		final Jbitrate_manager_state bm = this.vd.backend_state.bms;// b.bms;

		if( bm != null && bm.managed != 0 ) {
			return true;
		}
		return false;
	}

	/** finish taking in the block we just processed */
	public final int vorbis_bitrate_addblock() {
		final Jvorbis_dsp_state      vdsp = this.vd;
		final Jprivate_state         b = vdsp.backend_state;
		final Jbitrate_manager_state bm = b.bms;

		if( bm.managed == 0 ) {
			/* not a bitrate managed stream, but for API simplicity, we'll
			 * buffer the packet to keep the code path clean */

			if( bm.vb != null ) {
				return (-1); /* one has been submitted without being claimed */
			}
			bm.vb = this;
			return (0);
		}

		bm.vb = this;

		final Jvorbis_info           vi = vdsp.vi;
		final Jcodec_setup_info      ci = vdsp.vi.codec_setup;
		final Jbitrate_manager_info  bi = ci.bi;

		int choice = (int)Math.rint( bm.avgfloat );
		final Joggpack_buffer[] packetblob = this.m_internal.packetblob;
		int this_bits = packetblob[choice].oggpack_bytes() << 3;// * 8;
		final int min_target_bits = (this.W != 0 ? bm.min_bitsper * bm.short_per_long : bm.min_bitsper);
		final int max_target_bits = (this.W != 0 ? bm.max_bitsper * bm.short_per_long : bm.max_bitsper);
		final int samples = ci.blocksizes[this.W] >> 1;
		final int desired_fill = (int)(bi.reservoir_bits * bi.reservoir_bias);

		/* look ahead for avg floater */
		if( bm.avg_bitsper > 0 ) {
			double slew = 0.;
			final int avg_target_bits = (this.W != 0 ? bm.avg_bitsper * bm.short_per_long : bm.avg_bitsper);
			final double slewlimit = 15. / bi.slew_damp;

			/* choosing a new floater:
			   if we're over target, we slew down
			   if we're under target, we slew up

			   choose slew as follows: look through packetblobs of this frame
			   and set slew as the first in the appropriate direction that
			   gives us the slew we want.  This may mean no slew if delta is
			   already favorable.

			   Then limit slew to slew max */
			final int avg_reservoir = bm.avg_reservoir;// java
			if( avg_reservoir + (this_bits - avg_target_bits) > desired_fill ) {
				while( choice > 0 && this_bits > avg_target_bits &&
					avg_reservoir + (this_bits - avg_target_bits) > desired_fill ) {
					choice--;
					this_bits = packetblob[choice].oggpack_bytes() << 3;// * 8;
				}
			} else if( avg_reservoir + (this_bits - avg_target_bits) < desired_fill ) {
				while( choice + 1 < Jvorbis_info.PACKETBLOBS && this_bits < avg_target_bits &&
						avg_reservoir + (this_bits - avg_target_bits) < desired_fill ) {
					choice++;
					this_bits = packetblob[choice].oggpack_bytes() << 3;// * 8;
				}
			}

			slew = (int)(Math.rint( choice - bm.avgfloat ) / samples * vi.rate);
			if( slew < -slewlimit ) {
				slew = -slewlimit;
			}
			if( slew > slewlimit ) {
				slew = slewlimit;
			}
			choice = (int)(Math.rint( bm.avgfloat += slew / vi.rate * samples ));
			this_bits = packetblob[choice].oggpack_bytes() << 3;// * 8;
		}

		/* enforce min(if used) on the current floater (if used) */
		if( bm.min_bitsper > 0 ) {
			/* do we need to force the bitrate up? */
			if( this_bits < min_target_bits ) {
				final int minmax_reservoir = bm.minmax_reservoir;// java
				while( minmax_reservoir - (min_target_bits - this_bits) < 0 ) {
					choice++;
					if( choice >= Jvorbis_info.PACKETBLOBS ) {
						break;
					}
					this_bits = packetblob[choice].oggpack_bytes() << 3;// * 8;
				}
			}
		}

		/* enforce max (if used) on the current floater (if used) */
		if( bm.max_bitsper > 0 ) {
			/* do we need to force the bitrate down? */
			if( this_bits > max_target_bits ) {
				final int minmax_reservoir = bm.minmax_reservoir;// java
				while( minmax_reservoir + (this_bits - max_target_bits) > bi.reservoir_bits ) {
					choice--;
					if( choice < 0 ) {
						break;
					}
					this_bits = packetblob[choice].oggpack_bytes() << 3;// * 8;
				}
			}
		}

		/* Choice of packetblobs now made based on floater, and min/max
		   requirements. Now boundary check extreme choices */

		if( choice < 0 ) {
			/* choosing a smaller packetblob is insufficient to trim bitrate.
			   frame will need to be truncated */
			final int maxsize = (max_target_bits + (bi.reservoir_bits - bm.minmax_reservoir)) / 8;// java: can be negative, don't use >>
			bm.choice = choice = 0;

			if( packetblob[choice].oggpack_bytes() > maxsize ) {

				packetblob[choice].oggpack_writetrunc( maxsize << 3 );// * 8 );
				this_bits = packetblob[choice].oggpack_bytes() << 3;// * 8;
			}
		} else {
			int minsize = (min_target_bits - bm.minmax_reservoir + 7) / 8;// java: can be negative, don't use >>
			if( choice >= Jvorbis_info.PACKETBLOBS ) {
				choice = Jvorbis_info.PACKETBLOBS - 1;
			}

			bm.choice = choice;

			/* prop up bitrate according to demand. pad this frame out with zeroes */
			minsize -= packetblob[choice].oggpack_bytes();
			while( minsize-- > 0 ) {
				packetblob[choice].oggpack_write( 0, 8 );
			}
			this_bits = packetblob[choice].oggpack_bytes() << 3;// * 8;

		}

		/* now we have the final packet and the final packet size.  Update statistics */
		/* min and max reservoir */
		if( bm.min_bitsper > 0 || bm.max_bitsper > 0 ) {

			if( max_target_bits > 0 && this_bits > max_target_bits ) {
				bm.minmax_reservoir += (this_bits - max_target_bits);
			} else if( min_target_bits > 0 && this_bits < min_target_bits ) {
				bm.minmax_reservoir += (this_bits - min_target_bits);
			} else {
				/* inbetween; we want to take reservoir toward but not past desired_fill */
				if( bm.minmax_reservoir > desired_fill ) {
					if( max_target_bits > 0 ) {/* logical bulletproofing against initialization state */
						bm.minmax_reservoir += (this_bits - max_target_bits);
						if( bm.minmax_reservoir < desired_fill ) {
							bm.minmax_reservoir = desired_fill;
						}
					} else {
						bm.minmax_reservoir = desired_fill;
					}
				} else {
					if( min_target_bits > 0 ) { /* logical bulletproofing against initialization state */
						bm.minmax_reservoir += (this_bits - min_target_bits);
						if( bm.minmax_reservoir > desired_fill ) {
							bm.minmax_reservoir = desired_fill;
						}
					} else {
						bm.minmax_reservoir = desired_fill;
					}
				}
			}
		}

		/* avg reservoir */
		if( bm.avg_bitsper > 0 ) {
			final int avg_target_bits = (this.W != 0 ? bm.avg_bitsper * bm.short_per_long : bm.avg_bitsper);
			bm.avg_reservoir += this_bits - avg_target_bits;
		}

		return (0);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy