// Copyright (C) 2004 David Griffiths // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include #include #include #include "Tuna.h" static const float MAX_LUT_FREQ = 24000.0; // (maximum audible freq (apparently)) Tuna::Tuna() : m_Buffer(NULL), m_Root(440.0), m_Highest(0) { // start off with boring equal temp m_NumNotes=12; m_Scale.push_back(1+100/1200.0); m_Scale.push_back(1+200/1200.0); m_Scale.push_back(1+300/1200.0); m_Scale.push_back(1+400/1200.0); m_Scale.push_back(1+500/1200.0); m_Scale.push_back(1+600/1200.0); m_Scale.push_back(1+700/1200.0); m_Scale.push_back(1+800/1200.0); m_Scale.push_back(1+900/1200.0); m_Scale.push_back(1+1000/1200.0); m_Scale.push_back(1+1100/1200.0); m_Scale.push_back(2); CalculateNoteLUT(); } Tuna::~Tuna() { } bool Tuna::Open(const string &filename) { FILE *file = fopen(filename.c_str(),"r"); if (!file) { cerr<<"Tuna::Open: could not open "<::iterator i=m_Scale.begin(); i!=m_Scale.end(); i++) { cerr<<*i<::iterator i=m_NoteLUT.begin(); i!=m_NoteLUT.end(); i++) { cerr<<*i<m_Highest) { out=m_Highest; return m_NoteLUT.size(); } // or too low? if (in<=*m_NoteLUT.begin()) { out=*m_NoteLUT.begin(); return 1; } // snap frequency from 'in' to the nearest specified by the LUT return FindClosest(in, 0, m_NoteLUT.size(), out, usefilter); } // binary chop to the closest LUT freq int Tuna::FindClosest(float in, unsigned int low, int unsigned high, float &out, bool usefilter) { unsigned int mid = (high+low)/2; // if the value is somewhere between the next smallest, and next biggest if (in>=m_NoteLUT[mid-1] && in<=m_NoteLUT[mid+1]) { float closest = FLT_MAX; int index = 0; // need to search a whole octave for the right note, // as some or all may be disabled by the filter... unsigned int halfoctave = m_NumNotes/2; for (unsigned int n=mid-halfoctave; n=0 && nm_NoteLUT[mid]) { //cerr<<"going high "<::iterator i=m_Scale.begin(); i!=m_Scale.end(); i++) { m_Highest = pow(2.0f,*i)*freq; m_NoteLUT.push_back(m_Highest/16.0f); } freq*=2; } } float Tuna::GetNote(unsigned int index) { //int ANote = 69; //float AFreq = 440.0; //return (pow(2.0,index/12.0)*AFreq)/4.0f; //12tET if (index>=m_Scale.size()) index%=m_NoteLUT.size(); return m_NoteLUT[index]; } /* int Tuna::SnapFrequency(float in, float &out, bool usefilter) { float normalised = in/m_Root; int octave=0; if (normalised>=1) octave = (int)floor(normalised); else octave = -(int)floor(1/normalised); float scaletarget = 1+(normalised-abs(octave)); out = 0; // quantise fractional part float closest = FLT_MAX; int note=-1; for (int i=0; i<=m_Scale.size(); i++) { float distance = fabs(scaletarget-m_Scale[i]); if (distance2) out-=1; // stick whole number back on for octave cerr<=0) out+=octave; else out/=(float)abs(octave); // calculate back into frequency out*=m_Root; cerr<