///////////////////////////////////////////////////// ///////////////////////////////////////////////////// // // GetSpectrum // ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// #include "ckall.h" #ifdef PSP #define __max(a,b) (((a) > (b)) ? (a) : (b)) #define __min(a,b) (((a) < (b)) ? (a) : (b)) #endif short FFT(short int dir,long m,float *x,float *y) { long n,i,i1,j,k,i2,l,l1,l2; float c1,c2,tx,ty,t1,t2,u1,u2,z; /* Calculate the number of points */ n = 1; for (i=0;i> 1; j = 0; for (i=0;i>= 1; } j += k; } /* Compute the FFT */ c1 = -1.0; c2 = 0.0; l2 = 1; for (l=0;lSetDescription("Performs sound spectrum analysis."); /* rem: In: triggers the process
Out: is activated when the process is completed.

Start Frequency: Start of the requested frequency range.
End Frequency: End of the requested frequency range.

Value: . Average sound volume for frequency range

Band Count: The number of bands used to perform spectrum analysis.

Use this behavior building block to perform frequency analysis on a digital sound.
*/ od->SetCategory("Sounds/Processing"); od->SetType(CKDLL_BEHAVIORPROTOTYPE); od->SetGuid(CKGUID(0x47082a75,0x112b7c1b)); od->SetAuthorGuid(VIRTOOLS_GUID); od->SetAuthorName("Virtools"); od->SetVersion(0x00010000); od->SetCreationFunction(CreateGetSpectrumBehaviorProto); od->SetCompatibleClassId(CKCID_WAVESOUND); od->NeedManager(SOUND_MANAGER_GUID); return od; } #define IN_START_FREQUENCY 0 #define IN_END_FREQUENCY 1 #define OUT_VALUE 0 #define SETTINGS_BAND_COUNT 0 #define LOCAL_TICK 1 #define LOCAL_BANDS 2 #define BITS 10 CKERROR CreateGetSpectrumBehaviorProto(CKBehaviorPrototype **pproto) { CKBehaviorPrototype *proto = CreateCKBehaviorPrototype("Get Sound Spectrum"); if(!proto) return CKERR_OUTOFMEMORY; proto->DeclareInput("In"); proto->DeclareOutput("Out"); proto->DeclareInParameter("Start Frequency",CKPGUID_INT,"0"); proto->DeclareInParameter("End Frequency",CKPGUID_INT,"44100"); proto->DeclareOutParameter("Value",CKPGUID_PERCENTAGE,"0%"); proto->DeclareSetting("Band Count",CKPGUID_INT,"128"); proto->DeclareLocalParameter("Tick",CKPGUID_INT,"0"); proto->DeclareLocalParameter("Band",CKPGUID_VOIDBUF,NULL); proto->SetBehaviorFlags(CKBEHAVIOR_TARGETABLE); proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL); proto->SetFunction(GetSpectrum); *pproto = proto; return CK_OK; } int GetSpectrum(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; beh->ActivateInput(0,FALSE); beh->ActivateOutput(0); CKWaveSound* wave=(CKWaveSound*)beh->GetTarget(); if( !wave) return CKBR_OK; int nb_bands = 128; beh->GetLocalParameterValue(SETTINGS_BAND_COUNT,&nb_bands); nb_bands = 1 << BITS; int startfreq = 0; int endfreq = 44100; beh->GetInputParameterValue(IN_START_FREQUENCY,&startfreq); beh->GetInputParameterValue(IN_END_FREQUENCY,&endfreq); if(startfreq >= endfreq) return CKBR_OK; CKWaveFormat Format; wave->GetSoundFormat(Format); CKTimeManager *tm = behcontext.Context->GetTimeManager(); unsigned int lasttick = 0; beh->GetLocalParameterValue(LOCAL_TICK,&lasttick); unsigned int currenttick = tm->GetMainTickCount(); if(currenttick!= lasttick) { beh->SetLocalParameterValue(LOCAL_TICK,¤ttick); int pos = wave->GetPlayPosition(); int i,res = 0; void *buf1 = NULL,*buf2 =NULL; CKDWORD sz1=0,sz2=0; int size = nb_bands*Format.nChannels*(Format.wBitsPerSample/8); wave->Lock(pos,size,&buf1,&sz1,&buf2,&sz2,(CK_WAVESOUND_LOCKMODE)0); int bytepersample = Format.wBitsPerSample / 8; switch(Format.nChannels){ case 1: // Mono { VxScratch pool(((sz1+sz2)/bytepersample)*sizeof(float)); float *mem = (float *) pool.Mem(); float *it = mem; VxScratch bandpool(nb_bands); int isz1 = sz1; int isz2 = sz2; switch(Format.wBitsPerSample){ case 8: // 8 bits Mono { CKBYTE *ibuf1 = (CKBYTE*) buf1; CKBYTE *ibuf2 = (CKBYTE*) buf2; while(isz1>0){ *it = (float)(((int)(*ibuf1) + 0x7f)); ibuf1++; isz1--; it++; } while(isz2>0){ *it = ((float)((int)(*ibuf2) + 0x7f)); ibuf2++; isz2--; it++; } } break; case 16: // 16 bits Mono { signed short *ibuf1 = (signed short*) buf1; signed short *ibuf2 = (signed short*) buf2; while(isz1>0){ *it = ((float)(*ibuf1))/255.0f; ibuf1++; isz1-=2; it++; } while(isz2>0){ *it = ((float)(*ibuf2))/255.0f; ibuf2++; isz2-=2; it++; } } break; } VxScratch im(nb_bands*sizeof(float)); memset(im.Mem(),0,nb_bands*sizeof(float)); FFT(1,BITS,mem,(float*) im.Mem()); VxScratch tmpBands(nb_bands ); unsigned char *bands = (unsigned char*) tmpBands.Mem(); for(i=0;iSetLocalParameterValue(LOCAL_BANDS,bands,nb_bands); } break; case 2: { VxScratch pool(((sz1+sz2)/bytepersample)*sizeof(float)); float *mem = (float *) pool.Mem(); float *it = mem; VxScratch bandpool(nb_bands); // Offset int offset = (((sz1+sz2)/bytepersample))/2; int isz1 = sz1/bytepersample; int isz2 = sz2/bytepersample; switch(Format.wBitsPerSample){ case 8: { CKBYTE *ibuf1 = (CKBYTE*) buf1; CKBYTE *ibuf2 = (CKBYTE*) buf2; while(isz1>0){ *it = (float)(((int)(*ibuf1) + 0x7f)); ibuf1++; *(it+offset) = (float)(((int)(*ibuf1) + 0x7f)); ibuf1++; isz1-=2; it++; } while(isz2>0){ *it = (float)(((int)(*ibuf2)+ 0x7f)); ibuf2++; *(it+offset) = (float)(((int)(*ibuf2)+ 0x7f)); ibuf2++; isz2-=2; it++; } } break; case 16: { signed short *ibuf1 = (signed short*) buf1; signed short *ibuf2 = (signed short*) buf2; while(isz1>0){ *it = (float)(*ibuf1)/255.0f; ibuf1++; *(it+offset) = (float)(*ibuf1)/255.0f; ibuf1++; isz1-=2; it++; } while(isz2>0){ *(it) = (float)(*ibuf2)/255.0f; ibuf2++; *(it+offset) = (float)(*ibuf2)/255.0f; ibuf2++; isz2-=2; it++; } } break; } VxScratch im(nb_bands*sizeof(float)); memset(im.Mem(),0,nb_bands*sizeof(float)); FFT(1,BITS,mem,(float*) im.Mem()); memset(im.Mem(),0,nb_bands*sizeof(float)); FFT(1,BITS,mem+offset,(float*) im.Mem()); VxScratch tmpBands(nb_bands ); unsigned char *bands = (unsigned char*) tmpBands.Mem(); for(i=0;iSetLocalParameterValue(LOCAL_BANDS,bands,nb_bands); } break; } wave->Unlock(buf1,sz1,buf2,sz2); } float inv = 1.0f/255.0f; float sum = 0; unsigned char * bands = (unsigned char * ) beh->GetLocalParameterReadDataPtr(LOCAL_BANDS); nb_bands >>= 1; int startband = 1+(int) ((float)nb_bands*(float)startfreq / (0.5f*(float)Format.nSamplesPerSec)); int endband = 1+(int) ((float)nb_bands*(float)endfreq / (0.5f*(float)Format.nSamplesPerSec)); if(startband == endband) endband = startband+1; int end = __min(endband,nb_bands); for(int i=startband;iSetOutputParameterValue(OUT_VALUE,&sum); return CKBR_OK; }