/*
* Copyright 2010 Jan Schmidt-Reinisch
*
* SoundComp - a sound processing library
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; in version 2.1
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* A scale is a table that maps "note names" to frequencies and other pitch related event information.
* It is instantiated per voice, not per process.
* The relevant information is queried on event generation and copied over to the event.
* Although it has a native stub for structural completeness reasons,
* it is not meant to be used in native context under any circumstances.
*/
package de.maramuse.soundcomp.process;
import java.util.Map;
import java.util.TreeMap;
import de.maramuse.soundcomp.process.StandardParameters.Parameter;
import de.maramuse.soundcomp.util.NativeObjects;
import de.maramuse.soundcomp.util.ReadOnlyMap;
import de.maramuse.soundcomp.util.ReadOnlyMapImpl;
import de.maramuse.soundcomp.util.NotImplementedException;
public class Scale implements NamedSource {
// a scale is a multicolumn table with multiple indexes:
// 1. index="name" (String), 2. index="index" (integer)
// and the following columns: frequency (real), pitch(integer), nextpitch (integer), prevpitch(integer)
// the prev and next may be null (at the ends of the scale. it is then impossible to advance further in transposing)
protected static class ScaleElement {
public final String name;
public final double frequency;
public final int pitch;
public final Integer nextpitch;
public final Integer prevpitch;
public ScaleElement(final String name, final double frequency, final int pitch,
final Integer nextpitch, final Integer prevpitch) {
this.name=name;
this.frequency=frequency;
this.pitch=pitch;
this.nextpitch=nextpitch;
this.prevpitch=prevpitch;
}
public ScaleElement(ScaleElement el) {
this.name=el.name;
this.frequency=el.frequency;
this.pitch=el.pitch;
this.nextpitch=el.nextpitch;
this.prevpitch=el.prevpitch;
}
}
private long nativeSpace;
protected String abstractName;
protected String instanceName;
protected Map<String, ScaleElement> theTableByName=new TreeMap<String, ScaleElement>();
protected Map<Integer, ScaleElement> theTableByIndex=new TreeMap<Integer, ScaleElement>();
private static ParameterMap outputsMap=new ParameterMap();
private static ReadOnlyMapImpl<Integer, ValueType> sourceTypes=new ReadOnlyMapImpl<Integer, ValueType>();
public Scale(){
NativeObjects.registerNativeObject(this);
}
public Scale(boolean s){
}
public void put(String name, double freq, int pitch, Integer next, Integer prev) {
ScaleElement elem=new ScaleElement(name, freq, pitch, next, prev);
theTableByName.put(name, elem);
theTableByIndex.put(pitch, elem);
}
public void put(ScaleElement elem) {
theTableByName.put(elem.name, elem);
theTableByIndex.put(elem.pitch, elem);
}
/**
* get the frequency to the note "o"
*
* @param o
* the name of the note whose frequency we want
* @return the frequency
*/
public double get(String o) {
try{
return theTableByName.get(o).frequency;
}catch(Exception ex){
return Double.NaN;
}
}
/**
* get the pitch (table index) to the note "o"
*
* @param o
* the name of the note whose frequency we want
* @return the frequency. If "o" does not exist, return MIN_VALUE
*/
public int getPitch(String o) {
try{
return theTableByName.get(o).pitch;
}catch(Exception ex){
return Integer.MIN_VALUE;
}
}
/**
* get the frequency to the note "o"
*
* @param o
* the pitch of the note whose frequency we want
* @return the frequency
*/
public double get(int o) {
try{
return theTableByIndex.get(o).frequency;
}catch(Exception ex){
return Double.NaN;
}
}
/**
* get the frequency of the note "o" transposed by "trans"
*
* @param o
* @param trans
* @return
*/
public double get(String o, int trans) {
try{
int index=theTableByName.get(o).pitch;
return theTableByIndex.get(index+trans).frequency;
}catch(Exception ex){
return Double.NaN;
}
}
@Override
public void setAbstractName(String abstractName) {
this.abstractName=abstractName;
}
@Override
public String getAbstractName() {
return abstractName;
}
@Override
public void setInstanceName(String instanceName) {
this.instanceName=instanceName;
}
@Override
public String getInstanceName() {
return instanceName;
}
@Override
public void advanceState() {
// nothing to do
}
@Override
public void advanceOutput() {
// nothing to do
}
@Override
public long getNativeSpace() {
return nativeSpace;
}
@Override
public ReadOnlyMap<Integer, ValueType> getSourceTypes() {
return sourceTypes;
}
/**
* getValue throws an exception. It is not meant to be called.
*/
@Override
public double getValue(int index){
throw new NotImplementedException();
}
/**
* This is called on event generation
* @param index the pitch
* @return the frequency for pitch "index"
*/
public double getValueFor(int index) {
ScaleElement elem=theTableByIndex.get(index);
if(elem==null)throw new IllegalArgumentException("no scale entry in scale "+abstractName+" for key "+index);
return elem.frequency;
}
/**
* This is called on event generation
* @param name the note name for this event
* @return the frequency for the pitch "name" transposed by "transpose"
*/
public double getValueFor(String name) {
ScaleElement elem=theTableByName.get(name);
if(elem==null)throw new IllegalArgumentException("no scale entry in scale "+abstractName+" for name "+name);
return elem.frequency;
}
/**
* This is called on event generation
* @param name the note name for this event
* @param transpose the pitch transpose value
* @return the frequency for the pitch "name" transposed by "transpose"
*/
public double getValueFor(String name, int transpose) {
ScaleElement elem=theTableByName.get(name);
if(elem==null)throw new IllegalArgumentException("no scale entry in scale "+abstractName+" for name "+name);
int index=elem.pitch+transpose;
elem=theTableByIndex.get(index);
if(elem==null)throw new IllegalArgumentException("no scale entry in scale "+abstractName+" for name "+name+" transposed by "+transpose);
return elem.frequency;
}
@Override
public ReadOnlyMap<String, Parameter> outputsByName() {
return outputsMap;
}
}