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

sound.musicg.fingerprint.PairManager Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 Jacquet Wong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sound.musicg.fingerprint;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import sound.musicg.math.quicksort.QuickSortIndexPreserved;
import sound.musicg.properties.FingerprintProperties;

/**
 * Make pairs for the audio fingerprints, which a pair is used to group the same features together
 * 
 * @author jacquet
 *
 */
public class PairManager{

	FingerprintProperties fingerprintProperties=FingerprintProperties.getInstance();
	private int numFilterBanks=fingerprintProperties.getNumFilterBanks();
	private int bandwidthPerBank=fingerprintProperties.getNumFrequencyUnits()/numFilterBanks;
	private int anchorPointsIntervalLength=fingerprintProperties.getAnchorPointsIntervalLength();
	private int numAnchorPointsPerInterval=fingerprintProperties.getNumAnchorPointsPerInterval();
	private int maxTargetZoneDistance=fingerprintProperties.getMaxTargetZoneDistance();
	private int numFrequencyUnits=fingerprintProperties.getNumFrequencyUnits();
	
	private int maxPairs;
	private boolean isReferencePairing;
	private HashMap stopPairTable=new HashMap();
	
	/**
	 * Constructor
	 */
	public PairManager(){
		maxPairs=fingerprintProperties.getRefMaxActivePairs();
		isReferencePairing=true;
	}
	
	/**
	 * Constructor, number of pairs of robust points depends on the parameter isReferencePairing
	 * no. of pairs of reference and sample can be different due to environmental influence of source  
	 * @param isReferencePairing
	 */
	public PairManager(boolean isReferencePairing){
		if (isReferencePairing){
			maxPairs=fingerprintProperties.getRefMaxActivePairs();
		}
		else{
			maxPairs=fingerprintProperties.getSampleMaxActivePairs();
		}
		this.isReferencePairing=isReferencePairing;
	}
	
	/**
	 * Get a pair-positionList table
	 * It's a hash map which the key is the hashed pair, and the value is list of positions
	 * That means the table stores the positions which have the same hashed pair
	 * 
	 * @param fingerprint	fingerprint bytes
	 * @return pair-positionList HashMap
	 */
	public HashMap> getPair_PositionList_Table(byte[] fingerprint){
		
		List pairPositionList=getPairPositionList(fingerprint);
		
		// table to store pair:pos,pos,pos,...;pair2:pos,pos,pos,....
		HashMap> pair_positionList_table=new HashMap>();
		
		// get all pair_positions from list, use a table to collect the data group by pair hashcode
		Iterator pairPositionListIterator=pairPositionList.iterator();
		while (pairPositionListIterator.hasNext()){
			int[] pair_position=pairPositionListIterator.next();
			//System.out.println(pair_position[0]+","+pair_position[1]);
			
			// group by pair-hashcode, i.e.: >
			if (pair_positionList_table.containsKey(pair_position[0])){
				pair_positionList_table.get(pair_position[0]).add(pair_position[1]);
			}
			else{
				List positionList=new LinkedList();
				positionList.add(pair_position[1]);
				pair_positionList_table.put(pair_position[0], positionList);
			}
			// end group by pair-hashcode, i.e.: >
		}
		// end get all pair_positions from list, use a table to collect the data group by pair hashcode
		
		return pair_positionList_table;
	}
	
	// this return list contains: int[0]=pair_hashcode, int[1]=position
	private List getPairPositionList(byte[] fingerprint){
		
		int numFrames=FingerprintManager.getNumFrames(fingerprint);

		// table for paired frames
		byte[] pairedFrameTable=new byte[numFrames/anchorPointsIntervalLength+1];	// each second has numAnchorPointsPerSecond pairs only
		// end table for paired frames
		
		List pairList=new LinkedList();
		List sortedCoordinateList=getSortedCoordinateList(fingerprint);

		Iterator anchorPointListIterator=sortedCoordinateList.iterator();
		while (anchorPointListIterator.hasNext()){
			int[] anchorPoint=anchorPointListIterator.next();
			int anchorX=anchorPoint[0];
			int anchorY=anchorPoint[1];
			int numPairs=0;
			
			Iterator targetPointListIterator=sortedCoordinateList.iterator();
			while (targetPointListIterator.hasNext()){
				
				if (numPairs>=maxPairs){
					break;
				}
				
				if (isReferencePairing && pairedFrameTable[anchorX/anchorPointsIntervalLength]>=numAnchorPointsPerInterval){
					break;
				}

				int[] targetPoint=targetPointListIterator.next();
				int targetX=targetPoint[0];
				int targetY=targetPoint[1];
				
				if (anchorX==targetX && anchorY==targetY){
					continue;
				}
				
				// pair up the points
				int x1,y1,x2,y2;	// x2 always >= x1
				if (targetX>=anchorX){
					x2=targetX;
					y2=targetY;
					x1=anchorX;
					y1=anchorY;					
				}
				else{
					x2=anchorX;
					y2=anchorY;
					x1=targetX;
					y1=targetY;	
				}
				
				// check target zone
				if ((x2-x1)>maxTargetZoneDistance){
					continue;
				}
				// end check target zone
				
				// check filter bank zone				
				if (!(y1/bandwidthPerBank == y2/bandwidthPerBank)){
					continue;	// same filter bank should have equal value
				}
				// end check filter bank zone
				
				int pairHashcode=(x2-x1)*numFrequencyUnits*numFrequencyUnits+y2*numFrequencyUnits+y1;	
				
				// stop list applied on sample pairing only
				if (!isReferencePairing && stopPairTable.containsKey(pairHashcode)){
					numPairs++;	// no reservation
					continue;	// escape this point only							
				}
				// end stop list applied on sample pairing only
				
				// pass all rules
				pairList.add(new int[]{pairHashcode,anchorX});
				pairedFrameTable[anchorX/anchorPointsIntervalLength]++;
				//System.out.println(anchorX+","+anchorY+"&"+targetX+","+targetY+":"+pairHashcode+" ("+pairedFrameTable[anchorX/anchorPointsIntervalLength]+")");
				numPairs++;
				// end pair up the points
			}
		}
		
		return pairList;
	}
		
	private List getSortedCoordinateList(byte[] fingerprint){
		// each point data is 8 bytes 
		// first 2 bytes is x
		// next 2 bytes is y
		// next 4 bytes is intensity
		
		// get all intensities
		int numCoordinates=fingerprint.length/8;
		int[] intensities=new int[numCoordinates];
		for (int i=0; i sortedCoordinateList=new LinkedList();
		for (int i=sortIndexes.length-1; i>=0; i--){
			int pointer=sortIndexes[i]*8;
			int x=(int)(fingerprint[pointer]&0xff)<<8 | (int)(fingerprint[pointer+1]&0xff);
			int y=(int)(fingerprint[pointer+2]&0xff)<<8 | (int)(fingerprint[pointer+3]&0xff);
			sortedCoordinateList.add(new int[]{x,y});
		}
		return sortedCoordinateList;
	}

	/**
	 * Convert hashed pair to bytes
	 * 
	 * @param pairHashcode hashed pair
	 * @return byte array
	 */
	public static byte[] pairHashcodeToBytes(int pairHashcode){	
		return new byte[]{(byte)(pairHashcode>>8),(byte)pairHashcode};
	}
	
	/**
	 * Convert bytes to hased pair
	 * 
	 * @param pairBytes
	 * @return hashed pair
	 */
	public static int pairBytesToHashcode(byte[] pairBytes){	
		return (int)(pairBytes[0]&0xFF)<<8|(int)(pairBytes[1]&0xFF);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy