You can't have unlimited resolution without unlimited bandwidth.
Of course, that has been my point.
This does not mean that peaks move.
Your criticisms are not consistent. When I quoted you as implying peaks would not move due to lowpassing, you said I misquoted you while crying 'abuse'. So you have me warned while berating my lack of contemporary study and making inconsistent demands to perform various pet excercises.
Im not your student.
You're doing nobody any good by failing to read up on the field you're talking about before you work.
Untrue. I limit my research to protect my originality. Education is to Innovation what Masterbation is to Procreation I have learned adequate tools at home, school and university and beyond to suit my own designs. Ive never been forced to research previous solutions to computational problems -except for a while when I began learning to program -quite intensively, around the age of 9.
As to your experiments, they prove nothing until you specificially produce the ***exact*** equations, and explain your reasoning.
You demand exact equations and provide only irrelevant ones. To suggest I have not explained my reasoning in this thread is absurd.
@all,
I have only been trying to defend sensible, intuitive, practical use of terminology here by argueing against the idea forwarded - that "time resolution" of pcm is practicaly finer than the samplerate.
As explained previously, i understand that processes can maintain timing details in source which is suitably limited to particular samplerates bandwidth. But processes cannont recover timing details once bandwidth is limited. This means downsampling potentialy and normaly does damage 'time resolution'.
Despite a heavy bias to not examine the practical limitations on time resolution of samplerate, some expert contributers in this thread, have acknowledged that measureable timing details will be routinely distorted by downsampling at normal audio rates. I am not concerned with the audibility of such distortion, only its existence and its limits.
It has been much work trying to have it fairly examined in such a heated and onesided discussion. I do suspect others have better experience to estimate the situation than myself, but seem ideologicaly unwilling to do so.
I have tried to rise to the groups challenge and do some work to illustrate the situation,
heres a scrappy program, not quite finished, but I hope some might appreciate my input so far...
The central chunks of code are:
int nodi=1; //count of node found
int pregrad,pstgrad; //approximate derivatives
for( int ndfi=0; ndfi<samsGet; ndfi++) //ndfi = time index( samples loop )
{ smx2=smx1; smx1=smx0; smx0=retSam[ndfi];
pregrad=smx1-smx2;
pstgrad=smx0-smx1;
if((pregrad*pstgrad<-1)&&(Math.abs(pregrad-pstgrad)>100))
{ nodes[nodi++]=(ndfi<<8)+( (512*pstgrad+1) / ( ((pstgrad-pregrad)*2)+1) ); }
//record simple linear solution of 1st derivative=0
//expression: (( (512*pstgrad+1) / (((pstgrad-pregrad)*2)+1) )) produces ~ 0-255
//node units are samplesize/256 (1/256th of sample interval)
}//end for(ndfi)
This finds 'nodes' in pcm, approximately the presence and position of major peaks and troughs
and for(int aninx=1; aninx<=endnodea; aninx++) //ninx is node index
{ int findtime=anodes[aninx]; //next node to find (units of sample*256)
findfit=maxoff; //Maximum distance for fit
paired=false;
for(int findnode=lastfind; (findnode<endnodeb)&&(bnodes[findnode]<(findtime+maxoff)); findnode++)
{ if(Math.abs(findfit)>Math.abs(findtime-bnodes[findnode]))
{ findfit=findtime-bnodes[findnode];
lastfind=findnode; paired=true;
}
}
if(paired){ discreps[nndi++]=findfit; paired=false; }
else{ missnode++; }
}//end looping through 1 buffer
This finds a nodes nearest neighbour in parallel track and records its descrepancy
whole program (warning spaghetti/frankenstien)
import java.io.*;
class nodecouple
{ //int[] series = new int[80000];
public static void main(String[] args) /* main */
{ nodecouple nodecoup = new nodecouple(args); //creates instance of self for javas nonstatic context hooha
System.exit(1); } //graceless exit better than hang
public nodecouple(String[] args)
{ int chnksize=1024; //what length
int chnkread=1000; //how many
int srcsamx=4; //?
int maxoff=128; //maximum distance between pairings
int mgfy=1; //magnify record
System.out.println("Reading in"+args[0]+"\n");
getNodesWave tookWav1 = new getNodesWave(args[0], chnksize/mgfy);
//int[] test0=tookWav1.getnodes(0);
System.out.println("And Reading "+args[1]+"\n");
getNodesWave tookWav2 = new getNodesWave(args[1], chnksize);
if(tookWav1.totlFrames<chnksize*chnkread)
{ chnkread=tookWav1.totlFrames/chnksize; };
long ThScnds=((chnksize*chnkread)*1000/tookWav1.Samprate);
System.out.print("Only reading first "+ThScnds/1000+"."+(ThScnds%1000)/100+""+(ThScnds%100)/10+""+(ThScnds%10));
System.out.print(" seconds");
if(tookWav1.channels>1)
{ System.out.print(" (of 1 channel)"); }
System.out.println("(Change chnkread for more)");
int[] discreps= new int[(chnksize*chnkread)]; //(impossible maximum size for discreps)
int nndi=0; //count of nodes found
int missnode=0;
int endnodea=0,endnodeb=0;
int endnodeSuma=0,endnodeSumb=0;
System.out.println("\nLocating Nodes...");
for(int chnk=0; chnk<chnkread; chnk++) //refresh chunks to read
{ int[] anodes=tookWav1.getnodes(0); //nodes in a's chunk
int[] bnodes=tookWav2.getnodes(0); //nodes in b's chunk
endnodea=anodes[0]; //length of array is stored in first position (lowsampled one)
endnodeb=bnodes[0]; //length of array is stored in first position
endnodeSuma+=endnodea;
endnodeSumb+=endnodeb;
/*debout("a:"+endnodea, 9); debout("b:"+endnodeb, 6);
if(chnk%6==5){ debout("\n", 0); } */
int timedif;
int lastfind=1; //to be remind of position of previous couple
boolean paired = false;
int findfit;
for(int aninx=1; aninx<=endnodea; aninx++) //ninx is node index
{ int findtime=anodes[aninx]*mgfy; //next node to find (units of sample*256)
findfit=maxoff; //Maximum distance for fit
paired=false;
//note: sign of nodetime could be bodged to reflect peak or valley.
for(int findnode=lastfind; (findnode<endnodeb)&&(Math.abs(bnodes[findnode])<(findtime+maxoff)); findnode++)
{ if(Math.abs(findfit)>Math.abs(findtime-Math.abs(bnodes[findnode])))
{ findfit=findtime-bnodes[findnode];
if(findfit==-1){ debout("!",2); }
lastfind=findnode; paired=true;
}
}
if(paired){ discreps[nndi++]=findfit; paired=false; }
else{ missnode++; }
}//end looping through 1 buffer
}//end looping through all buffers
System.out.println("\nTotal nodes in: "+args[0]+":"+endnodeSuma);
System.out.println("Total nodes in: "+args[1]+":"+endnodeSumb);
System.out.println("\nMissednodes="+missnode+", discreps="+nndi+", Searchednodes="+endnodeSuma+"\n");
/*System.out.println("\nTime differences List..."); //dump all discreps
for(int tal=0; tal<nndi; tal++)
{ debout(""+discreps[tal],5); if(tal%16==15){ System.out.println(); }
}*/
int maxtallie=1;
int histbars=25;
int histrange=maxoff*2;
int[] tallie = new int[histbars];
int budge=histrange/((histbars-1)*2);
for(int npair=0; npair<nndi; npair++) //do tallie count
{ int valo=discreps[npair];
if(valo>-histrange/2)
{ for(int talo=1; talo<=histbars; talo++)
{ if (valo<(histrange*talo/histbars-histrange/2))
{ tallie[talo-1]++; talo=histbars+1; }
}
}
}
for(int x=0; x<histbars; x++)
{ if(tallie[x]>maxtallie){ maxtallie=tallie[x]; } }
debout("\n",0);
int histhigh=16;
for( int g=histhigh; g>0; g--)
{ debout(""+(maxtallie*g/histhigh)+": ",9);
for(int i=0; i<histbars; i++)
{ if(tallie[i]<(maxtallie*g/histhigh))
{ debout(" ",3);}
else
{ debout("**",3);}
}//i
debout("\n",0);
}//g
for(int x=0; x<histbars-3; x++)
{ System.out.print("----"); }
System.out.print("\n Sums: ");
for(int x=0; x<histbars; x+=2)
{ deboutm(""+tallie[x], 6); }
System.out.print("\n Devs: <");
for(int x=-histbars/2; x<(histbars+1)/2; x+=2) //printing hist headers
{ deboutm(""+Math.abs((int)( (x+0.5)*histrange)/histbars), 6); }
System.out.print(">");
System.out.println("\n\nDistribution chart, range="+histrange+"n (256n=1 sample)\n");
}
private void debout(String deb, int size) //writing to size, for debug output
{ size=size-deb.length();
for(int o=0; o<size; o++) { System.out.print(" ");}
System.out.print(deb);
}//end debout method
private void deboutm(String deb, int size) //writing to size, for debug output
{ size=size-deb.length();
int pesize=size/2;
int posize=size-pesize;
for(int o=0; o<pesize; o++) { System.out.print(" ");}
System.out.print(deb);
for(int o=0; o<posize; o++) { System.out.print(" ");}
}//end debout method
}//end nodecouple
class getNodesWave {
/**
* Wavfile gurgitor
*
* Casual version - it only understands simple wav file formats
*
* This utility is written in private as part of a study
* portfolio in developement.
*
* neutron.soupmix@ntlworld.com */
/* Public discernables are channels, sampling rate, timeframes, (samples/channels).... */
private int hdChnkSz,fmt,dmt,wavFrmtTag; //metaMetas
public int channels, rawPcmByts, totlFrames, bitsPerSample, Samprate; //stream details
byte[] loaded;
byte[] bpass= new byte[0]; //possibly bugged tweak! -appears to work
private int samsGet, framPerGet, FrmsBfd, rdIn, bytsRd, bytLft;
private int[] samsGvn;
private short[] retSam;
private short[][] samRng;
private byte samStep;
private int ndfi; //node find index
private int smx0,smx1,smx2;
public FileInputStream wavIn;
public File wavFile;
public static void main(String[] args)/* main */
{ System.out.println("getNodesWave has no main");
System.exit(1); } //graceless exit better than hang
public getNodesWave(String wvName, int samsPerGet){ //bytbffa is sampls per modwork area
System.out.println(" Opening "+wvName);
try
{ wavFile = new File(wvName);
FileInputStream wavIn = new FileInputStream(wavFile);
byte[] hdrz = new byte[44];
int hdrzlen = wavIn.read(hdrz);
byte hdrzi = 12; //wavIn.skip(12);
fmt // header should be fmt, fmt 4 bytes
= ((hdrz[hdrzi++]&0x00ff)<<24) | ((hdrz[hdrzi++]&0x00ff)<<16)
| ((hdrz[hdrzi++]&0x00ff)<<8) | ( (hdrz[hdrzi++]&0x00ff));
if (fmt!=0x666D7420)
{ System.out.println(" fmt sig not encountered - Failure Likely...");
System.out.println(" fmtsig val="+fmt+"\n");}
hdChnkSz //size in bytes of a header chunk
= ((hdrz[hdrzi++]&0x00ff) | ((hdrz[hdrzi++]&0x00ff)<<8)
| ((hdrz[hdrzi++]&0x00ff)<<16) | ((hdrz[hdrzi++]&0x00ff)<<24));
if (hdChnkSz!=16)
{ System.out.println(" Complex wav header - Failure Possible..."); }
wavFrmtTag = (hdrz[hdrzi++]&0x00ff)|((hdrz[hdrzi++]&0x00ff)<<8 );
channels = (hdrz[hdrzi++]&0x00ff)|((hdrz[hdrzi++]&0x00ff)<<8 ); //channels
Samprate
= ((hdrz[hdrzi++]&0x00ff) | ((hdrz[hdrzi++]&0x00ff)<<8) //samprate
| ((hdrz[hdrzi++]&0x00ff)<<16) | ((hdrz[hdrzi++]&0x00ff)<<24));
System.out.println(" SampleRate:"+Samprate);
hdrzi+=6; //skip byterate and blockalign
bitsPerSample = (hdrz[hdrzi++]&0x00ff)|((hdrz[hdrzi++]&0x00ff)<<8 );
//data chunk
dmt // header should be dmt, 4 bytes
= ((hdrz[hdrzi++]&0x00ff)<<24) | ((hdrz[hdrzi++]&0x00ff)<<16)
| ((hdrz[hdrzi++]&0x00ff)<<8) | ( (hdrz[hdrzi++]&0x00ff));
if (dmt!=0x64617461)
{ System.out.println(" No data signature found in wav - Abort! Abort! ");
System.out.println(" dmtsig val="+dmt+"\n");}
rawPcmByts //size in bytes of pcm data
= ((hdrz[hdrzi++]&0x00ff) | ((hdrz[hdrzi++]&0x00ff)<<8)
| ((hdrz[hdrzi++]&0x00ff)<<16) | ((hdrz[hdrzi++]&0x00ff)<<24));
//hdrzreading finished
//hopefuly wav chunk headers overwith
totlFrames=rawPcmByts/(2*channels);
if (channels==0){ System.out.println(" No Channels Arrrgh! Abort! Abort!"); channels=1; }
if (channels==1){ System.out.println(" Mono input"); }
if (channels==2){ System.out.println(" Stereo input"); }
if (channels>=3){ System.out.println(" "+channels+" channels (weird, trying as mono)" ); channels=1; }
long ThScnds=(rawPcmByts)/(2*Samprate*channels/1000);
System.out.println(" Samples "+(rawPcmByts)/(2*channels));
System.out.println(" Trackime at "+Samprate+"Hz :"+ThScnds/1000+"."+(ThScnds%1000)/100+""+(ThScnds%100)/10+""+(ThScnds%10)+"\n");
wavIn.close();
samStep=0;
retSam=new short[samsPerGet];
samRng=new short[channels][4096];
samsGvn=new int[channels];
samsGet=samsPerGet;
FrmsBfd=0;
bytsRd=0;
smx0=0;smx1=0;smx2=0;
rdIn=6144*channels; //reading in 6k a time per channel,
//6144 samples fitting into 4096wide ringbuffs
//1024 sample was safe get for two channel access
}//end io try
catch(FileNotFoundException fnfe)
{ System.out.println("File Not Found, " + wvName);
return; }// end catch FileNotFoundException
catch(IOException ioe)
{ System.out.println("IO Error: " + ioe);
return; }// end catch IOException*/
finally
{ } // end LoadArray
return;
}//end constructor (open wav, get header details)
private void debout(String deb, int size) //writing to size, for debug output
{ size=size-deb.length();
for(int o=0; o<size; o++) { System.out.print(" ");}
System.out.print(deb);
}//end debout method
private void debout(String deb) //writing to size, for debug output
{ System.out.println(deb);
}//end debout method
public void setStep(byte set)
{ samStep = set; return; }
public int[] getnodes( int chnnel )
{ if( (samsGvn[chnnel]+samsGet)>=(totlFrames) )
{ samsGet=totlFrames-samsGvn[chnnel]; //check if last get
if(samsGet==0){ System.out.println("wavin buffer empty"); }
retSam = new short[samsGet]; }
if(FrmsBfd<(samsGvn[chnnel]+samsGet)) { movebf(); } //check if ringbuff needs moved
for(int samsOut=0; samsOut<samsGet; samsOut++)
{ retSam[samsOut]=samRng[chnnel][(samsGvn[chnnel]++)%4096]; }
//** review channel returned.
//retSam is series of pcm levels
int[] nodes= new int[2008]; //fairly safe sized node list
int nodi=1; //count of node found
int pregrad,pstgrad; //approximate derivatives
for( int ndfi=0; ndfi<samsGet; ndfi++) //ndfi = time index( samples loop )
{ smx2=smx1; smx1=smx0; smx0=retSam[ndfi];
pregrad=smx1-smx2;
pstgrad=smx0-smx1;
if((pregrad*pstgrad<-1)&&(Math.abs(pregrad-pstgrad)>100))
{ nodes[nodi++]=(ndfi<<8)+( (512*pstgrad+1) / ( ((pstgrad-pregrad)*2)+1) ); }
//record simple linear solution of 1st derivative=0
//expression: (( (512*pstgrad+1) / (((pstgrad-pregrad)*2)+1) )) produces ~ 0-255
//node units are samplesize/256 (1/256th of sample interval)
//What was producing the central spike in
//an approxomated but balanced (equally distributed error) measure of a peaks intensity/accuteness,
//is a simple discernment of the second derivative (change of change) =
//the method used to select peaks strength, peaks in the middle had to be less powerful to
//be selected than peaks at the sides, (of the considered sample length)
//this then allowed nodes to be matched more often coincidentaly close, tahn not)
//the new expression used has no such bias
}//end for(ndfi)
nodes[0]=nodi-1; //first in nodelist stores length of nodelist
return nodes; //return list of nodes to analysis director
}// end getsams method
public void movebf() //fetch next load of samples
{
try
{ FileInputStream wavIn = new FileInputStream(wavFile);
wavIn.skip(44+bytsRd);
if((bytsRd+rdIn)>rawPcmByts){ rdIn=rawPcmByts-bytsRd; }
if(bpass.length!=rdIn){ bpass= new byte[rdIn]; }
bytsRd+= wavIn.read(bpass);
loaded=bpass;
wavIn.close();
}
catch(IOException ioe){ System.out.println("IO Error: " + ioe); return; }// end catch IOException
finally{ } // end LoadArray
if(channels==1)
{ for( int loadi=0; loadi<rdIn ; FrmsBfd++)
{ samRng[0][FrmsBfd%4096] = (short)( (loaded[loadi++]&0x00ff)|((loaded[loadi++]<<8)&0xff00) );
loadi+=samStep*2; } }
else
{ for( int loadi=0; loadi<rdIn ; )
{ samRng[0][FrmsBfd%4096] = (short)( (loaded[loadi++]&0x00ff)|((loaded[loadi++]<<8)&0xff00) );
samRng[1][(FrmsBfd++)%4096] = (short)( (loaded[loadi++]&0x00ff)|((loaded[loadi++]<<8)&0xff00) );
loadi+=samStep*4; } }
return;
}//end eatWav
}//end getNodesWave
Here is a current output:
---------- Run java ----------
Reading innofun22176.wav
SampleRate:176400
Stereo input
Samples 1850146
Trackime at 176400Hz :10.497
And Reading nofun176400.wav
SampleRate:176400
Stereo input
Samples 1850134
Trackime at 176400Hz :10.497
Only reading first 1.160 seconds (of 1 channel) (Change chnkread for more)
Locating Nodes...
Total nodes in: nofun22176.wav:1132
Total nodes in: nofun176400.wav:1444
Missednodes=127, discreps=1005, Searchednodes=1132
253 ***
237 ***
221 ***
205 ***
189 ***
173 ***
158 ***
142 ***
126 ***
110 *** ***
94 *** *** *** ***
79 *** *** *** *** ***
63 *** *** *** *** *** *** ***
47 *** *** *** *** *** *** *** ***
31 *** *** *** *** *** *** *** *** ***
15 *** *** *** *** *** *** *** *** *** *** *** *** ***
Sums: 3 28 76 102 103 67 50 22 22 5 9 36 125 253 83 21
Devs: 1920 1664 1408 1152 896 640 384 128 128 384 640 896 1152 1408 1664 1920
Distribution chart, range=4096n (256n=1 sample)
Output completed (0 sec consumed).
-This is a curious output that cant be trusted at this stage of the programs developement.
It compares a clip of cd audio upsampled x4, with one downsampled x2 and then upsampled x8
by ssrc_hp.exe
A 176400 (44100*4) Hz sample length in the chart is 256,
a 44100 Hz sample length in the chart is 1024
( these relate to the distribution bands )
more investigation/developement may follow..
Its obviously troublesome to start interprating unsecurely tested/debuged programs, but if some recognise the effort ive put into it (the code ended up taking some valuable hours to get to this stage).
- Maybe they could give me the benefit of their prediction of the best distribution possible of detectable conditions in a waveforms pairing between different samplerates/bandwidths.
regards'
cg
edit: inserted smaller chart