| /** |
| * projectM -- Milkdrop-esque visualisation SDK |
| * Copyright (C) 2003-2004 projectM Team |
| * |
| * 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; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * See 'LICENSE.txt' included within this release |
| * |
| */ |
| /** |
| * $Id: PCM.c,v 1.3 2006/03/13 20:35:26 psperl Exp $ |
| * |
| * Takes sound data from wherever and hands it back out. |
| * Returns PCM Data or spectrum data, or the derivative of the PCM data |
| */ |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| #include "Common.hpp" |
| #include "wipemalloc.h" |
| #include "fftsg.h" |
| #include "PCM.hpp" |
| #include <cassert> |
| #include <iostream> |
| |
| |
| int PCM::maxsamples = 2048; |
| |
| |
| //initPCM (int samples) |
| // |
| //Initializes the PCM buffer to |
| // number of samples specified. |
| |
| PCM::PCM () |
| { |
| initPCM (2048); |
| |
| #ifdef DEBUG |
| std::cerr << "[PCM] MAX SAMPLES:" << maxsamples << std::endl; |
| #endif |
| } |
| |
| void |
| PCM::initPCM (int samples) |
| { |
| int i; |
| |
| waveSmoothing = 0; |
| |
| //Allocate memory for PCM data buffer |
| assert (samples == 2048); |
| PCMd = (float **) wipemalloc (2 * sizeof (float *)); |
| PCMd[0] = (float *) wipemalloc (samples * sizeof (float)); |
| PCMd[1] = (float *) wipemalloc (samples * sizeof (float)); |
| |
| //maxsamples=samples; |
| newsamples = 0; |
| numsamples = maxsamples; |
| |
| //Initialize buffers to 0 |
| for (i = 0; i < samples; i++) { |
| PCMd[0][i] = |
| PCMd[1][i] = 0; |
| } |
| |
| start = 0; |
| |
| //Allocate FFT workspace |
| w = (double *) wipemalloc (maxsamples * sizeof (double)); |
| ip = (int *) wipemalloc (maxsamples * sizeof (int)); |
| ip[0] = 0; |
| |
| |
| /** PCM data */ |
| // this->maxsamples = 2048; |
| // this->numsamples = 0; |
| // this->pcmdataL = NULL; |
| // this->pcmdataR = NULL; |
| |
| /** Allocate PCM data structures */ |
| pcmdataL = (float *) wipemalloc (this->maxsamples * sizeof (float)); |
| pcmdataR = (float *) wipemalloc (this->maxsamples * sizeof (float)); |
| |
| } |
| |
| PCM::~PCM () |
| { |
| free (pcmdataL); |
| free (pcmdataR); |
| free (w); |
| free (ip); |
| |
| free (PCMd[0]); |
| free (PCMd[1]); |
| free (PCMd); |
| } |
| |
| |
| void |
| PCM::addPCMfloat (const float *PCMdata, int samples) |
| { |
| int i, j; |
| |
| for (i = 0; i < samples; i++) |
| { |
| j = i + start; |
| |
| if (PCMdata[i] != 0 ) { |
| PCMd[0][j % maxsamples] = PCMdata[i]; |
| PCMd[1][j % maxsamples] = PCMdata[i]; |
| } else { |
| PCMd[0][j % maxsamples] = 0; |
| PCMd[1][j % maxsamples] = 0; |
| } |
| } |
| |
| start += samples; |
| start = start % maxsamples; |
| |
| newsamples += samples; |
| if (newsamples > maxsamples) |
| newsamples = maxsamples; |
| |
| numsamples = getPCMnew (pcmdataR, 1, 0, waveSmoothing, 0, 0); |
| getPCMnew (pcmdataL, 0, 0, waveSmoothing, 0, 1); |
| getPCM (vdataL, 512, 0, 1, 0, 0); |
| getPCM (vdataR, 512, 1, 1, 0, 0); |
| } |
| |
| void |
| PCM::addPCM16Data (const short* pcm_data, short samples) |
| { |
| int i, j; |
| |
| for (i = 0; i < samples; ++i) { |
| j = i + start; |
| PCMd[0][j % maxsamples] = (pcm_data[i * 2 + 0] / 16384.0); |
| PCMd[1][j % maxsamples] = (pcm_data[i * 2 + 1] / 16384.0); |
| } |
| |
| start = (start + samples) % maxsamples; |
| |
| newsamples += samples; |
| if (newsamples > maxsamples) |
| newsamples = maxsamples; |
| |
| numsamples = getPCMnew (pcmdataR, 1, 0, waveSmoothing, 0, 0); |
| getPCMnew (pcmdataL, 0, 0, waveSmoothing, 0, 1); |
| getPCM (vdataL, 512, 0, 1, 0, 0); |
| getPCM (vdataR, 512, 1, 1, 0, 0); |
| } |
| |
| |
| void |
| PCM::addPCM16 (short PCMdata[2][512]) |
| { |
| int i, j; |
| int samples=512; |
| |
| for (i = 0; i < samples; i++) { |
| j = i + start; |
| if (PCMdata[0][i] != 0 && PCMdata[1][i] != 0) { |
| PCMd[0][j % maxsamples] = (PCMdata[0][i] / 16384.0); |
| PCMd[1][j % maxsamples] = (PCMdata[1][i] / 16384.0); |
| } else { |
| PCMd[0][j % maxsamples] = (float) 0; |
| PCMd[1][j % maxsamples] = (float) 0; |
| } |
| } |
| |
| // printf ("Added %d samples %d %d %f\n", samples, start,(start+samples)%maxsamples, PCM[0][start+10]); |
| |
| start += samples; |
| start = start % maxsamples; |
| |
| newsamples += samples; |
| if (newsamples > maxsamples) |
| newsamples = maxsamples; |
| |
| numsamples = getPCMnew (pcmdataR, 1, 0, waveSmoothing, 0, 0); |
| getPCMnew (pcmdataL, 0, 0, waveSmoothing, 0, 1); |
| getPCM (vdataL, 512, 0, 1, 0, 0); |
| getPCM (vdataR, 512, 1, 1, 0, 0); |
| } |
| |
| |
| void |
| PCM::addPCM8 (unsigned char PCMdata[2][1024]) |
| { |
| int i, j; |
| int samples = 1024; |
| |
| for (i = 0; i < samples; i++) { |
| j = i + start; |
| if (PCMdata[0][i] != 0 && PCMdata[1][i] != 0) { |
| PCMd[0][j % maxsamples] = ((float) (PCMdata[0][i] - 128.0) / 64); |
| PCMd[1][j % maxsamples] = ((float) (PCMdata[1][i] - 128.0) / 64); |
| } else { |
| PCMd[0][j % maxsamples] = 0; |
| PCMd[1][j % maxsamples] = 0; |
| } |
| } |
| |
| |
| // printf ("Added %d samples %d %d %f\n", samples, start,(start+samples)%maxsamples, PCM[0][start+10]); |
| |
| start += samples; |
| start = start % maxsamples; |
| |
| newsamples += samples; |
| if (newsamples > maxsamples) |
| newsamples = maxsamples; |
| |
| numsamples = getPCMnew (pcmdataR, 1, 0, waveSmoothing, 0, 0); |
| getPCMnew (pcmdataL, 0, 0, waveSmoothing, 0, 1); |
| getPCM (vdataL, 512, 0, 1, 0, 0); |
| getPCM (vdataR, 512, 1, 1, 0, 0); |
| } |
| |
| void |
| PCM::addPCM8_512 (const unsigned char PCMdata[2][512]) |
| { |
| int i, j; |
| int samples = 512; |
| |
| for (i = 0; i < samples; i++) { |
| j = i + start; |
| if (PCMdata[0][i] != 0 && PCMdata[1][i] != 0) { |
| PCMd[0][j % maxsamples] = ((float) (PCMdata[0][i] - 128.0) / 64); |
| PCMd[1][j % maxsamples] = ((float) (PCMdata[1][i] - 128.0) / 64); |
| } else { |
| PCMd[0][j % maxsamples] = 0; |
| PCMd[1][j % maxsamples] = 0; |
| } |
| } |
| |
| |
| // printf ("Added %d samples %d %d %f\n", samples, start,(start+samples)%maxsamples, PCM[0][start+10]); |
| |
| start += samples; |
| start = start % maxsamples; |
| |
| newsamples += samples; |
| if (newsamples > maxsamples) |
| newsamples = maxsamples; |
| |
| numsamples = getPCMnew (pcmdataR, 1, 0, waveSmoothing, 0, 0); |
| getPCMnew (pcmdataL, 0, 0, waveSmoothing, 0, 1); |
| getPCM (vdataL, 512, 0, 1, 0, 0); |
| getPCM (vdataR, 512, 1, 1, 0, 0); |
| } |
| |
| |
| //puts sound data requested at provided pointer |
| // |
| //samples is number of PCM samples to return |
| //freq = 0 gives PCM data |
| //freq = 1 gives FFT data |
| //smoothing is the smoothing coefficient |
| |
| //returned values are normalized from -1 to 1 |
| |
| void |
| PCM::getPCM ( |
| float *PCMdata, |
| int samples, |
| int channel, |
| int freq, |
| float smoothing, |
| int derive |
| ) |
| { |
| int i, index; |
| |
| index = start - 1; |
| |
| if (index < 0) |
| index = maxsamples + index; |
| |
| PCMdata[0] = PCMd[channel][index]; |
| |
| for (i = 1; i < samples; i++) { |
| index = start - 1 - i; |
| if (index < 0) |
| index = maxsamples + index; |
| |
| PCMdata[i] = (1 - smoothing) * PCMd[channel][index] |
| + smoothing * PCMdata[i - 1]; |
| } |
| |
| //return derivative of PCM data |
| if (derive) { |
| for (i = 0; i < samples - 1; i++) { |
| PCMdata[i] = PCMdata[i] - PCMdata[i + 1]; |
| } |
| PCMdata[samples-1] = 0; |
| } |
| |
| //return frequency data instead of PCM (perform FFT) |
| |
| if (freq) { |
| double temppcm[1024]; |
| |
| for (int i = 0; i < samples; i++) |
| {temppcm[i] = (double) PCMdata[i];} |
| |
| rdft (samples, 1, temppcm, ip, w); |
| for (int j = 0; j < samples; j++) |
| {PCMdata[j] = (float) temppcm[j];} |
| } |
| } |
| |
| //getPCMnew |
| // |
| //Like getPCM except it returns all new samples in the buffer |
| //the actual return value is the number of samples, up to maxsamples. |
| //the passed pointer, PCMData, must bee able to hold up to maxsamples |
| // |
| int |
| PCM::getPCMnew ( |
| float *PCMdata, |
| int channel, |
| int freq, |
| float smoothing, |
| int derive, |
| int reset |
| ) |
| { |
| int i, index; |
| |
| index = start - 1; |
| |
| if (index < 0) |
| index = maxsamples + index; |
| |
| PCMdata[0] = PCMd[channel][index]; |
| for (i = 1; i < newsamples; i++) { |
| index = start - 1 - i; |
| if (index < 0) |
| index = maxsamples + index; |
| |
| PCMdata[i] = (1 - smoothing) * PCMd[channel][index] |
| + smoothing * PCMdata[i-1]; |
| } |
| |
| //return derivative of PCM data |
| if (derive) { |
| for (i = 0; i < newsamples - 1; i++) { |
| PCMdata[i] = PCMdata[i] - PCMdata[i + 1]; |
| } |
| PCMdata[newsamples-1] = 0; |
| } |
| |
| //return frequency data instead of PCM (perform FFT) |
| // if (freq) rdft (samples, 1, PCMdata, ip, w); |
| i = newsamples; |
| if (reset) newsamples = 0; |
| |
| return i; |
| } |
| |
| //Free stuff |
| void |
| PCM::freePCM () |
| { |
| free (PCMd[0]); |
| free (PCMd[1]); |
| free (PCMd); |
| free (ip); |
| free (w); |
| |
| PCMd = NULL; |
| ip = NULL; |
| w = NULL; |
| } |