mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-29 14:48:39 +02:00
No naked malloc (calloc, strup, ...) and free!
This commit is contained in:
commit
a399d4e23a
@ -521,7 +521,7 @@ class GnomeShutdown
|
|||||||
public:
|
public:
|
||||||
GnomeShutdown()
|
GnomeShutdown()
|
||||||
{
|
{
|
||||||
mArgv[0] = strdup("Audacity");
|
mArgv[0].reset(strdup("Audacity"));
|
||||||
|
|
||||||
mGnomeui = dlopen("libgnomeui-2.so.0", RTLD_NOW);
|
mGnomeui = dlopen("libgnomeui-2.so.0", RTLD_NOW);
|
||||||
if (!mGnomeui) {
|
if (!mGnomeui) {
|
||||||
@ -550,11 +550,11 @@ class GnomeShutdown
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gnome_program_init(mArgv[0],
|
gnome_program_init(mArgv[0].get(),
|
||||||
"1.0",
|
"1.0",
|
||||||
libgnomeui_module_info_get(),
|
libgnomeui_module_info_get(),
|
||||||
1,
|
1,
|
||||||
mArgv,
|
reinterpret_cast<char**>(mArgv),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
mClient = gnome_master_client();
|
mClient = gnome_master_client();
|
||||||
@ -568,13 +568,11 @@ class GnomeShutdown
|
|||||||
virtual ~GnomeShutdown()
|
virtual ~GnomeShutdown()
|
||||||
{
|
{
|
||||||
// Do not dlclose() the libraries here lest you want segfaults...
|
// Do not dlclose() the libraries here lest you want segfaults...
|
||||||
|
|
||||||
free(mArgv[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
char *mArgv[1];
|
MallocString<> mArgv[1];
|
||||||
void *mGnomeui;
|
void *mGnomeui;
|
||||||
void *mGnome;
|
void *mGnome;
|
||||||
GnomeClient *mClient;
|
GnomeClient *mClient;
|
||||||
|
21
src/FFT.cpp
21
src/FFT.cpp
@ -113,8 +113,6 @@ void InitFFT()
|
|||||||
void DeinitFFT()
|
void DeinitFFT()
|
||||||
{
|
{
|
||||||
gFFTBitTable.reset();
|
gFFTBitTable.reset();
|
||||||
// Deallocate any unused RealFFTf tables
|
|
||||||
CleanupFFT();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t FastReverseBits(size_t i, size_t NumBits)
|
static inline size_t FastReverseBits(size_t i, size_t NumBits)
|
||||||
@ -230,14 +228,14 @@ void FFT(size_t NumSamples,
|
|||||||
|
|
||||||
void RealFFT(size_t NumSamples, const float *RealIn, float *RealOut, float *ImagOut)
|
void RealFFT(size_t NumSamples, const float *RealIn, float *RealOut, float *ImagOut)
|
||||||
{
|
{
|
||||||
HFFT hFFT = GetFFT(NumSamples);
|
auto hFFT = GetFFT(NumSamples);
|
||||||
Floats pFFT{ NumSamples };
|
Floats pFFT{ NumSamples };
|
||||||
// Copy the data into the processing buffer
|
// Copy the data into the processing buffer
|
||||||
for(size_t i = 0; i < NumSamples; i++)
|
for(size_t i = 0; i < NumSamples; i++)
|
||||||
pFFT[i] = RealIn[i];
|
pFFT[i] = RealIn[i];
|
||||||
|
|
||||||
// Perform the FFT
|
// Perform the FFT
|
||||||
RealFFTf(pFFT.get(), hFFT);
|
RealFFTf(pFFT.get(), hFFT.get());
|
||||||
|
|
||||||
// Copy the data into the real and imaginary outputs
|
// Copy the data into the real and imaginary outputs
|
||||||
for (size_t i = 1; i<(NumSamples / 2); i++) {
|
for (size_t i = 1; i<(NumSamples / 2); i++) {
|
||||||
@ -253,8 +251,6 @@ void RealFFT(size_t NumSamples, const float *RealIn, float *RealOut, float *Imag
|
|||||||
RealOut[i] = RealOut[NumSamples-i];
|
RealOut[i] = RealOut[NumSamples-i];
|
||||||
ImagOut[i] = -ImagOut[NumSamples-i];
|
ImagOut[i] = -ImagOut[NumSamples-i];
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseFFT(hFFT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -271,7 +267,7 @@ void RealFFT(size_t NumSamples, const float *RealIn, float *RealOut, float *Imag
|
|||||||
void InverseRealFFT(size_t NumSamples, const float *RealIn, const float *ImagIn,
|
void InverseRealFFT(size_t NumSamples, const float *RealIn, const float *ImagIn,
|
||||||
float *RealOut)
|
float *RealOut)
|
||||||
{
|
{
|
||||||
HFFT hFFT = GetFFT(NumSamples);
|
auto hFFT = GetFFT(NumSamples);
|
||||||
Floats pFFT{ NumSamples };
|
Floats pFFT{ NumSamples };
|
||||||
// Copy the data into the processing buffer
|
// Copy the data into the processing buffer
|
||||||
for (size_t i = 0; i < (NumSamples / 2); i++)
|
for (size_t i = 0; i < (NumSamples / 2); i++)
|
||||||
@ -287,12 +283,10 @@ void InverseRealFFT(size_t NumSamples, const float *RealIn, const float *ImagIn,
|
|||||||
pFFT[1] = RealIn[NumSamples / 2];
|
pFFT[1] = RealIn[NumSamples / 2];
|
||||||
|
|
||||||
// Perform the FFT
|
// Perform the FFT
|
||||||
InverseRealFFTf(pFFT.get(), hFFT);
|
InverseRealFFTf(pFFT.get(), hFFT.get());
|
||||||
|
|
||||||
// Copy the data to the (purely real) output buffer
|
// Copy the data to the (purely real) output buffer
|
||||||
ReorderToTime(hFFT, pFFT.get(), RealOut);
|
ReorderToTime(hFFT.get(), pFFT.get(), RealOut);
|
||||||
|
|
||||||
ReleaseFFT(hFFT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -308,14 +302,14 @@ void InverseRealFFT(size_t NumSamples, const float *RealIn, const float *ImagIn,
|
|||||||
|
|
||||||
void PowerSpectrum(size_t NumSamples, const float *In, float *Out)
|
void PowerSpectrum(size_t NumSamples, const float *In, float *Out)
|
||||||
{
|
{
|
||||||
HFFT hFFT = GetFFT(NumSamples);
|
auto hFFT = GetFFT(NumSamples);
|
||||||
Floats pFFT{ NumSamples };
|
Floats pFFT{ NumSamples };
|
||||||
// Copy the data into the processing buffer
|
// Copy the data into the processing buffer
|
||||||
for (size_t i = 0; i<NumSamples; i++)
|
for (size_t i = 0; i<NumSamples; i++)
|
||||||
pFFT[i] = In[i];
|
pFFT[i] = In[i];
|
||||||
|
|
||||||
// Perform the FFT
|
// Perform the FFT
|
||||||
RealFFTf(pFFT.get(), hFFT);
|
RealFFTf(pFFT.get(), hFFT.get());
|
||||||
|
|
||||||
// Copy the data into the real and imaginary outputs
|
// Copy the data into the real and imaginary outputs
|
||||||
for (size_t i = 1; i<NumSamples / 2; i++) {
|
for (size_t i = 1; i<NumSamples / 2; i++) {
|
||||||
@ -325,7 +319,6 @@ void PowerSpectrum(size_t NumSamples, const float *In, float *Out)
|
|||||||
// Handle the (real-only) DC and Fs/2 bins
|
// Handle the (real-only) DC and Fs/2 bins
|
||||||
Out[0] = pFFT[0]*pFFT[0];
|
Out[0] = pFFT[0]*pFFT[0];
|
||||||
Out[NumSamples / 2] = pFFT[1]*pFFT[1];
|
Out[NumSamples / 2] = pFFT[1]*pFFT[1];
|
||||||
ReleaseFFT(hFFT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -386,10 +386,10 @@ int import_ffmpeg_decode_frame(streamContext *sc, bool flushing)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sc->m_samplefmt = sc->m_codecCtx->sample_fmt;
|
sc->m_samplefmt = sc->m_codecCtx->sample_fmt;
|
||||||
sc->m_samplesize = av_get_bytes_per_sample(sc->m_samplefmt);
|
sc->m_samplesize = static_cast<size_t>(av_get_bytes_per_sample(sc->m_samplefmt));
|
||||||
|
|
||||||
int channels = sc->m_codecCtx->channels;
|
int channels = sc->m_codecCtx->channels;
|
||||||
unsigned int newsize = sc->m_samplesize * frame->nb_samples * channels;
|
auto newsize = sc->m_samplesize * frame->nb_samples * channels;
|
||||||
sc->m_decodedAudioSamplesValidSiz = newsize;
|
sc->m_decodedAudioSamplesValidSiz = newsize;
|
||||||
// Reallocate the audio sample buffer if it's smaller than the frame size.
|
// Reallocate the audio sample buffer if it's smaller than the frame size.
|
||||||
if (newsize > sc->m_decodedAudioSamplesSiz )
|
if (newsize > sc->m_decodedAudioSamplesSiz )
|
||||||
|
@ -982,13 +982,13 @@ struct streamContext
|
|||||||
int m_frameValid{}; // is m_decodedVideoFrame/m_decodedAudioSamples valid?
|
int m_frameValid{}; // is m_decodedVideoFrame/m_decodedAudioSamples valid?
|
||||||
AVMallocHolder<uint8_t> m_decodedAudioSamples; // decoded audio samples stored here
|
AVMallocHolder<uint8_t> m_decodedAudioSamples; // decoded audio samples stored here
|
||||||
unsigned int m_decodedAudioSamplesSiz{}; // current size of m_decodedAudioSamples
|
unsigned int m_decodedAudioSamplesSiz{}; // current size of m_decodedAudioSamples
|
||||||
int m_decodedAudioSamplesValidSiz{}; // # valid bytes in m_decodedAudioSamples
|
size_t m_decodedAudioSamplesValidSiz{}; // # valid bytes in m_decodedAudioSamples
|
||||||
int m_initialchannels{}; // number of channels allocated when we begin the importing. Assumes that number of channels doesn't change on the fly.
|
int m_initialchannels{}; // number of channels allocated when we begin the importing. Assumes that number of channels doesn't change on the fly.
|
||||||
|
|
||||||
int m_samplesize{}; // input sample size in bytes
|
size_t m_samplesize{}; // input sample size in bytes
|
||||||
AVSampleFormat m_samplefmt{ AV_SAMPLE_FMT_NONE }; // input sample format
|
AVSampleFormat m_samplefmt{ AV_SAMPLE_FMT_NONE }; // input sample format
|
||||||
|
|
||||||
int m_osamplesize{}; // output sample size in bytes
|
size_t m_osamplesize{}; // output sample size in bytes
|
||||||
sampleFormat m_osamplefmt{ floatSample }; // output sample format
|
sampleFormat m_osamplefmt{ floatSample }; // output sample format
|
||||||
|
|
||||||
streamContext() { memset(this, 0, sizeof(*this)); }
|
streamContext() { memset(this, 0, sizeof(*this)); }
|
||||||
|
@ -15,6 +15,8 @@ information.
|
|||||||
*//*******************************************************************/
|
*//*******************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Audacity.h"
|
||||||
|
#include "MemoryX.h"
|
||||||
#include <wx/arrstr.h>
|
#include <wx/arrstr.h>
|
||||||
#include <wx/intl.h>
|
#include <wx/intl.h>
|
||||||
#include "sndfile.h"
|
#include "sndfile.h"
|
||||||
@ -119,7 +121,6 @@ wxString sf_header_name(int format)
|
|||||||
wxString sf_header_shortname(int format)
|
wxString sf_header_shortname(int format)
|
||||||
{
|
{
|
||||||
SF_FORMAT_INFO format_info;
|
SF_FORMAT_INFO format_info;
|
||||||
char *tmp;
|
|
||||||
int i;
|
int i;
|
||||||
wxString s;
|
wxString s;
|
||||||
|
|
||||||
@ -127,8 +128,7 @@ wxString sf_header_shortname(int format)
|
|||||||
format_info.format = (format & SF_FORMAT_TYPEMASK);
|
format_info.format = (format & SF_FORMAT_TYPEMASK);
|
||||||
sf_command(NULL, SFC_GET_FORMAT_INFO, &format_info, sizeof(format_info));
|
sf_command(NULL, SFC_GET_FORMAT_INFO, &format_info, sizeof(format_info));
|
||||||
|
|
||||||
tmp = (char *)malloc(strlen(format_info.name)+1);
|
MallocString<> tmp { strdup( format_info.name ) };
|
||||||
strcpy(tmp, format_info.name);
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while(tmp[i]) {
|
while(tmp[i]) {
|
||||||
if (tmp[i]==' ')
|
if (tmp[i]==' ')
|
||||||
@ -137,9 +137,7 @@ wxString sf_header_shortname(int format)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = LAT1CTOWX(tmp);
|
s = LAT1CTOWX(tmp.get());
|
||||||
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
107
src/RealFFTf.cpp
107
src/RealFFTf.cpp
@ -37,11 +37,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Audacity.h"
|
#include "Audacity.h"
|
||||||
|
#include <vector>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "Experimental.h"
|
#include "Experimental.h"
|
||||||
|
|
||||||
|
#include <wx/thread.h>
|
||||||
|
|
||||||
#include "RealFFTf.h"
|
#include "RealFFTf.h"
|
||||||
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
|
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
|
||||||
#include "RealFFTf48x.h"
|
#include "RealFFTf48x.h"
|
||||||
@ -58,13 +61,8 @@
|
|||||||
HFFT InitializeFFT(size_t fftlen)
|
HFFT InitializeFFT(size_t fftlen)
|
||||||
{
|
{
|
||||||
int temp;
|
int temp;
|
||||||
HFFT h;
|
HFFT h{ safenew FFTParam };
|
||||||
|
|
||||||
if((h=(HFFT)malloc(sizeof(FFTParam)))==NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr,"Error allocating memory for FFT\n");
|
|
||||||
exit(8);
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* FFT size is only half the number of data points
|
* FFT size is only half the number of data points
|
||||||
* The full FFT output can be reconstructed from this FFT's output.
|
* The full FFT output can be reconstructed from this FFT's output.
|
||||||
@ -72,17 +70,9 @@ HFFT InitializeFFT(size_t fftlen)
|
|||||||
*/
|
*/
|
||||||
h->Points = fftlen / 2;
|
h->Points = fftlen / 2;
|
||||||
|
|
||||||
if((h->SinTable=(fft_type *)malloc(2*h->Points*sizeof(fft_type)))==NULL)
|
h->SinTable.reinit(2*h->Points);
|
||||||
{
|
|
||||||
fprintf(stderr,"Error allocating memory for Sine table.\n");
|
|
||||||
exit(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((h->BitReversed=(int *)malloc(h->Points*sizeof(int)))==NULL)
|
h->BitReversed.reinit(h->Points);
|
||||||
{
|
|
||||||
fprintf(stderr,"Error allocating memory for BitReversed.\n");
|
|
||||||
exit(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0; i < h->Points; i++)
|
for(size_t i = 0; i < h->Points; i++)
|
||||||
{
|
{
|
||||||
@ -109,40 +99,33 @@ HFFT InitializeFFT(size_t fftlen)
|
|||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Free up the memory allotted for Sin table and Twiddle Pointers
|
|
||||||
*/
|
|
||||||
void EndFFT(HFFT h)
|
|
||||||
{
|
|
||||||
if(h->Points > 0) {
|
|
||||||
free(h->BitReversed);
|
|
||||||
free(h->SinTable);
|
|
||||||
}
|
|
||||||
h->Points = 0;
|
|
||||||
free(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum : size_t { MAX_HFFT = 10 };
|
enum : size_t { MAX_HFFT = 10 };
|
||||||
static HFFT hFFTArray[MAX_HFFT] = { NULL };
|
|
||||||
static int nFFTLockCount[MAX_HFFT] = { 0 };
|
// Maintain a pool:
|
||||||
|
static std::vector< movable_ptr<FFTParam> > hFFTArray(MAX_HFFT);
|
||||||
|
wxCriticalSection getFFTMutex;
|
||||||
|
|
||||||
/* Get a handle to the FFT tables of the desired length */
|
/* Get a handle to the FFT tables of the desired length */
|
||||||
/* This version keeps common tables rather than allocating a NEW table every time */
|
/* This version keeps common tables rather than allocating a NEW table every time */
|
||||||
HFFT GetFFT(size_t fftlen)
|
HFFT GetFFT(size_t fftlen)
|
||||||
{
|
{
|
||||||
|
// To do: smarter policy about when to retain in the pool and when to
|
||||||
|
// allocate a unique instance.
|
||||||
|
|
||||||
|
wxCriticalSectionLocker locker{ getFFTMutex };
|
||||||
|
|
||||||
size_t h = 0;
|
size_t h = 0;
|
||||||
auto n = fftlen/2;
|
auto n = fftlen/2;
|
||||||
|
auto size = hFFTArray.size();
|
||||||
for(;
|
for(;
|
||||||
(h < MAX_HFFT) && (hFFTArray[h] != NULL) && (n != hFFTArray[h]->Points);
|
(h < size) && hFFTArray[h] && (n != hFFTArray[h]->Points);
|
||||||
h++)
|
h++)
|
||||||
;
|
;
|
||||||
if(h < MAX_HFFT) {
|
if(h < size) {
|
||||||
if(hFFTArray[h] == NULL) {
|
if(hFFTArray[h] == NULL) {
|
||||||
hFFTArray[h] = InitializeFFT(fftlen);
|
hFFTArray[h].reset( InitializeFFT(fftlen).release() );
|
||||||
nFFTLockCount[h] = 0;
|
|
||||||
}
|
}
|
||||||
nFFTLockCount[h]++;
|
return HFFT{ hFFTArray[h].get() };
|
||||||
return hFFTArray[h];
|
|
||||||
} else {
|
} else {
|
||||||
// All buffers used, so fall back to allocating a NEW set of tables
|
// All buffers used, so fall back to allocating a NEW set of tables
|
||||||
return InitializeFFT(fftlen);
|
return InitializeFFT(fftlen);
|
||||||
@ -150,31 +133,21 @@ HFFT GetFFT(size_t fftlen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Release a previously requested handle to the FFT tables */
|
/* Release a previously requested handle to the FFT tables */
|
||||||
void ReleaseFFT(HFFT hFFT)
|
void FFTDeleter::operator() (FFTParam *hFFT) const
|
||||||
{
|
{
|
||||||
int h;
|
wxCriticalSectionLocker locker{ getFFTMutex };
|
||||||
for(h=0; (h<MAX_HFFT) && (hFFTArray[h] != hFFT); h++);
|
|
||||||
if(h<MAX_HFFT) {
|
|
||||||
nFFTLockCount[h]--;
|
|
||||||
} else {
|
|
||||||
EndFFT(hFFT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Deallocate any unused FFT tables */
|
auto it = hFFTArray.begin(), end = hFFTArray.end();
|
||||||
void CleanupFFT()
|
while (it != end && it->get() != hFFT)
|
||||||
{
|
++it;
|
||||||
int h;
|
if ( it != end )
|
||||||
for(h=0; (h<MAX_HFFT); h++) {
|
;
|
||||||
if((nFFTLockCount[h] <= 0) && (hFFTArray[h] != NULL)) {
|
else
|
||||||
EndFFT(hFFTArray[h]);
|
delete hFFT;
|
||||||
hFFTArray[h] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forward FFT routine. Must call InitializeFFT(fftlen) first!
|
* Forward FFT routine. Must call GetFFT(fftlen) first!
|
||||||
*
|
*
|
||||||
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
||||||
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
||||||
@ -191,7 +164,7 @@ void CleanupFFT()
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void RealFFTf(fft_type *buffer,HFFT h)
|
void RealFFTf(fft_type *buffer, const FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
const fft_type *sptr;
|
const fft_type *sptr;
|
||||||
@ -216,7 +189,7 @@ void RealFFTf(fft_type *buffer,HFFT h)
|
|||||||
{
|
{
|
||||||
A = buffer;
|
A = buffer;
|
||||||
B = buffer + ButterfliesPerGroup * 2;
|
B = buffer + ButterfliesPerGroup * 2;
|
||||||
sptr = h->SinTable;
|
sptr = h->SinTable.get();
|
||||||
|
|
||||||
while(A < endptr1)
|
while(A < endptr1)
|
||||||
{
|
{
|
||||||
@ -239,8 +212,8 @@ void RealFFTf(fft_type *buffer,HFFT h)
|
|||||||
ButterfliesPerGroup >>= 1;
|
ButterfliesPerGroup >>= 1;
|
||||||
}
|
}
|
||||||
/* Massage output to get the output for a real input sequence. */
|
/* Massage output to get the output for a real input sequence. */
|
||||||
br1 = h->BitReversed + 1;
|
br1 = h->BitReversed.get() + 1;
|
||||||
br2 = h->BitReversed + h->Points - 1;
|
br2 = h->BitReversed.get() + h->Points - 1;
|
||||||
|
|
||||||
while(br1<br2)
|
while(br1<br2)
|
||||||
{
|
{
|
||||||
@ -281,7 +254,7 @@ void RealFFTf(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -293,7 +266,7 @@ void RealFFTf(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf(fft_type *buffer,HFFT h)
|
void InverseRealFFTf(fft_type *buffer, const FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
const fft_type *sptr;
|
const fft_type *sptr;
|
||||||
@ -307,7 +280,7 @@ void InverseRealFFTf(fft_type *buffer,HFFT h)
|
|||||||
/* Massage input to get the input for a real output sequence. */
|
/* Massage input to get the input for a real output sequence. */
|
||||||
A = buffer + 2;
|
A = buffer + 2;
|
||||||
B = buffer + h->Points * 2 - 2;
|
B = buffer + h->Points * 2 - 2;
|
||||||
br1 = h->BitReversed + 1;
|
br1 = h->BitReversed.get() + 1;
|
||||||
while(A<B)
|
while(A<B)
|
||||||
{
|
{
|
||||||
sin=h->SinTable[*br1];
|
sin=h->SinTable[*br1];
|
||||||
@ -353,7 +326,7 @@ void InverseRealFFTf(fft_type *buffer,HFFT h)
|
|||||||
{
|
{
|
||||||
A = buffer;
|
A = buffer;
|
||||||
B = buffer + ButterfliesPerGroup * 2;
|
B = buffer + ButterfliesPerGroup * 2;
|
||||||
sptr = h->SinTable;
|
sptr = h->SinTable.get();
|
||||||
|
|
||||||
while(A < endptr1)
|
while(A < endptr1)
|
||||||
{
|
{
|
||||||
@ -376,7 +349,7 @@ void InverseRealFFTf(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq(HFFT hFFT, const fft_type *buffer,
|
void ReorderToFreq(const FFTParam *hFFT, const fft_type *buffer,
|
||||||
fft_type *RealOut, fft_type *ImagOut)
|
fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
// Copy the data into the real and imaginary outputs
|
// Copy the data into the real and imaginary outputs
|
||||||
@ -390,7 +363,7 @@ void ReorderToFreq(HFFT hFFT, const fft_type *buffer,
|
|||||||
ImagOut[hFFT->Points] = 0;
|
ImagOut[hFFT->Points] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime(HFFT hFFT, const fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime(const FFTParam *hFFT, const fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
// Copy the data into the real outputs
|
// Copy the data into the real outputs
|
||||||
for(size_t i = 0; i < hFFT->Points; i++) {
|
for(size_t i = 0; i < hFFT->Points; i++) {
|
||||||
|
@ -1,28 +1,33 @@
|
|||||||
#ifndef __realfftf_h
|
#ifndef __realfftf_h
|
||||||
#define __realfftf_h
|
#define __realfftf_h
|
||||||
|
|
||||||
|
#include "Audacity.h"
|
||||||
#include "Experimental.h"
|
#include "Experimental.h"
|
||||||
|
#include "MemoryX.h"
|
||||||
|
|
||||||
#define fft_type float
|
using fft_type = float;
|
||||||
struct FFTParam {
|
struct FFTParam {
|
||||||
int *BitReversed;
|
ArrayOf<int> BitReversed;
|
||||||
fft_type *SinTable;
|
ArrayOf<fft_type> SinTable;
|
||||||
size_t Points;
|
size_t Points;
|
||||||
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
|
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
|
||||||
int pow2Bits;
|
int pow2Bits;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
typedef FFTParam * HFFT;
|
|
||||||
|
|
||||||
HFFT InitializeFFT(size_t);
|
struct FFTDeleter{
|
||||||
void EndFFT(HFFT);
|
void operator () (FFTParam *p) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
using HFFT = std::unique_ptr<
|
||||||
|
FFTParam, FFTDeleter
|
||||||
|
>;
|
||||||
|
|
||||||
HFFT GetFFT(size_t);
|
HFFT GetFFT(size_t);
|
||||||
void ReleaseFFT(HFFT);
|
void RealFFTf(fft_type *, const FFTParam *);
|
||||||
void CleanupFFT();
|
void InverseRealFFTf(fft_type *, const FFTParam *);
|
||||||
void RealFFTf(fft_type *,HFFT);
|
void ReorderToTime(const FFTParam *hFFT, const fft_type *buffer, fft_type *TimeOut);
|
||||||
void InverseRealFFTf(fft_type *,HFFT);
|
void ReorderToFreq(const FFTParam *hFFT, const fft_type *buffer,
|
||||||
void ReorderToTime(HFFT hFFT, const fft_type *buffer, fft_type *TimeOut);
|
|
||||||
void ReorderToFreq(HFFT hFFT, const fft_type *buffer,
|
|
||||||
fft_type *RealOut, fft_type *ImagOut);
|
fft_type *RealOut, fft_type *ImagOut);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
* and BitReversed tables so they don't need to be reallocated
|
* and BitReversed tables so they don't need to be reallocated
|
||||||
* and recomputed on every call.
|
* and recomputed on every call.
|
||||||
* - Added Reorder* functions to undo the bit-reversal
|
* - Added Reorder* functions to undo the bit-reversal
|
||||||
|
* Modified 15 April 2016 Paul Licameli
|
||||||
|
* - C++11 smart pointers
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009 Philip VanBaren
|
* Copyright (C) 2009 Philip VanBaren
|
||||||
*
|
*
|
||||||
@ -146,7 +148,7 @@ int SmallRB(int bits, int numberBits)
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* wrapper funcitons. If passed -1 function choice will be made locally */
|
/* wrapper funcitons. If passed -1 function choice will be made locally */
|
||||||
void RealFFTf1x(fft_type *buffer, HFFT h, int functionType)
|
void RealFFTf1x(fft_type *buffer, FFTParam *h, int functionType)
|
||||||
{
|
{
|
||||||
switch(functionType) {
|
switch(functionType) {
|
||||||
case FFT_SinCosTableVBR16:
|
case FFT_SinCosTableVBR16:
|
||||||
@ -167,7 +169,7 @@ void RealFFTf1x(fft_type *buffer, HFFT h, int functionType)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void InverseRealFFTf1x(fft_type *buffer, HFFT h, int functionType)
|
void InverseRealFFTf1x(fft_type *buffer, FFTParam *h, int functionType)
|
||||||
{
|
{
|
||||||
switch(functionType) {
|
switch(functionType) {
|
||||||
case FFT_SinCosTableVBR16:
|
case FFT_SinCosTableVBR16:
|
||||||
@ -188,7 +190,7 @@ void InverseRealFFTf1x(fft_type *buffer, HFFT h, int functionType)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime1x(HFFT hFFT, fft_type *buffer, fft_type *TimeOut, int functionType)
|
void ReorderToTime1x(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut, int functionType)
|
||||||
{
|
{
|
||||||
switch(functionType) {
|
switch(functionType) {
|
||||||
case FFT_SinCosTableVBR16:
|
case FFT_SinCosTableVBR16:
|
||||||
@ -209,7 +211,7 @@ void ReorderToTime1x(HFFT hFFT, fft_type *buffer, fft_type *TimeOut, int functio
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq1x(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut, int functionType)
|
void ReorderToFreq1x(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut, int functionType)
|
||||||
{
|
{
|
||||||
switch(functionType) {
|
switch(functionType) {
|
||||||
case FFT_SinCosTableVBR16:
|
case FFT_SinCosTableVBR16:
|
||||||
@ -230,7 +232,7 @@ void ReorderToFreq1x(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *I
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealFFTf4x( fft_type *buffer, HFFT h, int functionType)
|
void RealFFTf4x( fft_type *buffer, FFTParam *h, int functionType)
|
||||||
{
|
{
|
||||||
switch(functionType) {
|
switch(functionType) {
|
||||||
case FFT_SinCosTableVBR16:
|
case FFT_SinCosTableVBR16:
|
||||||
@ -251,7 +253,7 @@ void RealFFTf4x( fft_type *buffer, HFFT h, int functionType)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void InverseRealFFTf4x( fft_type *buffer, HFFT h, int functionType)
|
void InverseRealFFTf4x( fft_type *buffer, FFTParam *h, int functionType)
|
||||||
{
|
{
|
||||||
switch(functionType) {
|
switch(functionType) {
|
||||||
case FFT_SinCosTableVBR16:
|
case FFT_SinCosTableVBR16:
|
||||||
@ -272,7 +274,7 @@ void InverseRealFFTf4x( fft_type *buffer, HFFT h, int functionType)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime4x(HFFT hFFT, fft_type *buffer, fft_type *TimeOut, int functionType)
|
void ReorderToTime4x(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut, int functionType)
|
||||||
{
|
{
|
||||||
switch(functionType) {
|
switch(functionType) {
|
||||||
case FFT_SinCosTableVBR16:
|
case FFT_SinCosTableVBR16:
|
||||||
@ -293,7 +295,7 @@ void ReorderToTime4x(HFFT hFFT, fft_type *buffer, fft_type *TimeOut, int functio
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq4x(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut, int functionType)
|
void ReorderToFreq4x(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut, int functionType)
|
||||||
{
|
{
|
||||||
switch(functionType) {
|
switch(functionType) {
|
||||||
case FFT_SinCosTableVBR16:
|
case FFT_SinCosTableVBR16:
|
||||||
@ -318,7 +320,7 @@ void ReorderToFreq4x(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *I
|
|||||||
#ifdef REAL_SINCOSBRTABLE
|
#ifdef REAL_SINCOSBRTABLE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forward FFT routine. Must call InitializeFFT(fftlen) first!
|
* Forward FFT routine. Must call GetFFT(fftlen) first!
|
||||||
*
|
*
|
||||||
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
||||||
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
||||||
@ -335,7 +337,7 @@ void ReorderToFreq4x(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *I
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void RealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
void RealFFTf1xSinCosBRTable(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *sptr;
|
fft_type *sptr;
|
||||||
@ -360,7 +362,7 @@ void RealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
{
|
{
|
||||||
A = buffer;
|
A = buffer;
|
||||||
B = buffer + ButterfliesPerGroup * 2;
|
B = buffer + ButterfliesPerGroup * 2;
|
||||||
sptr = h->SinTable;
|
sptr = h->SinTable.get();
|
||||||
|
|
||||||
while(A < endptr1)
|
while(A < endptr1)
|
||||||
{
|
{
|
||||||
@ -383,8 +385,8 @@ void RealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
ButterfliesPerGroup >>= 1;
|
ButterfliesPerGroup >>= 1;
|
||||||
}
|
}
|
||||||
/* Massage output to get the output for a real input sequence. */
|
/* Massage output to get the output for a real input sequence. */
|
||||||
br1 = h->BitReversed + 1;
|
br1 = h->BitReversed.get() + 1;
|
||||||
br2 = h->BitReversed + h->Points - 1;
|
br2 = h->BitReversed.get() + h->Points - 1;
|
||||||
|
|
||||||
while(br1 < br2)
|
while(br1 < br2)
|
||||||
{
|
{
|
||||||
@ -425,7 +427,7 @@ void RealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -437,7 +439,7 @@ void RealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
void InverseRealFFTf1xSinCosBRTable(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *sptr;
|
fft_type *sptr;
|
||||||
@ -451,7 +453,7 @@ void InverseRealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
/* Massage input to get the input for a real output sequence. */
|
/* Massage input to get the input for a real output sequence. */
|
||||||
A = buffer + 2;
|
A = buffer + 2;
|
||||||
B = buffer + h->Points * 2 - 2;
|
B = buffer + h->Points * 2 - 2;
|
||||||
br1 = h->BitReversed + 1;
|
br1 = h->BitReversed.get() + 1;
|
||||||
while(A < B)
|
while(A < B)
|
||||||
{
|
{
|
||||||
sin=h->SinTable[*br1];
|
sin=h->SinTable[*br1];
|
||||||
@ -497,7 +499,7 @@ void InverseRealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
{
|
{
|
||||||
A = buffer;
|
A = buffer;
|
||||||
B = buffer + ButterfliesPerGroup * 2;
|
B = buffer + ButterfliesPerGroup * 2;
|
||||||
sptr = h->SinTable;
|
sptr = h->SinTable.get();
|
||||||
|
|
||||||
while(A < endptr1)
|
while(A < endptr1)
|
||||||
{
|
{
|
||||||
@ -520,7 +522,7 @@ void InverseRealFFTf1xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq1xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq1xSinCosBRTable(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
// Copy the data into the real and imaginary outputs
|
// Copy the data into the real and imaginary outputs
|
||||||
for(size_t i = 1; i < hFFT->Points; i++) {
|
for(size_t i = 1; i < hFFT->Points; i++) {
|
||||||
@ -533,7 +535,7 @@ void ReorderToFreq1xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *RealOut
|
|||||||
ImagOut[hFFT->Points] = 0;
|
ImagOut[hFFT->Points] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime1xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime1xSinCosBRTable(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
// Copy the data into the real outputs
|
// Copy the data into the real outputs
|
||||||
for(size_t i = 0; i < hFFT->Points; i++) {
|
for(size_t i = 0; i < hFFT->Points; i++) {
|
||||||
@ -543,7 +545,7 @@ void ReorderToTime1xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *TimeOut
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4x processing simd
|
// 4x processing simd
|
||||||
void RealFFTf4xSinCosBRTable(fft_type *buffer,HFFT h)
|
void RealFFTf4xSinCosBRTable(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -571,7 +573,7 @@ void RealFFTf4xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
{
|
{
|
||||||
A = localBuffer;
|
A = localBuffer;
|
||||||
B = &localBuffer[ButterfliesPerGroup * 2];
|
B = &localBuffer[ButterfliesPerGroup * 2];
|
||||||
sptr = h->SinTable;
|
sptr = h->SinTable.get();
|
||||||
while(A < endptr1)
|
while(A < endptr1)
|
||||||
{
|
{
|
||||||
sin = _mm_set1_ps(*(sptr++));
|
sin = _mm_set1_ps(*(sptr++));
|
||||||
@ -637,7 +639,7 @@ void RealFFTf4xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -649,7 +651,7 @@ void RealFFTf4xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf4xSinCosBRTable(fft_type *buffer,HFFT h)
|
void InverseRealFFTf4xSinCosBRTable(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -717,7 +719,7 @@ void InverseRealFFTf4xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
{
|
{
|
||||||
A = localBuffer;
|
A = localBuffer;
|
||||||
B = localBuffer + ButterfliesPerGroup * 2;
|
B = localBuffer + ButterfliesPerGroup * 2;
|
||||||
sptr = h->SinTable;
|
sptr = h->SinTable.get();
|
||||||
while(A < endptr1)
|
while(A < endptr1)
|
||||||
{
|
{
|
||||||
sin = _mm_set1_ps(*(sptr++));
|
sin = _mm_set1_ps(*(sptr++));
|
||||||
@ -739,7 +741,7 @@ void InverseRealFFTf4xSinCosBRTable(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq4xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq4xSinCosBRTable(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
__m128 *localRealOut=(__m128 *)RealOut;
|
__m128 *localRealOut=(__m128 *)RealOut;
|
||||||
@ -758,7 +760,7 @@ void ReorderToFreq4xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *RealOut
|
|||||||
localImagOut[hFFT->Points] = _mm_set1_ps(0.0);
|
localImagOut[hFFT->Points] = _mm_set1_ps(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime4xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime4xSinCosBRTable(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
__m128 *localTimeOut=(__m128 *)TimeOut;
|
__m128 *localTimeOut=(__m128 *)TimeOut;
|
||||||
@ -777,7 +779,7 @@ void ReorderToTime4xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *TimeOut
|
|||||||
#ifdef REAL_SINCOSTABLE_VBR16
|
#ifdef REAL_SINCOSTABLE_VBR16
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forward FFT routine. Must call InitializeFFT(fftlen) first!
|
* Forward FFT routine. Must call GetFFT(fftlen) first!
|
||||||
*
|
*
|
||||||
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
||||||
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
||||||
@ -794,7 +796,7 @@ void ReorderToTime4xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *TimeOut
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void RealFFTf1xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
void RealFFTf1xSinCosTableVBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *endptr1,*endptr2;
|
fft_type *endptr1,*endptr2;
|
||||||
@ -880,7 +882,7 @@ void RealFFTf1xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -892,7 +894,7 @@ void RealFFTf1xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf1xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
void InverseRealFFTf1xSinCosTableVBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *endptr1,*endptr2;
|
fft_type *endptr1,*endptr2;
|
||||||
@ -907,7 +909,7 @@ void InverseRealFFTf1xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
|||||||
/* Massage input to get the input for a real output sequence. */
|
/* Massage input to get the input for a real output sequence. */
|
||||||
A = buffer + 2;
|
A = buffer + 2;
|
||||||
B = buffer + h->Points * 2 - 2;
|
B = buffer + h->Points * 2 - 2;
|
||||||
br1 = h->BitReversed + 1;
|
br1 = h->BitReversed.get() + 1;
|
||||||
br1Index = 1; //h->BitReversed + 1;
|
br1Index = 1; //h->BitReversed + 1;
|
||||||
while(A < B)
|
while(A < B)
|
||||||
{
|
{
|
||||||
@ -980,7 +982,7 @@ void InverseRealFFTf1xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime1xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime1xSinCosTableVBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
// Copy the data into the real outputs
|
// Copy the data into the real outputs
|
||||||
for(size_t i = 0;i < hFFT->Points; i++) {
|
for(size_t i = 0;i < hFFT->Points; i++) {
|
||||||
@ -991,7 +993,7 @@ void ReorderToTime1xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *Time
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq1xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq1xSinCosTableVBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
// Copy the data into the real and imaginary outputs
|
// Copy the data into the real and imaginary outputs
|
||||||
for(size_t i = 1; i < hFFT->Points; i++) {
|
for(size_t i = 1; i < hFFT->Points; i++) {
|
||||||
@ -1007,7 +1009,7 @@ void ReorderToFreq1xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *Real
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4x processing simd
|
// 4x processing simd
|
||||||
void RealFFTf4xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
void RealFFTf4xSinCosTableVBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -1105,7 +1107,7 @@ void RealFFTf4xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -1117,7 +1119,7 @@ void RealFFTf4xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf4xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
void InverseRealFFTf4xSinCosTableVBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -1210,7 +1212,7 @@ void InverseRealFFTf4xSinCosTableVBR16(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime4xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime4xSinCosTableVBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer = (__m128 *)buffer;
|
__m128 *localBuffer = (__m128 *)buffer;
|
||||||
__m128 *localTimeOut = (__m128 *)TimeOut;
|
__m128 *localTimeOut = (__m128 *)TimeOut;
|
||||||
@ -1223,7 +1225,7 @@ void ReorderToTime4xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *Time
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq4xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq4xSinCosTableVBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer = (__m128 *)buffer;
|
__m128 *localBuffer = (__m128 *)buffer;
|
||||||
__m128 *localRealOut = (__m128 *)RealOut;
|
__m128 *localRealOut = (__m128 *)RealOut;
|
||||||
@ -1247,7 +1249,7 @@ void ReorderToFreq4xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *Real
|
|||||||
#ifdef REAL_SINCOSTABLE_BR16
|
#ifdef REAL_SINCOSTABLE_BR16
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forward FFT routine. Must call InitializeFFT(fftlen) first!
|
* Forward FFT routine. Must call GetFFT(fftlen) first!
|
||||||
*
|
*
|
||||||
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
||||||
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
||||||
@ -1264,7 +1266,7 @@ void ReorderToFreq4xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *Real
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void RealFFTf1xSinCosTableBR16(fft_type *buffer,HFFT h)
|
void RealFFTf1xSinCosTableBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *endptr1, *endptr2;
|
fft_type *endptr1, *endptr2;
|
||||||
@ -1354,7 +1356,7 @@ void RealFFTf1xSinCosTableBR16(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -1366,7 +1368,7 @@ void RealFFTf1xSinCosTableBR16(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf1xSinCosTableBR16(fft_type *buffer,HFFT h)
|
void InverseRealFFTf1xSinCosTableBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *endptr1,*endptr2;
|
fft_type *endptr1,*endptr2;
|
||||||
@ -1453,7 +1455,7 @@ void InverseRealFFTf1xSinCosTableBR16(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq1xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq1xSinCosTableBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
int bitReverseShift=16-hFFT->pow2Bits;
|
int bitReverseShift=16-hFFT->pow2Bits;
|
||||||
// Copy the data into the real and imaginary outputs
|
// Copy the data into the real and imaginary outputs
|
||||||
@ -1470,7 +1472,7 @@ void ReorderToFreq1xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *RealO
|
|||||||
ImagOut[hFFT->Points] = 0;
|
ImagOut[hFFT->Points] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime1xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime1xSinCosTableBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
int bitReverseShift=16-hFFT->pow2Bits;
|
int bitReverseShift=16-hFFT->pow2Bits;
|
||||||
// Copy the data into the real outputs
|
// Copy the data into the real outputs
|
||||||
@ -1484,7 +1486,7 @@ void ReorderToTime1xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeO
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4x processing simd
|
// 4x processing simd
|
||||||
void RealFFTf4xSinCosTableBR16(fft_type *buffer,HFFT h)
|
void RealFFTf4xSinCosTableBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -1586,7 +1588,7 @@ void RealFFTf4xSinCosTableBR16(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -1598,7 +1600,7 @@ void RealFFTf4xSinCosTableBR16(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf4xSinCosTableBR16(fft_type *buffer,HFFT h)
|
void InverseRealFFTf4xSinCosTableBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -1692,7 +1694,7 @@ void InverseRealFFTf4xSinCosTableBR16(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime4xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime4xSinCosTableBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer = (__m128 *)buffer;
|
__m128 *localBuffer = (__m128 *)buffer;
|
||||||
__m128 *localTimeOut = (__m128 *)TimeOut;
|
__m128 *localTimeOut = (__m128 *)TimeOut;
|
||||||
@ -1708,7 +1710,7 @@ void ReorderToTime4xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq4xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq4xSinCosTableBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer = (__m128 *)buffer;
|
__m128 *localBuffer = (__m128 *)buffer;
|
||||||
__m128 *localRealOut = (__m128 *)RealOut;
|
__m128 *localRealOut = (__m128 *)RealOut;
|
||||||
@ -1734,7 +1736,7 @@ void ReorderToFreq4xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *RealO
|
|||||||
#ifdef FAST_MATH_BR24
|
#ifdef FAST_MATH_BR24
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forward FFT routine. Must call InitializeFFT(fftlen) first!
|
* Forward FFT routine. Must call GetFFT(fftlen) first!
|
||||||
*
|
*
|
||||||
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
||||||
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
||||||
@ -1751,7 +1753,7 @@ void ReorderToFreq4xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *RealO
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void RealFFTf1xFastMathBR24(fft_type *buffer,HFFT h)
|
void RealFFTf1xFastMathBR24(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A, *B;
|
fft_type *A, *B;
|
||||||
fft_type *endptr1, *endptr2;
|
fft_type *endptr1, *endptr2;
|
||||||
@ -1886,7 +1888,7 @@ void RealFFTf1xFastMathBR24(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -1898,7 +1900,7 @@ void RealFFTf1xFastMathBR24(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf1xFastMathBR24(fft_type *buffer,HFFT h)
|
void InverseRealFFTf1xFastMathBR24(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *endptr1,*endptr2;
|
fft_type *endptr1,*endptr2;
|
||||||
@ -2019,7 +2021,7 @@ void InverseRealFFTf1xFastMathBR24(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq1xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq1xFastMathBR24(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
int bitReverseShift = 24 - hFFT->pow2Bits;
|
int bitReverseShift = 24 - hFFT->pow2Bits;
|
||||||
// Copy the data into the real and imaginary outputs
|
// Copy the data into the real and imaginary outputs
|
||||||
@ -2037,7 +2039,7 @@ void ReorderToFreq1xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *RealOut,
|
|||||||
ImagOut[hFFT->Points] = 0;
|
ImagOut[hFFT->Points] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime1xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime1xFastMathBR24(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
int bitReverseShift = 24 - hFFT->pow2Bits;
|
int bitReverseShift = 24 - hFFT->pow2Bits;
|
||||||
// Copy the data into the real outputs
|
// Copy the data into the real outputs
|
||||||
@ -2050,7 +2052,7 @@ void ReorderToTime1xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealFFTf4xFastMathBR24(fft_type *buffer,HFFT h)
|
void RealFFTf4xFastMathBR24(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -2186,7 +2188,7 @@ void RealFFTf4xFastMathBR24(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -2198,7 +2200,7 @@ void RealFFTf4xFastMathBR24(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf4xFastMathBR24(fft_type *buffer,HFFT h)
|
void InverseRealFFTf4xFastMathBR24(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -2325,7 +2327,7 @@ void InverseRealFFTf4xFastMathBR24(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq4xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq4xFastMathBR24(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer = (__m128 *)buffer;
|
__m128 *localBuffer = (__m128 *)buffer;
|
||||||
__m128 *localRealOut = (__m128 *)RealOut;
|
__m128 *localRealOut = (__m128 *)RealOut;
|
||||||
@ -2347,7 +2349,7 @@ void ReorderToFreq4xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *RealOut,
|
|||||||
localImagOut[hFFT->Points] = _mm_set1_ps(0.0);
|
localImagOut[hFFT->Points] = _mm_set1_ps(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime4xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime4xFastMathBR24(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer = (__m128 *)buffer;
|
__m128 *localBuffer = (__m128 *)buffer;
|
||||||
__m128 *localTimeOut = (__m128 *)TimeOut;
|
__m128 *localTimeOut = (__m128 *)TimeOut;
|
||||||
@ -2369,7 +2371,7 @@ void ReorderToTime4xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
|||||||
#ifdef FAST_MATH_BR16
|
#ifdef FAST_MATH_BR16
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forward FFT routine. Must call InitializeFFT(fftlen) first!
|
* Forward FFT routine. Must call GetFFT(fftlen) first!
|
||||||
*
|
*
|
||||||
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
* Note: Output is BIT-REVERSED! so you must use the BitReversed to
|
||||||
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
* get legible output, (i.e. Real_i = buffer[ h->BitReversed[i] ]
|
||||||
@ -2386,7 +2388,7 @@ void ReorderToTime4xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void RealFFTf1xFastMathBR16(fft_type *buffer,HFFT h)
|
void RealFFTf1xFastMathBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *endptr1,*endptr2;
|
fft_type *endptr1,*endptr2;
|
||||||
@ -2517,7 +2519,7 @@ void RealFFTf1xFastMathBR16(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -2529,7 +2531,7 @@ void RealFFTf1xFastMathBR16(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf1xFastMathBR16(fft_type *buffer,HFFT h)
|
void InverseRealFFTf1xFastMathBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
fft_type *A,*B;
|
fft_type *A,*B;
|
||||||
fft_type *endptr1,*endptr2;
|
fft_type *endptr1,*endptr2;
|
||||||
@ -2650,7 +2652,7 @@ void InverseRealFFTf1xFastMathBR16(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq1xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq1xFastMathBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
int bitReverseShift = 16 - hFFT->pow2Bits;
|
int bitReverseShift = 16 - hFFT->pow2Bits;
|
||||||
// Copy the data into the real and imaginary outputs
|
// Copy the data into the real and imaginary outputs
|
||||||
@ -2667,7 +2669,7 @@ void ReorderToFreq1xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut,
|
|||||||
ImagOut[hFFT->Points] = 0;
|
ImagOut[hFFT->Points] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime1xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime1xFastMathBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
int bitReverseShift=16-hFFT->pow2Bits;
|
int bitReverseShift=16-hFFT->pow2Bits;
|
||||||
// Copy the data into the real outputs
|
// Copy the data into the real outputs
|
||||||
@ -2680,7 +2682,7 @@ void ReorderToTime1xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealFFTf4xFastMathBR16(fft_type *buffer,HFFT h)
|
void RealFFTf4xFastMathBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer = (__m128 *)buffer;
|
__m128 *localBuffer = (__m128 *)buffer;
|
||||||
@ -2816,7 +2818,7 @@ void RealFFTf4xFastMathBR16(fft_type *buffer,HFFT h)
|
|||||||
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
* get legible output, (i.e. wave[2*i] = buffer[ BitReversed[i] ]
|
||||||
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
* wave[2*i+1] = buffer[ BitReversed[i]+1 ] )
|
||||||
* Input is in normal order, interleaved (real,imaginary) complex data
|
* Input is in normal order, interleaved (real,imaginary) complex data
|
||||||
* You must call InitializeFFT(fftlen) first to initialize some buffers!
|
* You must call GetFFT(fftlen) first to initialize some buffers!
|
||||||
*
|
*
|
||||||
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
* Input buffer[0] is the DC bin, and input buffer[1] is the Fs/2 bin
|
||||||
* - this can be done because both values will always be real only
|
* - this can be done because both values will always be real only
|
||||||
@ -2828,7 +2830,7 @@ void RealFFTf4xFastMathBR16(fft_type *buffer,HFFT h)
|
|||||||
* values would be similar in amplitude to the input values, which is
|
* values would be similar in amplitude to the input values, which is
|
||||||
* good when using fixed point arithmetic)
|
* good when using fixed point arithmetic)
|
||||||
*/
|
*/
|
||||||
void InverseRealFFTf4xFastMathBR16(fft_type *buffer,HFFT h)
|
void InverseRealFFTf4xFastMathBR16(fft_type *buffer, FFTParam *h)
|
||||||
{
|
{
|
||||||
|
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
@ -2955,7 +2957,7 @@ void InverseRealFFTf4xFastMathBR16(fft_type *buffer,HFFT h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToFreq4xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
void ReorderToFreq4xFastMathBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
__m128 *localRealOut=(__m128 *)RealOut;
|
__m128 *localRealOut=(__m128 *)RealOut;
|
||||||
@ -2977,7 +2979,7 @@ void ReorderToFreq4xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut,
|
|||||||
localImagOut[hFFT->Points] = _mm_set1_ps(0.0);
|
localImagOut[hFFT->Points] = _mm_set1_ps(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReorderToTime4xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut)
|
void ReorderToTime4xFastMathBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut)
|
||||||
{
|
{
|
||||||
__m128 *localBuffer=(__m128 *)buffer;
|
__m128 *localBuffer=(__m128 *)buffer;
|
||||||
__m128 *localTimeOut=(__m128 *)TimeOut;
|
__m128 *localTimeOut=(__m128 *)TimeOut;
|
||||||
|
@ -16,64 +16,64 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* wrapper funcitons. If passed -1 function choice will be made locally */
|
/* wrapper funcitons. If passed -1 function choice will be made locally */
|
||||||
void RealFFTf1x(fft_type *,HFFT, int functionType=-1);
|
void RealFFTf1x(fft_type *, FFTParam*, int functionType=-1);
|
||||||
void InverseRealFFTf1x(fft_type *,HFFT, int functionType=-1);
|
void InverseRealFFTf1x(fft_type *, FFTParam*, int functionType=-1);
|
||||||
void ReorderToTime1x(HFFT hFFT, fft_type *buffer, fft_type *TimeOut, int functionType=-1);
|
void ReorderToTime1x(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut, int functionType=-1);
|
||||||
void ReorderToFreq1x(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut, int functionType=-1);
|
void ReorderToFreq1x(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut, int functionType=-1);
|
||||||
void RealFFTf4x(fft_type *,HFFT, int functionType=-1);
|
void RealFFTf4x(fft_type *, FFTParam *, int functionType=-1);
|
||||||
void InverseRealFFTf4x(fft_type *,HFFT, int functionType=-1);
|
void InverseRealFFTf4x(fft_type *, FFTParam *, int functionType=-1);
|
||||||
void ReorderToTime4x(HFFT hFFT, fft_type *buffer, fft_type *TimeOut, int functionType=-1);
|
void ReorderToTime4x(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut, int functionType=-1);
|
||||||
void ReorderToFreq4x(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut, int functionType=-1);
|
void ReorderToFreq4x(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut, int functionType=-1);
|
||||||
|
|
||||||
/* SinCosBRTable versions */
|
/* SinCosBRTable versions */
|
||||||
void RealFFTf1xSinCosBRTable(fft_type *,HFFT);
|
void RealFFTf1xSinCosBRTable(fft_type *, FFTParam*);
|
||||||
void InverseRealFFTf1xSinCosBRTable(fft_type *,HFFT);
|
void InverseRealFFTf1xSinCosBRTable(fft_type *, FFTParam*);
|
||||||
void ReorderToTime1xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime1xSinCosBRTable(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq1xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq1xSinCosBRTable(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
void RealFFTf4xSinCosBRTable(fft_type *,HFFT);
|
void RealFFTf4xSinCosBRTable(fft_type *, FFTParam *);
|
||||||
void InverseRealFFTf4xSinCosBRTable(fft_type *,HFFT);
|
void InverseRealFFTf4xSinCosBRTable(fft_type *, FFTParam *);
|
||||||
void ReorderToTime4xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime4xSinCosBRTable(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq4xSinCosBRTable(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq4xSinCosBRTable(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
|
|
||||||
/* Fast Math BR16 versions */
|
/* Fast Math BR16 versions */
|
||||||
void RealFFTf1xFastMathBR16(fft_type *,HFFT);
|
void RealFFTf1xFastMathBR16(fft_type *, FFTParam*);
|
||||||
void InverseRealFFTf1xFastMathBR16(fft_type *,HFFT);
|
void InverseRealFFTf1xFastMathBR16(fft_type *, FFTParam*);
|
||||||
void ReorderToTime1xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime1xFastMathBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq1xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq1xFastMathBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
void RealFFTf4xFastMathBR16(fft_type *,HFFT);
|
void RealFFTf4xFastMathBR16(fft_type *, FFTParam *);
|
||||||
void InverseRealFFTf4xFastMathBR16(fft_type *,HFFT);
|
void InverseRealFFTf4xFastMathBR16(fft_type *, FFTParam *);
|
||||||
void ReorderToTime4xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime4xFastMathBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq4xFastMathBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq4xFastMathBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
|
|
||||||
/* Fast Math BR24 versions */
|
/* Fast Math BR24 versions */
|
||||||
void RealFFTf1xFastMathBR24(fft_type *,HFFT);
|
void RealFFTf1xFastMathBR24(fft_type *, FFTParam*);
|
||||||
void InverseRealFFTf1xFastMathBR24(fft_type *,HFFT);
|
void InverseRealFFTf1xFastMathBR24(fft_type *, FFTParam*);
|
||||||
void ReorderToTime1xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime1xFastMathBR24(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq1xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq1xFastMathBR24(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
void RealFFTf4xFastMathBR24(fft_type *,HFFT);
|
void RealFFTf4xFastMathBR24(fft_type *, FFTParam *);
|
||||||
void InverseRealFFTf4xFastMathBR24(fft_type *,HFFT);
|
void InverseRealFFTf4xFastMathBR24(fft_type *, FFTParam *);
|
||||||
void ReorderToTime4xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime4xFastMathBR24(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq4xFastMathBR24(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq4xFastMathBR24(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
|
|
||||||
/* SinCosTable virtual BR versions */
|
/* SinCosTable virtual BR versions */
|
||||||
void RealFFTf1xSinCosTableVBR16(fft_type *,HFFT);
|
void RealFFTf1xSinCosTableVBR16(fft_type *, FFTParam*);
|
||||||
void InverseRealFFTf1xSinCosTableVBR16(fft_type *,HFFT);
|
void InverseRealFFTf1xSinCosTableVBR16(fft_type *, FFTParam*);
|
||||||
void ReorderToTime1xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime1xSinCosTableVBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq1xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq1xSinCosTableVBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
void RealFFTf4xSinCosTableVBR16(fft_type *,HFFT);
|
void RealFFTf4xSinCosTableVBR16(fft_type *, FFTParam *);
|
||||||
void InverseRealFFTf4xSinCosTableVBR16(fft_type *,HFFT);
|
void InverseRealFFTf4xSinCosTableVBR16(fft_type *, FFTParam *);
|
||||||
void ReorderToTime4xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime4xSinCosTableVBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq4xSinCosTableVBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq4xSinCosTableVBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
|
|
||||||
/* SinCosTable BR16 versions */
|
/* SinCosTable BR16 versions */
|
||||||
void RealFFTf1xSinCosTableBR16(fft_type *,HFFT);
|
void RealFFTf1xSinCosTableBR16(fft_type *, FFTParam*);
|
||||||
void InverseRealFFTf1xSinCosTableBR16(fft_type *,HFFT);
|
void InverseRealFFTf1xSinCosTableBR16(fft_type *, FFTParam*);
|
||||||
void ReorderToTime1xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime1xSinCosTableBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq1xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq1xSinCosTableBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
void RealFFTf4xSinCosTableBR16(fft_type *,HFFT);
|
void RealFFTf4xSinCosTableBR16(fft_type *, FFTParam *);
|
||||||
void InverseRealFFTf4xSinCosTableBR16(fft_type *,HFFT);
|
void InverseRealFFTf4xSinCosTableBR16(fft_type *, FFTParam *);
|
||||||
void ReorderToTime4xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *TimeOut);
|
void ReorderToTime4xSinCosTableBR16(FFTParam *hFFT, fft_type *buffer, fft_type *TimeOut);
|
||||||
void ReorderToFreq4xSinCosTableBR16(HFFT hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
void ReorderToFreq4xSinCosTableBR16(FFTParam *hFFT, fft_type *buffer, fft_type *RealOut, fft_type *ImagOut);
|
||||||
|
|
||||||
void TableUsage(int iMask);
|
void TableUsage(int iMask);
|
||||||
|
|
||||||
|
@ -41,13 +41,11 @@ Resample::Resample(const bool useBestMethod, const double dMinFactor, const doub
|
|||||||
mbWantConstRateResampling = false; // variable rate resampling
|
mbWantConstRateResampling = false; // variable rate resampling
|
||||||
q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR);
|
q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR);
|
||||||
}
|
}
|
||||||
mHandle = (void *)soxr_create(1, dMinFactor, 1, 0, 0, &q_spec, 0);
|
mHandle.reset(soxr_create(1, dMinFactor, 1, 0, 0, &q_spec, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Resample::~Resample()
|
Resample::~Resample()
|
||||||
{
|
{
|
||||||
soxr_delete((soxr_t)mHandle);
|
|
||||||
mHandle = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Resample::GetNumMethods() { return 4; }
|
int Resample::GetNumMethods() { return 4; }
|
||||||
@ -85,16 +83,16 @@ std::pair<size_t, size_t>
|
|||||||
size_t idone, odone;
|
size_t idone, odone;
|
||||||
if (mbWantConstRateResampling)
|
if (mbWantConstRateResampling)
|
||||||
{
|
{
|
||||||
soxr_process((soxr_t)mHandle,
|
soxr_process(mHandle.get(),
|
||||||
inBuffer , (lastFlag? ~inBufferLen : inBufferLen), &idone,
|
inBuffer , (lastFlag? ~inBufferLen : inBufferLen), &idone,
|
||||||
outBuffer, outBufferLen, &odone);
|
outBuffer, outBufferLen, &odone);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
soxr_set_io_ratio((soxr_t)mHandle, 1/factor, 0);
|
soxr_set_io_ratio(mHandle.get(), 1/factor, 0);
|
||||||
|
|
||||||
inBufferLen = lastFlag? ~inBufferLen : inBufferLen;
|
inBufferLen = lastFlag? ~inBufferLen : inBufferLen;
|
||||||
soxr_process((soxr_t)mHandle,
|
soxr_process(mHandle.get(),
|
||||||
inBuffer , inBufferLen , &idone,
|
inBuffer , inBufferLen , &idone,
|
||||||
outBuffer, outBufferLen, &odone);
|
outBuffer, outBufferLen, &odone);
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,19 @@
|
|||||||
|
|
||||||
#include "Audacity.h"
|
#include "Audacity.h"
|
||||||
|
|
||||||
|
#include "MemoryX.h"
|
||||||
#include <wx/intl.h>
|
#include <wx/intl.h>
|
||||||
#include <wx/string.h>
|
#include <wx/string.h>
|
||||||
|
|
||||||
#include "SampleFormat.h"
|
#include "SampleFormat.h"
|
||||||
|
|
||||||
|
struct soxr;
|
||||||
|
extern "C" void soxr_delete(soxr*);
|
||||||
|
struct soxr_deleter {
|
||||||
|
void operator () (soxr *p) const { if (p) soxr_delete(p); }
|
||||||
|
};
|
||||||
|
using soxrHandle = std::unique_ptr<soxr, soxr_deleter>;
|
||||||
|
|
||||||
class Resample final
|
class Resample final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -78,7 +86,7 @@ class Resample final
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
int mMethod; // resampler-specific enum for resampling method
|
int mMethod; // resampler-specific enum for resampling method
|
||||||
void* mHandle; // constant-rate or variable-rate resampler (XOR per instance)
|
soxrHandle mHandle; // constant-rate or variable-rate resampler (XOR per instance)
|
||||||
bool mbWantConstRateResampling;
|
bool mbWantConstRateResampling;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,16 +74,6 @@ const wxChar *GetSampleFormatStr(sampleFormat format)
|
|||||||
return wxT("Unknown format"); // compiler food
|
return wxT("Unknown format"); // compiler food
|
||||||
}
|
}
|
||||||
|
|
||||||
AUDACITY_DLL_API samplePtr NewSamples(size_t count, sampleFormat format)
|
|
||||||
{
|
|
||||||
return (samplePtr)malloc(count * SAMPLE_SIZE(format));
|
|
||||||
}
|
|
||||||
|
|
||||||
AUDACITY_DLL_API void DeleteSamples(samplePtr p)
|
|
||||||
{
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Risky? Assumes 0.0f is represented by 0x00000000;
|
// TODO: Risky? Assumes 0.0f is represented by 0x00000000;
|
||||||
void ClearSamples(samplePtr src, sampleFormat format,
|
void ClearSamples(samplePtr src, sampleFormat format,
|
||||||
size_t start, size_t len)
|
size_t start, size_t len)
|
||||||
|
@ -49,10 +49,6 @@ const wxChar *GetSampleFormatStr(sampleFormat format);
|
|||||||
// Allocating/Freeing Samples
|
// Allocating/Freeing Samples
|
||||||
//
|
//
|
||||||
|
|
||||||
AUDACITY_DLL_API samplePtr NewSamples(size_t count, sampleFormat format);
|
|
||||||
AUDACITY_DLL_API void DeleteSamples(samplePtr p);
|
|
||||||
|
|
||||||
// RAII version of above
|
|
||||||
class SampleBuffer {
|
class SampleBuffer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -60,7 +56,7 @@ public:
|
|||||||
: mPtr(0)
|
: mPtr(0)
|
||||||
{}
|
{}
|
||||||
SampleBuffer(size_t count, sampleFormat format)
|
SampleBuffer(size_t count, sampleFormat format)
|
||||||
: mPtr(NewSamples(count, format))
|
: mPtr((samplePtr)malloc(count * SAMPLE_SIZE(format)))
|
||||||
{}
|
{}
|
||||||
~SampleBuffer()
|
~SampleBuffer()
|
||||||
{
|
{
|
||||||
@ -71,14 +67,14 @@ public:
|
|||||||
SampleBuffer &Allocate(size_t count, sampleFormat format)
|
SampleBuffer &Allocate(size_t count, sampleFormat format)
|
||||||
{
|
{
|
||||||
Free();
|
Free();
|
||||||
mPtr = NewSamples(count, format);
|
mPtr = (samplePtr)malloc(count * SAMPLE_SIZE(format));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Free()
|
void Free()
|
||||||
{
|
{
|
||||||
DeleteSamples(mPtr);
|
free(mPtr);
|
||||||
mPtr = 0;
|
mPtr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +347,9 @@ wxImage ThemeBase::MaskedImage( char const ** pXpm, char const ** pMask )
|
|||||||
|
|
||||||
// unsigned char *src = Img1.GetData();
|
// unsigned char *src = Img1.GetData();
|
||||||
unsigned char *mk = Img2.GetData();
|
unsigned char *mk = Img2.GetData();
|
||||||
unsigned char *alpha = (unsigned char*)malloc( nBytes );
|
//wxImage::setAlpha requires memory allocated with malloc, not new
|
||||||
|
MallocString<unsigned char> alpha{
|
||||||
|
static_cast<unsigned char*>(malloc( nBytes )) };
|
||||||
|
|
||||||
// Extract alpha channel from second XPM.
|
// Extract alpha channel from second XPM.
|
||||||
for(i=0;i<nBytes;i++)
|
for(i=0;i<nBytes;i++)
|
||||||
@ -356,7 +358,7 @@ wxImage ThemeBase::MaskedImage( char const ** pXpm, char const ** pMask )
|
|||||||
mk+=3;
|
mk+=3;
|
||||||
}
|
}
|
||||||
|
|
||||||
Img1.SetAlpha( alpha);
|
Img1.SetAlpha( alpha.release() );
|
||||||
|
|
||||||
//dmazzoni: the top line does not work on wxGTK
|
//dmazzoni: the top line does not work on wxGTK
|
||||||
//wxBitmap Result( Img1, 32 );
|
//wxBitmap Result( Img1, 32 );
|
||||||
|
@ -273,7 +273,8 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void ComputeSpectrumUsingRealFFTf
|
static void ComputeSpectrumUsingRealFFTf
|
||||||
(float * __restrict buffer, HFFT hFFT, const float * __restrict window, size_t len, float * __restrict out)
|
(float * __restrict buffer, const FFTParam *hFFT,
|
||||||
|
const float * __restrict window, size_t len, float * __restrict out)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
if(len > hFFT->Points * 2)
|
if(len > hFFT->Points * 2)
|
||||||
@ -924,7 +925,7 @@ bool SpecCache::CalculateOneSpectrum
|
|||||||
}
|
}
|
||||||
else if (reassignment) {
|
else if (reassignment) {
|
||||||
static const double epsilon = 1e-16;
|
static const double epsilon = 1e-16;
|
||||||
const HFFT hFFT = settings.hFFT;
|
const auto hFFT = settings.hFFT.get();
|
||||||
|
|
||||||
float *const scratch2 = scratch + fftLen;
|
float *const scratch2 = scratch + fftLen;
|
||||||
std::copy(scratch, scratch2, scratch2);
|
std::copy(scratch, scratch2, scratch2);
|
||||||
@ -1024,7 +1025,7 @@ bool SpecCache::CalculateOneSpectrum
|
|||||||
|
|
||||||
// This function mutates useBuffer
|
// This function mutates useBuffer
|
||||||
ComputeSpectrumUsingRealFFTf
|
ComputeSpectrumUsingRealFFTf
|
||||||
(useBuffer, settings.hFFT, settings.window.get(), fftLen, results);
|
(useBuffer, settings.hFFT.get(), settings.window.get(), fftLen, results);
|
||||||
if (!gainFactors.empty()) {
|
if (!gainFactors.empty()) {
|
||||||
// Apply a frequency-dependant gain factor
|
// Apply a frequency-dependant gain factor
|
||||||
for (size_t ii = 0; ii < nBins; ++ii)
|
for (size_t ii = 0; ii < nBins; ++ii)
|
||||||
@ -1160,7 +1161,7 @@ void SpecCache::Populate
|
|||||||
#endif
|
#endif
|
||||||
for (auto xx = lowerBoundX; xx < upperBoundX; ++xx) {
|
for (auto xx = lowerBoundX; xx < upperBoundX; ++xx) {
|
||||||
float *const results = &freq[nBins * xx];
|
float *const results = &freq[nBins * xx];
|
||||||
const HFFT hFFT = settings.hFFT;
|
const auto hFFT = settings.hFFT.get();
|
||||||
for (size_t ii = 0; ii < nBins; ++ii) {
|
for (size_t ii = 0; ii < nBins; ++ii) {
|
||||||
float &power = results[ii];
|
float &power = results[ii];
|
||||||
if (power <= 0)
|
if (power <= 0)
|
||||||
|
@ -220,7 +220,7 @@ EffectEqualization::EffectEqualization()
|
|||||||
mCurve = NULL;
|
mCurve = NULL;
|
||||||
mPanel = NULL;
|
mPanel = NULL;
|
||||||
|
|
||||||
hFFT = InitializeFFT(windowSize);
|
hFFT = GetFFT(windowSize);
|
||||||
|
|
||||||
SetLinearEffectFlag(true);
|
SetLinearEffectFlag(true);
|
||||||
|
|
||||||
@ -282,9 +282,6 @@ EffectEqualization::EffectEqualization()
|
|||||||
|
|
||||||
EffectEqualization::~EffectEqualization()
|
EffectEqualization::~EffectEqualization()
|
||||||
{
|
{
|
||||||
if(hFFT)
|
|
||||||
EndFFT(hFFT);
|
|
||||||
hFFT = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IdentInterface implementation
|
// IdentInterface implementation
|
||||||
@ -1319,7 +1316,7 @@ void EffectEqualization::Filter(size_t len, float *buffer)
|
|||||||
{
|
{
|
||||||
float re,im;
|
float re,im;
|
||||||
// Apply FFT
|
// Apply FFT
|
||||||
RealFFTf(buffer, hFFT);
|
RealFFTf(buffer, hFFT.get());
|
||||||
//FFT(len, false, inr, NULL, outr, outi);
|
//FFT(len, false, inr, NULL, outr, outi);
|
||||||
|
|
||||||
// Apply filter
|
// Apply filter
|
||||||
@ -1336,8 +1333,8 @@ void EffectEqualization::Filter(size_t len, float *buffer)
|
|||||||
mFFTBuffer[1] = buffer[1] * mFilterFuncR[len/2];
|
mFFTBuffer[1] = buffer[1] * mFilterFuncR[len/2];
|
||||||
|
|
||||||
// Inverse FFT and normalization
|
// Inverse FFT and normalization
|
||||||
InverseRealFFTf(mFFTBuffer.get(), hFFT);
|
InverseRealFFTf(mFFTBuffer.get(), hFFT.get());
|
||||||
ReorderToTime(hFFT, mFFTBuffer.get(), buffer);
|
ReorderToTime(hFFT.get(), mFFTBuffer.get(), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -158,7 +158,7 @@ void * malloc_simd(const size_t size)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_simd(void* mem)
|
void free_simd::operator() (void* mem) const
|
||||||
{
|
{
|
||||||
#if defined WIN32 // WIN32
|
#if defined WIN32 // WIN32
|
||||||
_aligned_free(mem);
|
_aligned_free(mem);
|
||||||
@ -169,7 +169,7 @@ void free_simd(void* mem)
|
|||||||
|
|
||||||
EffectEqualization48x::EffectEqualization48x():
|
EffectEqualization48x::EffectEqualization48x():
|
||||||
mThreadCount(0),mFilterSize(0),mWindowSize(0),mBlockSize(0),mWorkerDataCount(0),mBlocksPerBuffer(20),
|
mThreadCount(0),mFilterSize(0),mWindowSize(0),mBlockSize(0),mWorkerDataCount(0),mBlocksPerBuffer(20),
|
||||||
mScratchBufferSize(0),mSubBufferSize(0),mBigBuffer(NULL),mThreaded(false),
|
mScratchBufferSize(0),mSubBufferSize(0),mThreaded(false),
|
||||||
mBenching(false),mBufferCount(0)
|
mBenching(false),mBufferCount(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ bool EffectEqualization48x::AllocateBuffersWorkers(int nThreads)
|
|||||||
|
|
||||||
mScratchBufferSize=mWindowSize*3*sizeof(float)*mBufferCount; // 3 window size blocks of instruction size
|
mScratchBufferSize=mWindowSize*3*sizeof(float)*mBufferCount; // 3 window size blocks of instruction size
|
||||||
mSubBufferSize=mBlockSize*(mBufferCount*(mBlocksPerBuffer-1)); // we are going to do a full block overlap
|
mSubBufferSize=mBlockSize*(mBufferCount*(mBlocksPerBuffer-1)); // we are going to do a full block overlap
|
||||||
mBigBuffer=(float *)malloc_simd(sizeof(float)*(mSubBufferSize+mFilterSize+mScratchBufferSize)*mWorkerDataCount); // we run over by filtersize
|
mBigBuffer.reset( (float *)malloc_simd(sizeof(float) * (mSubBufferSize + mFilterSize + mScratchBufferSize) * mWorkerDataCount) ); // we run over by filtersize
|
||||||
// fill the bufferInfo
|
// fill the bufferInfo
|
||||||
mBufferInfo.reinit(mWorkerDataCount);
|
mBufferInfo.reinit(mWorkerDataCount);
|
||||||
for(int i=0;i<mWorkerDataCount;i++) {
|
for(int i=0;i<mWorkerDataCount;i++) {
|
||||||
@ -250,8 +250,7 @@ bool EffectEqualization48x::FreeBuffersWorkers()
|
|||||||
mWorkerDataCount=0;
|
mWorkerDataCount=0;
|
||||||
}
|
}
|
||||||
mBufferInfo.reset();
|
mBufferInfo.reset();
|
||||||
free_simd(mBigBuffer);
|
mBigBuffer.reset();
|
||||||
mBigBuffer=NULL;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,8 +671,8 @@ bool EffectEqualization48x::ProcessOne1x(int count, WaveTrack * t,
|
|||||||
output->Append((samplePtr)&mBigBuffer[(bigRun?mBlockSize:0)+(mFilterSize>>1)], floatSample, subBufferSize-((bigRun?mBlockSize:0)+(mFilterSize>>1)));
|
output->Append((samplePtr)&mBigBuffer[(bigRun?mBlockSize:0)+(mFilterSize>>1)], floatSample, subBufferSize-((bigRun?mBlockSize:0)+(mFilterSize>>1)));
|
||||||
}
|
}
|
||||||
if(singleProcessLength && !bBreakLoop) {
|
if(singleProcessLength && !bBreakLoop) {
|
||||||
t->Get((samplePtr)mBigBuffer, floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
ProcessBuffer(mBigBuffer, mBigBuffer, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
ProcessBuffer(mBigBuffer.get(), mBigBuffer.get(), singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
output->Append((samplePtr)&mBigBuffer[bigRuns > 0 ? mBlockSize : 0], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
output->Append((samplePtr)&mBigBuffer[bigRuns > 0 ? mBlockSize : 0], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
}
|
}
|
||||||
output->Flush();
|
output->Flush();
|
||||||
@ -688,7 +687,7 @@ void EffectEqualization48x::Filter1x(size_t len,
|
|||||||
int i;
|
int i;
|
||||||
float real, imag;
|
float real, imag;
|
||||||
// Apply FFT
|
// Apply FFT
|
||||||
RealFFTf1x(buffer, mEffectEqualization->hFFT);
|
RealFFTf1x(buffer, mEffectEqualization->hFFT.get());
|
||||||
|
|
||||||
// Apply filter
|
// Apply filter
|
||||||
// DC component is purely real
|
// DC component is purely real
|
||||||
@ -721,8 +720,8 @@ void EffectEqualization48x::Filter1x(size_t len,
|
|||||||
scratchBuffer[1] = buffer[1] * filterFuncR;
|
scratchBuffer[1] = buffer[1] * filterFuncR;
|
||||||
|
|
||||||
// Inverse FFT and normalization
|
// Inverse FFT and normalization
|
||||||
InverseRealFFTf1x(scratchBuffer, mEffectEqualization->hFFT);
|
InverseRealFFTf1x(scratchBuffer, mEffectEqualization->hFFT.get());
|
||||||
ReorderToTime1x(mEffectEqualization->hFFT, scratchBuffer, buffer);
|
ReorderToTime1x(mEffectEqualization->hFFT.get(), scratchBuffer, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectEqualization48x::ProcessBuffer4x(BufferInfo *bufferInfo)
|
bool EffectEqualization48x::ProcessBuffer4x(BufferInfo *bufferInfo)
|
||||||
@ -853,8 +852,8 @@ bool EffectEqualization48x::ProcessOne4x(int count, WaveTrack * t,
|
|||||||
output->Append((samplePtr)&mBigBuffer[(bigRun?mBlockSize:0)+(mFilterSize>>1)], floatSample, subBufferSize-((bigRun?mBlockSize:0)+(mFilterSize>>1)));
|
output->Append((samplePtr)&mBigBuffer[(bigRun?mBlockSize:0)+(mFilterSize>>1)], floatSample, subBufferSize-((bigRun?mBlockSize:0)+(mFilterSize>>1)));
|
||||||
}
|
}
|
||||||
if(singleProcessLength && !bBreakLoop) {
|
if(singleProcessLength && !bBreakLoop) {
|
||||||
t->Get((samplePtr)mBigBuffer, floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
ProcessBuffer(mBigBuffer, mBigBuffer, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
ProcessBuffer(mBigBuffer.get(), mBigBuffer.get(), singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
output->Append((samplePtr)&mBigBuffer[bigRuns > 0 ? mBlockSize : 0], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
output->Append((samplePtr)&mBigBuffer[bigRuns > 0 ? mBlockSize : 0], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
// output->Append((samplePtr)&mBigBuffer[bigRuns?mBlockSize:0], floatSample, singleProcessLength);
|
// output->Append((samplePtr)&mBigBuffer[bigRuns?mBlockSize:0], floatSample, singleProcessLength);
|
||||||
}
|
}
|
||||||
@ -965,8 +964,8 @@ bool EffectEqualization48x::ProcessOne1x4xThreaded(int count, WaveTrack * t,
|
|||||||
mDataMutex.Unlock(); // Get back in line for data
|
mDataMutex.Unlock(); // Get back in line for data
|
||||||
}
|
}
|
||||||
if(singleProcessLength && !bBreakLoop) {
|
if(singleProcessLength && !bBreakLoop) {
|
||||||
t->Get((samplePtr)mBigBuffer, floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
ProcessBuffer(mBigBuffer, mBigBuffer, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
ProcessBuffer(mBigBuffer.get(), mBigBuffer.get(), singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
output->Append((samplePtr)&mBigBuffer[mBlockSize], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
output->Append((samplePtr)&mBigBuffer[mBlockSize], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
}
|
}
|
||||||
output->Flush();
|
output->Flush();
|
||||||
@ -981,7 +980,7 @@ void EffectEqualization48x::Filter4x(size_t len,
|
|||||||
int i;
|
int i;
|
||||||
__m128 real128, imag128;
|
__m128 real128, imag128;
|
||||||
// Apply FFT
|
// Apply FFT
|
||||||
RealFFTf4x(buffer, mEffectEqualization->hFFT);
|
RealFFTf4x(buffer, mEffectEqualization->hFFT.get());
|
||||||
|
|
||||||
// Apply filter
|
// Apply filter
|
||||||
// DC component is purely real
|
// DC component is purely real
|
||||||
@ -1015,8 +1014,8 @@ void EffectEqualization48x::Filter4x(size_t len,
|
|||||||
localFFTBuffer[1] = _mm_mul_ps(localBuffer[1], filterFuncR);
|
localFFTBuffer[1] = _mm_mul_ps(localBuffer[1], filterFuncR);
|
||||||
|
|
||||||
// Inverse FFT and normalization
|
// Inverse FFT and normalization
|
||||||
InverseRealFFTf4x(scratchBuffer, mEffectEqualization->hFFT);
|
InverseRealFFTf4x(scratchBuffer, mEffectEqualization->hFFT.get());
|
||||||
ReorderToTime4x(mEffectEqualization->hFFT, scratchBuffer, buffer);
|
ReorderToTime4x(mEffectEqualization->hFFT.get(), scratchBuffer, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __AVX_ENABLED
|
#ifdef __AVX_ENABLED
|
||||||
@ -1183,8 +1182,8 @@ bool EffectEqualization48x::ProcessOne8x(int count, WaveTrack * t,
|
|||||||
output->Append((samplePtr)&mBigBuffer[(bigRun?mBlockSize:0)+(mFilterSize>>1)], floatSample, mSubBufferSize-((bigRun?mBlockSize:0)+(mFilterSize>>1)));
|
output->Append((samplePtr)&mBigBuffer[(bigRun?mBlockSize:0)+(mFilterSize>>1)], floatSample, mSubBufferSize-((bigRun?mBlockSize:0)+(mFilterSize>>1)));
|
||||||
}
|
}
|
||||||
if(singleProcessLength && !bBreakLoop) {
|
if(singleProcessLength && !bBreakLoop) {
|
||||||
t->Get((samplePtr)mBigBuffer, floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
ProcessBuffer(mBigBuffer, mBigBuffer, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
ProcessBuffer(mBigBuffer.get(), mBigBuffer.get(), singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
output->Append((samplePtr)&mBigBuffer[mBlockSize], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
output->Append((samplePtr)&mBigBuffer[mBlockSize], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
}
|
}
|
||||||
output->Flush();
|
output->Flush();
|
||||||
@ -1262,8 +1261,8 @@ bool EffectEqualization48x::ProcessOne8xThreaded(int count, WaveTrack * t,
|
|||||||
mDataMutex.Unlock(); // Get back in line for data
|
mDataMutex.Unlock(); // Get back in line for data
|
||||||
}
|
}
|
||||||
if(singleProcessLength && !bBreakLoop) {
|
if(singleProcessLength && !bBreakLoop) {
|
||||||
t->Get((samplePtr)mBigBuffer, floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
ProcessBuffer(mBigBuffer, mBigBuffer, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
ProcessBuffer(mBigBuffer.get(), mBigBuffer.get(), singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
output->Append((samplePtr)&mBigBuffer[mBlockSize], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
output->Append((samplePtr)&mBigBuffer[mBlockSize], floatSample, singleProcessLength+mBlockSize+(mFilterSize>>1));
|
||||||
}
|
}
|
||||||
output->Flush();
|
output->Flush();
|
||||||
|
@ -32,6 +32,11 @@ Intrinsics (SSE/AVX) and Threaded Equalization
|
|||||||
#define MATH_FUNCTION_AVX 16
|
#define MATH_FUNCTION_AVX 16
|
||||||
#define MATH_FUNCTION_SEGMENTED_CODE 32
|
#define MATH_FUNCTION_SEGMENTED_CODE 32
|
||||||
|
|
||||||
|
struct free_simd {
|
||||||
|
void operator () (void*) const;
|
||||||
|
};
|
||||||
|
using simd_floats = std::unique_ptr< float[], free_simd >;
|
||||||
|
|
||||||
// added by Andrew Hallendorff intrinsics processing
|
// added by Andrew Hallendorff intrinsics processing
|
||||||
enum EQBufferStatus
|
enum EQBufferStatus
|
||||||
{
|
{
|
||||||
@ -156,7 +161,7 @@ private:
|
|||||||
size_t mBlocksPerBuffer;
|
size_t mBlocksPerBuffer;
|
||||||
size_t mScratchBufferSize;
|
size_t mScratchBufferSize;
|
||||||
size_t mSubBufferSize;
|
size_t mSubBufferSize;
|
||||||
float *mBigBuffer;
|
simd_floats mBigBuffer;
|
||||||
ArrayOf<BufferInfo> mBufferInfo;
|
ArrayOf<BufferInfo> mBufferInfo;
|
||||||
wxMutex mDataMutex;
|
wxMutex mDataMutex;
|
||||||
ArrayOf<EQWorker> mEQWorkers;
|
ArrayOf<EQWorker> mEQWorkers;
|
||||||
|
@ -640,7 +640,6 @@ bool EffectNoiseReduction::Process()
|
|||||||
|
|
||||||
EffectNoiseReduction::Worker::~Worker()
|
EffectNoiseReduction::Worker::~Worker()
|
||||||
{
|
{
|
||||||
EndFFT(hFFT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectNoiseReduction::Worker::Process
|
bool EffectNoiseReduction::Worker::Process
|
||||||
@ -727,7 +726,7 @@ EffectNoiseReduction::Worker::Worker
|
|||||||
, mSampleRate(sampleRate)
|
, mSampleRate(sampleRate)
|
||||||
|
|
||||||
, mWindowSize(settings.WindowSize())
|
, mWindowSize(settings.WindowSize())
|
||||||
, hFFT(InitializeFFT(mWindowSize))
|
, hFFT(GetFFT(mWindowSize))
|
||||||
, mFFTBuffer(mWindowSize)
|
, mFFTBuffer(mWindowSize)
|
||||||
, mInWaveBuffer(mWindowSize)
|
, mInWaveBuffer(mWindowSize)
|
||||||
, mOutOverlapBuffer(mWindowSize)
|
, mOutOverlapBuffer(mWindowSize)
|
||||||
@ -945,7 +944,7 @@ void EffectNoiseReduction::Worker::FillFirstHistoryWindow()
|
|||||||
mFFTBuffer[ii] = mInWaveBuffer[ii] * mInWindow[ii];
|
mFFTBuffer[ii] = mInWaveBuffer[ii] * mInWindow[ii];
|
||||||
else
|
else
|
||||||
memmove(&mFFTBuffer[0], &mInWaveBuffer[0], mWindowSize * sizeof(float));
|
memmove(&mFFTBuffer[0], &mInWaveBuffer[0], mWindowSize * sizeof(float));
|
||||||
RealFFTf(&mFFTBuffer[0], hFFT);
|
RealFFTf(&mFFTBuffer[0], hFFT.get());
|
||||||
|
|
||||||
Record &record = *mQueue[0];
|
Record &record = *mQueue[0];
|
||||||
|
|
||||||
@ -1243,7 +1242,7 @@ void EffectNoiseReduction::Worker::ReduceNoise
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invert the FFT into the output buffer
|
// Invert the FFT into the output buffer
|
||||||
InverseRealFFTf(&mFFTBuffer[0], hFFT);
|
InverseRealFFTf(&mFFTBuffer[0], hFFT.get());
|
||||||
|
|
||||||
// Overlap-add
|
// Overlap-add
|
||||||
if (mOutWindow.size() > 0) {
|
if (mOutWindow.size() > 0) {
|
||||||
|
@ -288,7 +288,7 @@ void EffectNoiseRemoval::Initialize()
|
|||||||
mImagFFTs.reinit(mHistoryLen, mSpectrumSize);
|
mImagFFTs.reinit(mHistoryLen, mSpectrumSize);
|
||||||
|
|
||||||
// Initialize the FFT
|
// Initialize the FFT
|
||||||
hFFT = InitializeFFT(mWindowSize);
|
hFFT = GetFFT(mWindowSize);
|
||||||
|
|
||||||
mFFTBuffer.reinit(mWindowSize);
|
mFFTBuffer.reinit(mWindowSize);
|
||||||
mInWaveBuffer.reinit(mWindowSize);
|
mInWaveBuffer.reinit(mWindowSize);
|
||||||
@ -307,7 +307,7 @@ void EffectNoiseRemoval::Initialize()
|
|||||||
|
|
||||||
void EffectNoiseRemoval::Cleanup()
|
void EffectNoiseRemoval::Cleanup()
|
||||||
{
|
{
|
||||||
EndFFT(hFFT);
|
hFFT.reset();
|
||||||
|
|
||||||
if (mDoProfile) {
|
if (mDoProfile) {
|
||||||
ApplyFreqSmoothing(mNoiseThreshold.get());
|
ApplyFreqSmoothing(mNoiseThreshold.get());
|
||||||
@ -374,8 +374,8 @@ void EffectNoiseRemoval::FillFirstHistoryWindow()
|
|||||||
{
|
{
|
||||||
for(size_t i = 0; i < mWindowSize; i++)
|
for(size_t i = 0; i < mWindowSize; i++)
|
||||||
mFFTBuffer[i] = mInWaveBuffer[i];
|
mFFTBuffer[i] = mInWaveBuffer[i];
|
||||||
RealFFTf(mFFTBuffer.get(), hFFT);
|
RealFFTf(mFFTBuffer.get(), hFFT.get());
|
||||||
for(size_t i = 1; i < (mSpectrumSize-1); i++) {
|
for(size_t i = 1; i + 1 < mSpectrumSize; i++) {
|
||||||
mRealFFTs[0][i] = mFFTBuffer[hFFT->BitReversed[i] ];
|
mRealFFTs[0][i] = mFFTBuffer[hFFT->BitReversed[i] ];
|
||||||
mImagFFTs[0][i] = mFFTBuffer[hFFT->BitReversed[i]+1];
|
mImagFFTs[0][i] = mFFTBuffer[hFFT->BitReversed[i]+1];
|
||||||
mSpectrums[0][i] = mRealFFTs[0][i]*mRealFFTs[0][i] + mImagFFTs[0][i]*mImagFFTs[0][i];
|
mSpectrums[0][i] = mRealFFTs[0][i]*mRealFFTs[0][i] + mImagFFTs[0][i]*mImagFFTs[0][i];
|
||||||
@ -502,7 +502,7 @@ void EffectNoiseRemoval::RemoveNoise()
|
|||||||
mFFTBuffer[1] = mRealFFTs[out][mSpectrumSize-1] * mGains[out][mSpectrumSize-1];
|
mFFTBuffer[1] = mRealFFTs[out][mSpectrumSize-1] * mGains[out][mSpectrumSize-1];
|
||||||
|
|
||||||
// Invert the FFT into the output buffer
|
// Invert the FFT into the output buffer
|
||||||
InverseRealFFTf(mFFTBuffer.get(), hFFT);
|
InverseRealFFTf(mFFTBuffer.get(), hFFT.get());
|
||||||
|
|
||||||
// Overlap-add
|
// Overlap-add
|
||||||
for(size_t j = 0; j < (mSpectrumSize-1); j++) {
|
for(size_t j = 0; j < (mSpectrumSize-1); j++) {
|
||||||
|
@ -78,8 +78,8 @@ FactoryPresets[] =
|
|||||||
struct Reverb_priv_t
|
struct Reverb_priv_t
|
||||||
{
|
{
|
||||||
reverb_t reverb;
|
reverb_t reverb;
|
||||||
float *dry;
|
float *dry {};
|
||||||
float *wet[2];
|
float *wet[2] { {}, {} };
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -171,7 +171,7 @@ bool EffectReverb::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelName
|
|||||||
mNumChans = 2;
|
mNumChans = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
mP = (Reverb_priv_t *) calloc(sizeof(*mP), mNumChans);
|
mP.reinit(mNumChans, true);
|
||||||
|
|
||||||
for (int i = 0; i < mNumChans; i++)
|
for (int i = 0; i < mNumChans; i++)
|
||||||
{
|
{
|
||||||
@ -194,12 +194,7 @@ bool EffectReverb::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelName
|
|||||||
|
|
||||||
bool EffectReverb::ProcessFinalize()
|
bool EffectReverb::ProcessFinalize()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < mNumChans; i++)
|
mP.reset();
|
||||||
{
|
|
||||||
reverb_delete(&mP[i].reverb);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(mP);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned mNumChans {};
|
unsigned mNumChans {};
|
||||||
Reverb_priv_t *mP;
|
ArrayOf<Reverb_priv_t> mP;
|
||||||
|
|
||||||
Params mParams;
|
Params mParams;
|
||||||
|
|
||||||
|
@ -29,16 +29,15 @@ using std::max;
|
|||||||
#define FIFO_SIZE_T size_t
|
#define FIFO_SIZE_T size_t
|
||||||
#define FIFO_MIN 0x4000
|
#define FIFO_MIN 0x4000
|
||||||
#define fifo_read_ptr(f) fifo_read(f, (FIFO_SIZE_T)0, NULL)
|
#define fifo_read_ptr(f) fifo_read(f, (FIFO_SIZE_T)0, NULL)
|
||||||
#define lsx_zalloc(var, n) var = (float *)calloc(n, sizeof(*var))
|
#define lsx_zalloc(var, n) (var.reinit(n, true), var.get())
|
||||||
#define filter_advance(p) if (--(p)->ptr < (p)->buffer) (p)->ptr += (p)->size
|
#define filter_advance(p) if (--(p)->ptr < (p)->buffer.get()) (p)->ptr += (p)->size
|
||||||
#define filter_delete(p) free((p)->buffer)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char * data;
|
ArrayOf<char> data;
|
||||||
size_t allocation; /* Number of bytes allocated for data. */
|
size_t allocation {}; /* Number of bytes allocated for data. */
|
||||||
size_t item_size; /* Size of each item in data */
|
size_t item_size {}; /* Size of each item in data */
|
||||||
size_t begin; /* Offset of the first byte to read. */
|
size_t begin {}; /* Offset of the first byte to read. */
|
||||||
size_t end; /* 1 + Offset of the last byte byte to read. */
|
size_t end {}; /* 1 + Offset of the last byte byte to read. */
|
||||||
} fifo_t;
|
} fifo_t;
|
||||||
|
|
||||||
static void fifo_clear(fifo_t * f)
|
static void fifo_clear(fifo_t * f)
|
||||||
@ -55,19 +54,19 @@ static void * fifo_reserve(fifo_t * f, FIFO_SIZE_T n)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (f->end + n <= f->allocation) {
|
if (f->end + n <= f->allocation) {
|
||||||
void *p = f->data + f->end;
|
void *p = f->data.get() + f->end;
|
||||||
|
|
||||||
f->end += n;
|
f->end += n;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
if (f->begin > FIFO_MIN) {
|
if (f->begin > FIFO_MIN) {
|
||||||
memmove(f->data, f->data + f->begin, f->end - f->begin);
|
memmove(f->data.get(), f->data.get() + f->begin, f->end - f->begin);
|
||||||
f->end -= f->begin;
|
f->end -= f->begin;
|
||||||
f->begin = 0;
|
f->begin = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
f->allocation += n;
|
f->allocation += n;
|
||||||
f->data = (char *)realloc(f->data, f->allocation);
|
f->data.reinit(f->allocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +80,7 @@ static void * fifo_write(fifo_t * f, FIFO_SIZE_T n, void const * data)
|
|||||||
|
|
||||||
static void * fifo_read(fifo_t * f, FIFO_SIZE_T n, void * data)
|
static void * fifo_read(fifo_t * f, FIFO_SIZE_T n, void * data)
|
||||||
{
|
{
|
||||||
char * ret = f->data + f->begin;
|
char * ret = f->data.get() + f->begin;
|
||||||
n *= f->item_size;
|
n *= f->item_size;
|
||||||
if (n > (FIFO_SIZE_T)(f->end - f->begin))
|
if (n > (FIFO_SIZE_T)(f->end - f->begin))
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -91,22 +90,18 @@ static void * fifo_read(fifo_t * f, FIFO_SIZE_T n, void * data)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fifo_delete(fifo_t * f)
|
|
||||||
{
|
|
||||||
free(f->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fifo_create(fifo_t * f, FIFO_SIZE_T item_size)
|
static void fifo_create(fifo_t * f, FIFO_SIZE_T item_size)
|
||||||
{
|
{
|
||||||
f->item_size = item_size;
|
f->item_size = item_size;
|
||||||
f->allocation = FIFO_MIN;
|
f->allocation = FIFO_MIN;
|
||||||
f->data = (char *)malloc(f->allocation);
|
f->data.reinit(f->allocation);
|
||||||
fifo_clear(f);
|
fifo_clear(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t size;
|
size_t size;
|
||||||
float * buffer, * ptr;
|
ArrayOf<float> buffer;
|
||||||
|
float * ptr;
|
||||||
float store;
|
float store;
|
||||||
} filter_t;
|
} filter_t;
|
||||||
|
|
||||||
@ -199,23 +194,13 @@ static void filter_array_process(filter_array_t * p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filter_array_delete(filter_array_t * p)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < array_length(allpass_lengths); ++i)
|
|
||||||
filter_delete(&p->allpass[i]);
|
|
||||||
for (i = 0; i < array_length(comb_lengths); ++i)
|
|
||||||
filter_delete(&p->comb[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float feedback;
|
float feedback {};
|
||||||
float hf_damping;
|
float hf_damping {};
|
||||||
float gain;
|
float gain {};
|
||||||
fifo_t input_fifo;
|
fifo_t input_fifo {};
|
||||||
filter_array_t chan[2];
|
filter_array_t chan[2];
|
||||||
float * out[2];
|
ArrayOf<float> out[2];
|
||||||
} reverb_t;
|
} reverb_t;
|
||||||
|
|
||||||
static void reverb_create(reverb_t * p, double sample_rate_Hz,
|
static void reverb_create(reverb_t * p, double sample_rate_Hz,
|
||||||
@ -254,17 +239,7 @@ static void reverb_process(reverb_t * p, size_t length)
|
|||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < 2 && p->out[i]; ++i)
|
for (i = 0; i < 2 && p->out[i]; ++i)
|
||||||
filter_array_process(p->chan + i, length, (float *) fifo_read_ptr(&p->input_fifo), p->out[i], &p->feedback, &p->hf_damping, &p->gain);
|
filter_array_process(p->chan + i, length, (float *) fifo_read_ptr(&p->input_fifo), p->out[i].get(), &p->feedback, &p->hf_damping, &p->gain);
|
||||||
fifo_read(&p->input_fifo, length, NULL);
|
fifo_read(&p->input_fifo, length, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reverb_delete(reverb_t * p)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < 2 && p->out[i]; ++i) {
|
|
||||||
free(p->out[i]);
|
|
||||||
filter_array_delete(p->chan + i);
|
|
||||||
}
|
|
||||||
fifo_delete(&p->input_fifo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -33,38 +33,29 @@ public:
|
|||||||
ResampleBuf()
|
ResampleBuf()
|
||||||
{
|
{
|
||||||
processed = 0;
|
processed = 0;
|
||||||
buf = NULL;
|
|
||||||
leftBuffer = NULL;
|
|
||||||
rightBuffer = NULL;
|
|
||||||
|
|
||||||
SBSMSBuf = NULL;
|
|
||||||
outputLeftTrack = NULL;
|
outputLeftTrack = NULL;
|
||||||
outputRightTrack = NULL;
|
outputRightTrack = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
~ResampleBuf()
|
~ResampleBuf()
|
||||||
{
|
{
|
||||||
if(buf) free(buf);
|
|
||||||
if(leftBuffer) free(leftBuffer);
|
|
||||||
if(rightBuffer) free(rightBuffer);
|
|
||||||
if(SBSMSBuf) free(SBSMSBuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bPitch;
|
bool bPitch;
|
||||||
audio *buf;
|
ArrayOf<audio> buf;
|
||||||
double ratio;
|
double ratio;
|
||||||
sampleCount processed;
|
sampleCount processed;
|
||||||
size_t blockSize;
|
size_t blockSize;
|
||||||
long SBSMSBlockSize;
|
long SBSMSBlockSize;
|
||||||
sampleCount offset;
|
sampleCount offset;
|
||||||
sampleCount end;
|
sampleCount end;
|
||||||
float *leftBuffer;
|
ArrayOf<float> leftBuffer;
|
||||||
float *rightBuffer;
|
ArrayOf<float> rightBuffer;
|
||||||
WaveTrack *leftTrack;
|
WaveTrack *leftTrack;
|
||||||
WaveTrack *rightTrack;
|
WaveTrack *rightTrack;
|
||||||
std::unique_ptr<SBSMS> sbsms;
|
std::unique_ptr<SBSMS> sbsms;
|
||||||
std::unique_ptr<SBSMSInterface> iface;
|
std::unique_ptr<SBSMSInterface> iface;
|
||||||
audio *SBSMSBuf;
|
ArrayOf<audio> SBSMSBuf;
|
||||||
|
|
||||||
// Not required by callbacks, but makes for easier cleanup
|
// Not required by callbacks, but makes for easier cleanup
|
||||||
std::unique_ptr<Resampler> resampler;
|
std::unique_ptr<Resampler> resampler;
|
||||||
@ -104,8 +95,8 @@ long resampleCB(void *cb_data, SBSMSFrame *data)
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Get the samples from the tracks and put them in the buffers.
|
// Get the samples from the tracks and put them in the buffers.
|
||||||
r->leftTrack->Get((samplePtr)(r->leftBuffer), floatSample, r->offset, blockSize);
|
r->leftTrack->Get((samplePtr)(r->leftBuffer.get()), floatSample, r->offset, blockSize);
|
||||||
r->rightTrack->Get((samplePtr)(r->rightBuffer), floatSample, r->offset, blockSize);
|
r->rightTrack->Get((samplePtr)(r->rightBuffer.get()), floatSample, r->offset, blockSize);
|
||||||
|
|
||||||
// convert to sbsms audio format
|
// convert to sbsms audio format
|
||||||
for(decltype(blockSize) i=0; i<blockSize; i++) {
|
for(decltype(blockSize) i=0; i<blockSize; i++) {
|
||||||
@ -113,7 +104,7 @@ long resampleCB(void *cb_data, SBSMSFrame *data)
|
|||||||
r->buf[i][1] = r->rightBuffer[i];
|
r->buf[i][1] = r->rightBuffer[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
data->buf = r->buf;
|
data->buf = r->buf.get();
|
||||||
data->size = blockSize;
|
data->size = blockSize;
|
||||||
if(r->bPitch) {
|
if(r->bPitch) {
|
||||||
float t0 = r->processed.as_float() / r->iface->getSamplesToInput();
|
float t0 = r->processed.as_float() / r->iface->getSamplesToInput();
|
||||||
@ -132,8 +123,8 @@ long resampleCB(void *cb_data, SBSMSFrame *data)
|
|||||||
long postResampleCB(void *cb_data, SBSMSFrame *data)
|
long postResampleCB(void *cb_data, SBSMSFrame *data)
|
||||||
{
|
{
|
||||||
ResampleBuf *r = (ResampleBuf*) cb_data;
|
ResampleBuf *r = (ResampleBuf*) cb_data;
|
||||||
auto count = r->sbsms->read(r->iface.get(), r->SBSMSBuf, r->SBSMSBlockSize);
|
auto count = r->sbsms->read(r->iface.get(), r->SBSMSBuf.get(), r->SBSMSBlockSize);
|
||||||
data->buf = r->SBSMSBuf;
|
data->buf = r->SBSMSBuf.get();
|
||||||
data->size = count;
|
data->size = count;
|
||||||
data->ratio0 = 1.0 / r->ratio;
|
data->ratio0 = 1.0 / r->ratio;
|
||||||
data->ratio1 = 1.0 / r->ratio;
|
data->ratio1 = 1.0 / r->ratio;
|
||||||
@ -285,11 +276,11 @@ bool EffectSBSMS::Process()
|
|||||||
ResampleBuf rb;
|
ResampleBuf rb;
|
||||||
auto maxBlockSize = leftTrack->GetMaxBlockSize();
|
auto maxBlockSize = leftTrack->GetMaxBlockSize();
|
||||||
rb.blockSize = maxBlockSize;
|
rb.blockSize = maxBlockSize;
|
||||||
rb.buf = (audio*)calloc(rb.blockSize,sizeof(audio));
|
rb.buf.reinit(rb.blockSize, true);
|
||||||
rb.leftTrack = leftTrack;
|
rb.leftTrack = leftTrack;
|
||||||
rb.rightTrack = rightTrack?rightTrack:leftTrack;
|
rb.rightTrack = rightTrack?rightTrack:leftTrack;
|
||||||
rb.leftBuffer = (float*)calloc(maxBlockSize,sizeof(float));
|
rb.leftBuffer.reinit(maxBlockSize, true);
|
||||||
rb.rightBuffer = (float*)calloc(maxBlockSize,sizeof(float));
|
rb.rightBuffer.reinit(maxBlockSize, true);
|
||||||
|
|
||||||
// Samples in selection
|
// Samples in selection
|
||||||
auto samplesIn = end - start;
|
auto samplesIn = end - start;
|
||||||
@ -325,7 +316,7 @@ bool EffectSBSMS::Process()
|
|||||||
rb.resampler = std::make_unique<Resampler>(resampleCB, &rb, srProcess==srTrack?SlideIdentity:SlideConstant);
|
rb.resampler = std::make_unique<Resampler>(resampleCB, &rb, srProcess==srTrack?SlideIdentity:SlideConstant);
|
||||||
rb.sbsms = std::make_unique<SBSMS>(rightTrack ? 2 : 1, rb.quality.get(), true);
|
rb.sbsms = std::make_unique<SBSMS>(rightTrack ? 2 : 1, rb.quality.get(), true);
|
||||||
rb.SBSMSBlockSize = rb.sbsms->getInputFrameSize();
|
rb.SBSMSBlockSize = rb.sbsms->getInputFrameSize();
|
||||||
rb.SBSMSBuf = (audio*)calloc(rb.SBSMSBlockSize,sizeof(audio));
|
rb.SBSMSBuf.reinit(static_cast<size_t>(rb.SBSMSBlockSize), true);
|
||||||
|
|
||||||
// Note: width of getMaxPresamples() is only long. Widen it
|
// Note: width of getMaxPresamples() is only long. Widen it
|
||||||
decltype(start) processPresamples = rb.quality->getMaxPresamples();
|
decltype(start) processPresamples = rb.quality->getMaxPresamples();
|
||||||
|
@ -277,7 +277,8 @@ void AUControl::CreateCocoa()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioUnitCocoaViewInfo *viewInfo = (AudioUnitCocoaViewInfo *) malloc(dataSize);
|
ArrayOf<char> buffer{ dataSize };
|
||||||
|
auto viewInfo = (AudioUnitCocoaViewInfo *) buffer.get();
|
||||||
if (viewInfo == NULL)
|
if (viewInfo == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -331,8 +332,6 @@ void AUControl::CreateCocoa()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(viewInfo);
|
|
||||||
|
|
||||||
if (!mView)
|
if (!mView)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -474,7 +473,8 @@ void AUControl::CreateCarbon()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioComponentDescription *compList = (AudioComponentDescription *) malloc(dataSize);
|
ArrayOf<char> buffer{ dataSize };
|
||||||
|
auto compList = (AudioComponentDescription *) buffer.get();
|
||||||
if (compList == NULL)
|
if (compList == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -488,11 +488,7 @@ void AUControl::CreateCarbon()
|
|||||||
compList,
|
compList,
|
||||||
&dataSize);
|
&dataSize);
|
||||||
if (result != noErr)
|
if (result != noErr)
|
||||||
{
|
|
||||||
free(compList);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// Get the component
|
// Get the component
|
||||||
AudioComponent comp = AudioComponentFindNext(NULL, &compList[0]);
|
AudioComponent comp = AudioComponentFindNext(NULL, &compList[0]);
|
||||||
@ -500,9 +496,6 @@ void AUControl::CreateCarbon()
|
|||||||
// Try to create an instance
|
// Try to create an instance
|
||||||
result = AudioComponentInstanceNew(comp, &mInstance);
|
result = AudioComponentInstanceNew(comp, &mInstance);
|
||||||
|
|
||||||
// Done with the list
|
|
||||||
free(compList);
|
|
||||||
|
|
||||||
if (result != noErr)
|
if (result != noErr)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -2187,7 +2187,8 @@ void AudioUnitEffect::GetChannelCounts()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AUChannelInfo *info = (AUChannelInfo *) malloc(dataSize);
|
ArrayOf<char> buffer{ dataSize };
|
||||||
|
auto info = (AUChannelInfo *) buffer.get();
|
||||||
|
|
||||||
// Retrieve the channel info
|
// Retrieve the channel info
|
||||||
result = AudioUnitGetProperty(mUnit,
|
result = AudioUnitGetProperty(mUnit,
|
||||||
@ -2202,7 +2203,6 @@ void AudioUnitEffect::GetChannelCounts()
|
|||||||
mAudioIns = 2;
|
mAudioIns = 2;
|
||||||
mAudioOuts = 2;
|
mAudioOuts = 2;
|
||||||
|
|
||||||
free(info);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,11 +316,6 @@ LV2Effect::LV2Effect(const LilvPlugin *plug)
|
|||||||
|
|
||||||
mDialog = NULL;
|
mDialog = NULL;
|
||||||
|
|
||||||
mURIMap = NULL;
|
|
||||||
mNumURIMap = 0;
|
|
||||||
mOptions = NULL;
|
|
||||||
mNumOptions = 0;
|
|
||||||
|
|
||||||
mIdleFeature = NULL;
|
mIdleFeature = NULL;
|
||||||
mOptionsInterface = NULL;
|
mOptionsInterface = NULL;
|
||||||
|
|
||||||
@ -329,19 +324,6 @@ LV2Effect::LV2Effect(const LilvPlugin *plug)
|
|||||||
|
|
||||||
LV2Effect::~LV2Effect()
|
LV2Effect::~LV2Effect()
|
||||||
{
|
{
|
||||||
if (mURIMap)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < mNumURIMap; i++)
|
|
||||||
{
|
|
||||||
free(mURIMap[i]);
|
|
||||||
}
|
|
||||||
free(mURIMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mOptions)
|
|
||||||
{
|
|
||||||
free(mOptions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -675,7 +657,7 @@ bool LV2Effect::SetHost(EffectHostInterface *host)
|
|||||||
AddFeature(LV2_UI_PREFIX "makeResident", NULL);
|
AddFeature(LV2_UI_PREFIX "makeResident", NULL);
|
||||||
AddFeature(LV2_UI__noUserResize, NULL);
|
AddFeature(LV2_UI__noUserResize, NULL);
|
||||||
AddFeature(LV2_BUF_SIZE__boundedBlockLength, NULL);
|
AddFeature(LV2_BUF_SIZE__boundedBlockLength, NULL);
|
||||||
AddFeature(LV2_OPTIONS__options, mOptions);
|
AddFeature(LV2_OPTIONS__options, mOptions.data());
|
||||||
AddFeature(LV2_URI_MAP_URI, &mUriMapFeature);
|
AddFeature(LV2_URI_MAP_URI, &mUriMapFeature);
|
||||||
AddFeature(LV2_URID__map, &mURIDMapFeature);
|
AddFeature(LV2_URID__map, &mURIDMapFeature);
|
||||||
AddFeature(LV2_URID__unmap, &mURIDUnmapFeature);
|
AddFeature(LV2_URID__unmap, &mURIDUnmapFeature);
|
||||||
@ -1302,10 +1284,9 @@ bool LV2Effect::SaveParameters(const wxString & group)
|
|||||||
|
|
||||||
size_t LV2Effect::AddOption(const char *key, uint32_t size, const char *type, void *value)
|
size_t LV2Effect::AddOption(const char *key, uint32_t size, const char *type, void *value)
|
||||||
{
|
{
|
||||||
int ndx = mNumOptions;
|
int ndx = mOptions.size();
|
||||||
|
|
||||||
mNumOptions += 1;
|
mOptions.resize(1 + mOptions.size());
|
||||||
mOptions = (LV2_Options_Option *) realloc(mOptions, mNumOptions * sizeof(LV2_Options_Option));
|
|
||||||
memset(&mOptions[ndx], 0, sizeof(mOptions[ndx]));
|
memset(&mOptions[ndx], 0, sizeof(mOptions[ndx]));
|
||||||
|
|
||||||
if (key != NULL)
|
if (key != NULL)
|
||||||
@ -1323,26 +1304,24 @@ size_t LV2Effect::AddOption(const char *key, uint32_t size, const char *type, vo
|
|||||||
|
|
||||||
LV2_Feature *LV2Effect::AddFeature(const char *uri, void *data)
|
LV2_Feature *LV2Effect::AddFeature(const char *uri, void *data)
|
||||||
{
|
{
|
||||||
mFeatures.resize(mFeatures.size() + 1);
|
size_t ndx = mFeatures.size();
|
||||||
|
mFeatures.resize(1 + mFeatures.size());
|
||||||
auto &pFeature = mFeatures.back();
|
|
||||||
|
|
||||||
if (uri != NULL)
|
if (uri != NULL)
|
||||||
{
|
{
|
||||||
pFeature = make_movable<LV2_Feature>();
|
mFeatures[ndx].reset( safenew LV2_Feature );
|
||||||
pFeature->URI = uri;
|
mFeatures[ndx]->URI = uri;
|
||||||
pFeature->data = data;
|
mFeatures[ndx]->data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
mFeaturePtrs.push_back(pFeature.get());
|
return mFeatures[ndx].get();
|
||||||
return pFeature.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LilvInstance *LV2Effect::InitInstance(float sampleRate)
|
LilvInstance *LV2Effect::InitInstance(float sampleRate)
|
||||||
{
|
{
|
||||||
LilvInstance *handle = lilv_plugin_instantiate(mPlug,
|
LilvInstance *handle = lilv_plugin_instantiate(
|
||||||
sampleRate,
|
mPlug, sampleRate,
|
||||||
mFeaturePtrs.data());
|
reinterpret_cast<const LV2_Feature *const *>(mFeatures.data()));
|
||||||
if (!handle)
|
if (!handle)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1478,7 +1457,7 @@ bool LV2Effect::BuildFancy()
|
|||||||
lilv_node_as_uri(uiType),
|
lilv_node_as_uri(uiType),
|
||||||
lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(ui))),
|
lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(ui))),
|
||||||
lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(ui))),
|
lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(ui))),
|
||||||
mFeaturePtrs.data());
|
reinterpret_cast<const LV2_Feature *const *>(mFeatures.data()));
|
||||||
|
|
||||||
lilv_uis_free(uis);
|
lilv_uis_free(uis);
|
||||||
|
|
||||||
@ -2033,19 +2012,19 @@ LV2_URID LV2Effect::urid_map(LV2_URID_Map_Handle handle, const char *uri)
|
|||||||
|
|
||||||
LV2_URID LV2Effect::URID_Map(const char *uri)
|
LV2_URID LV2Effect::URID_Map(const char *uri)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < mNumURIMap; i++)
|
size_t ndx = mURIMap.size();
|
||||||
|
for (int i = 0; i < ndx; i++)
|
||||||
{
|
{
|
||||||
if (strcmp(mURIMap[i], uri) == 0)
|
if (strcmp(mURIMap[i].get(), uri) == 0)
|
||||||
{
|
{
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mNumURIMap += 1;
|
mURIMap.resize(1 + mURIMap.size());
|
||||||
mURIMap = (char **) realloc(mURIMap, mNumURIMap * sizeof(char*));
|
mURIMap[ndx].reset( strdup(uri) );
|
||||||
mURIMap[mNumURIMap - 1] = strdup(uri);
|
|
||||||
|
|
||||||
return mNumURIMap;
|
return ndx + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static callback
|
// static callback
|
||||||
@ -2056,9 +2035,9 @@ const char *LV2Effect::urid_unmap(LV2_URID_Unmap_Handle handle, LV2_URID urid)
|
|||||||
|
|
||||||
const char *LV2Effect::URID_Unmap(LV2_URID urid)
|
const char *LV2Effect::URID_Unmap(LV2_URID urid)
|
||||||
{
|
{
|
||||||
if (urid > 0 && urid <= (LV2_URID) mNumURIMap)
|
if (urid > 0 && urid <= (LV2_URID) mURIMap.size())
|
||||||
{
|
{
|
||||||
return mURIMap[urid - 1];
|
return mURIMap[urid - 1].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#include "../../MemoryX.h"
|
#include "../../MemoryX.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <wx/checkbox.h>
|
#include <wx/checkbox.h>
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
#include <wx/dynarray.h>
|
#include <wx/dynarray.h>
|
||||||
@ -289,8 +288,7 @@ private:
|
|||||||
|
|
||||||
bool mUseGUI;
|
bool mUseGUI;
|
||||||
|
|
||||||
char **mURIMap;
|
std::vector< movable_ptr_with_deleter<char, freer> > mURIMap;
|
||||||
int mNumURIMap;
|
|
||||||
|
|
||||||
LV2_URI_Map_Feature mUriMapFeature;
|
LV2_URI_Map_Feature mUriMapFeature;
|
||||||
LV2_URID_Map mURIDMapFeature;
|
LV2_URID_Map mURIDMapFeature;
|
||||||
@ -302,11 +300,9 @@ private:
|
|||||||
size_t mSampleRateOption;
|
size_t mSampleRateOption;
|
||||||
|
|
||||||
LV2_Options_Interface *mOptionsInterface;
|
LV2_Options_Interface *mOptionsInterface;
|
||||||
LV2_Options_Option *mOptions;
|
std::vector<LV2_Options_Option> mOptions;
|
||||||
int mNumOptions;
|
|
||||||
|
|
||||||
std::vector<movable_ptr<LV2_Feature>> mFeatures;
|
std::vector<movable_ptr<LV2_Feature>> mFeatures;
|
||||||
std::vector<LV2_Feature*> mFeaturePtrs;
|
|
||||||
|
|
||||||
LV2_Feature *mInstanceAccessFeature;
|
LV2_Feature *mInstanceAccessFeature;
|
||||||
LV2_Feature *mParentFeature;
|
LV2_Feature *mParentFeature;
|
||||||
|
@ -240,7 +240,7 @@ wxWindow *ExportPlugin::OptionsCreate(wxWindow *parent, int WXUNUSED(format))
|
|||||||
std::unique_ptr<Mixer> ExportPlugin::CreateMixer(const WaveTrackConstArray &inputTracks,
|
std::unique_ptr<Mixer> ExportPlugin::CreateMixer(const WaveTrackConstArray &inputTracks,
|
||||||
const TimeTrack *timeTrack,
|
const TimeTrack *timeTrack,
|
||||||
double startTime, double stopTime,
|
double startTime, double stopTime,
|
||||||
unsigned numOutChannels, int outBufferSize, bool outInterleaved,
|
unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
|
||||||
double outRate, sampleFormat outFormat,
|
double outRate, sampleFormat outFormat,
|
||||||
bool highQuality, MixerSpec *mixerSpec)
|
bool highQuality, MixerSpec *mixerSpec)
|
||||||
{
|
{
|
||||||
|
@ -123,7 +123,7 @@ protected:
|
|||||||
std::unique_ptr<Mixer> CreateMixer(const WaveTrackConstArray &inputTracks,
|
std::unique_ptr<Mixer> CreateMixer(const WaveTrackConstArray &inputTracks,
|
||||||
const TimeTrack *timeTrack,
|
const TimeTrack *timeTrack,
|
||||||
double startTime, double stopTime,
|
double startTime, double stopTime,
|
||||||
unsigned numOutChannels, int outBufferSize, bool outInterleaved,
|
unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
|
||||||
double outRate, sampleFormat outFormat,
|
double outRate, sampleFormat outFormat,
|
||||||
bool highQuality = true, MixerSpec *mixerSpec = NULL);
|
bool highQuality = true, MixerSpec *mixerSpec = NULL);
|
||||||
|
|
||||||
|
@ -857,7 +857,7 @@ ProgressResult ExportFFmpeg::Export(AudacityProject *project,
|
|||||||
if (!ret)
|
if (!ret)
|
||||||
return ProgressResult::Cancelled;
|
return ProgressResult::Cancelled;
|
||||||
|
|
||||||
int pcmBufferSize = 1024;
|
size_t pcmBufferSize = 1024;
|
||||||
const WaveTrackConstArray waveTracks =
|
const WaveTrackConstArray waveTracks =
|
||||||
tracks->GetWaveTrackConstArray(selectionOnly, false);
|
tracks->GetWaveTrackConstArray(selectionOnly, false);
|
||||||
auto mixer = CreateMixer(waveTracks,
|
auto mixer = CreateMixer(waveTracks,
|
||||||
|
@ -173,6 +173,14 @@ static struct
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct FLAC__StreamMetadataDeleter {
|
||||||
|
void operator () (FLAC__StreamMetadata *p) const
|
||||||
|
{ if (p) ::FLAC__metadata_object_delete(p); }
|
||||||
|
};
|
||||||
|
using FLAC__StreamMetadataHandle = std::unique_ptr<
|
||||||
|
FLAC__StreamMetadata, FLAC__StreamMetadataDeleter
|
||||||
|
>;
|
||||||
|
|
||||||
class ExportFLAC final : public ExportPlugin
|
class ExportFLAC final : public ExportPlugin
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -196,7 +204,7 @@ private:
|
|||||||
|
|
||||||
bool GetMetadata(AudacityProject *project, const Tags *tags);
|
bool GetMetadata(AudacityProject *project, const Tags *tags);
|
||||||
|
|
||||||
FLAC__StreamMetadata *mMetadata;
|
FLAC__StreamMetadataHandle mMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -248,7 +256,10 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mMetadata) {
|
if (mMetadata) {
|
||||||
encoder.set_metadata(&mMetadata, 1);
|
// set_metadata expects an array of pointers to metadata and a size.
|
||||||
|
// The size is 1.
|
||||||
|
FLAC__StreamMetadata *p = mMetadata.get();
|
||||||
|
encoder.set_metadata(&p, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleFormat format;
|
sampleFormat format;
|
||||||
@ -299,9 +310,7 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mMetadata) {
|
mMetadata.reset();
|
||||||
::FLAC__metadata_object_delete(mMetadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
const WaveTrackConstArray waveTracks =
|
const WaveTrackConstArray waveTracks =
|
||||||
tracks->GetWaveTrackConstArray(selectionOnly, false);
|
tracks->GetWaveTrackConstArray(selectionOnly, false);
|
||||||
@ -367,7 +376,7 @@ bool ExportFLAC::GetMetadata(AudacityProject *project, const Tags *tags)
|
|||||||
if (tags == NULL)
|
if (tags == NULL)
|
||||||
tags = project->GetTags();
|
tags = project->GetTags();
|
||||||
|
|
||||||
mMetadata = ::FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
mMetadata.reset(::FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT));
|
||||||
|
|
||||||
wxString n;
|
wxString n;
|
||||||
for (const auto &pair : tags->GetRange()) {
|
for (const auto &pair : tags->GetRange()) {
|
||||||
@ -378,7 +387,7 @@ bool ExportFLAC::GetMetadata(AudacityProject *project, const Tags *tags)
|
|||||||
}
|
}
|
||||||
FLAC::Metadata::VorbisComment::Entry entry(n.mb_str(wxConvUTF8),
|
FLAC::Metadata::VorbisComment::Entry entry(n.mb_str(wxConvUTF8),
|
||||||
v.mb_str(wxConvUTF8));
|
v.mb_str(wxConvUTF8));
|
||||||
::FLAC__metadata_object_vorbiscomment_append_comment(mMetadata,
|
::FLAC__metadata_object_vorbiscomment_append_comment(mMetadata.get(),
|
||||||
entry.get_entry(),
|
entry.get_entry(),
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, const Tags *tags);
|
int AddTags(AudacityProject *project, ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
|
||||||
#ifdef USE_LIBID3TAG
|
#ifdef USE_LIBID3TAG
|
||||||
void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
|
void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
|
||||||
#endif
|
#endif
|
||||||
@ -242,15 +242,15 @@ ProgressResult ExportMP2::Export(AudacityProject *project,
|
|||||||
return ProgressResult::Cancelled;
|
return ProgressResult::Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *id3buffer = NULL;
|
ArrayOf<char> id3buffer;
|
||||||
int id3len;
|
int id3len;
|
||||||
bool endOfFile;
|
bool endOfFile;
|
||||||
id3len = AddTags(project, &id3buffer, &endOfFile, metadata);
|
id3len = AddTags(project, id3buffer, &endOfFile, metadata);
|
||||||
if (id3len && !endOfFile)
|
if (id3len && !endOfFile)
|
||||||
outFile.Write(id3buffer, id3len);
|
outFile.Write(id3buffer.get(), id3len);
|
||||||
|
|
||||||
// Values taken from the twolame simple encoder sample
|
// Values taken from the twolame simple encoder sample
|
||||||
const int pcmBufferSize = 9216 / 2; // number of samples
|
const size_t pcmBufferSize = 9216 / 2; // number of samples
|
||||||
const size_t mp2BufferSize = 16384u; // bytes
|
const size_t mp2BufferSize = 16384u; // bytes
|
||||||
|
|
||||||
// We allocate a buffer which is twice as big as the
|
// We allocate a buffer which is twice as big as the
|
||||||
@ -307,11 +307,7 @@ ProgressResult ExportMP2::Export(AudacityProject *project,
|
|||||||
/* Write ID3 tag if it was supposed to be at the end of the file */
|
/* Write ID3 tag if it was supposed to be at the end of the file */
|
||||||
|
|
||||||
if (id3len && endOfFile)
|
if (id3len && endOfFile)
|
||||||
outFile.Write(id3buffer, id3len);
|
outFile.Write(id3buffer.get(), id3len);
|
||||||
|
|
||||||
if (id3buffer) {
|
|
||||||
free(id3buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close file */
|
/* Close file */
|
||||||
|
|
||||||
@ -326,11 +322,16 @@ wxWindow *ExportMP2::OptionsCreate(wxWindow *parent, int format)
|
|||||||
return safenew ExportMP2Options(parent, format);
|
return safenew ExportMP2Options(parent, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct id3_tag_deleter {
|
||||||
|
void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
|
||||||
|
};
|
||||||
|
using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
|
||||||
|
|
||||||
// returns buffer len; caller frees
|
// returns buffer len; caller frees
|
||||||
int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool *endOfFile, const Tags *tags)
|
int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags)
|
||||||
{
|
{
|
||||||
#ifdef USE_LIBID3TAG
|
#ifdef USE_LIBID3TAG
|
||||||
struct id3_tag *tp = id3_tag_new();
|
id3_tag_holder tp { id3_tag_new() };
|
||||||
|
|
||||||
for (const auto &pair : tags->GetRange()) {
|
for (const auto &pair : tags->GetRange()) {
|
||||||
const auto &n = pair.first;
|
const auto &n = pair.first;
|
||||||
@ -349,7 +350,7 @@ int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool
|
|||||||
else if (n.CmpNoCase(TAG_YEAR) == 0) {
|
else if (n.CmpNoCase(TAG_YEAR) == 0) {
|
||||||
// LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
|
// LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
|
||||||
// so we add old one as well.
|
// so we add old one as well.
|
||||||
AddFrame(tp, n, v, "TYER");
|
AddFrame(tp.get(), n, v, "TYER");
|
||||||
name = ID3_FRAME_YEAR;
|
name = ID3_FRAME_YEAR;
|
||||||
}
|
}
|
||||||
else if (n.CmpNoCase(TAG_GENRE) == 0) {
|
else if (n.CmpNoCase(TAG_GENRE) == 0) {
|
||||||
@ -362,7 +363,7 @@ int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool
|
|||||||
name = ID3_FRAME_TRACK;
|
name = ID3_FRAME_TRACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFrame(tp, n, v, name);
|
AddFrame(tp.get(), n, v, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
|
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
|
||||||
@ -378,11 +379,10 @@ int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool
|
|||||||
|
|
||||||
id3_length_t len;
|
id3_length_t len;
|
||||||
|
|
||||||
len = id3_tag_render(tp, 0);
|
len = id3_tag_render(tp.get(), 0);
|
||||||
*buffer = (char *)malloc(len);
|
buffer.reinit(len);
|
||||||
len = id3_tag_render(tp, (id3_byte_t *)*buffer);
|
len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get());
|
||||||
|
|
||||||
id3_tag_delete(tp);
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
#else //ifdef USE_LIBID3TAG
|
#else //ifdef USE_LIBID3TAG
|
||||||
@ -402,8 +402,8 @@ void ExportMP2::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
|
|||||||
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
|
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
id3_ucs4_t *ucs4 =
|
MallocString<id3_ucs4_t> ucs4 {
|
||||||
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8));
|
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
|
||||||
|
|
||||||
if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
|
if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
|
||||||
// A hack to get around iTunes not recognizing the comment. The
|
// A hack to get around iTunes not recognizing the comment. The
|
||||||
@ -413,22 +413,20 @@ void ExportMP2::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
|
|||||||
// way of clearing the field, so do it directly.
|
// way of clearing the field, so do it directly.
|
||||||
id3_field *f = id3_frame_field(frame, 1);
|
id3_field *f = id3_frame_field(frame, 1);
|
||||||
memset(f->immediate.value, 0, sizeof(f->immediate.value));
|
memset(f->immediate.value, 0, sizeof(f->immediate.value));
|
||||||
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4);
|
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "TXXX") == 0) {
|
else if (strcmp(name, "TXXX") == 0) {
|
||||||
id3_field_setstring(id3_frame_field(frame, 2), ucs4);
|
id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
|
||||||
free(ucs4);
|
|
||||||
|
|
||||||
ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8));
|
ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
|
||||||
|
|
||||||
id3_field_setstring(id3_frame_field(frame, 1), ucs4);
|
id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
id3_field_setstrings(id3_frame_field(frame, 1), 1, &ucs4);
|
auto addr = ucs4.get();
|
||||||
|
id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ucs4);
|
|
||||||
|
|
||||||
id3_tag_attachframe(tp, frame);
|
id3_tag_attachframe(tp, frame);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1617,7 +1617,7 @@ private:
|
|||||||
int FindValue(CHOICES *choices, int cnt, int needle, int def);
|
int FindValue(CHOICES *choices, int cnt, int needle, int def);
|
||||||
wxString FindName(CHOICES *choices, int cnt, int needle);
|
wxString FindName(CHOICES *choices, int cnt, int needle);
|
||||||
int AskResample(int bitrate, int rate, int lowrate, int highrate);
|
int AskResample(int bitrate, int rate, int lowrate, int highrate);
|
||||||
int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, const Tags *tags);
|
int AddTags(AudacityProject *project, ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
|
||||||
#ifdef USE_LIBID3TAG
|
#ifdef USE_LIBID3TAG
|
||||||
void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
|
void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
|
||||||
#endif
|
#endif
|
||||||
@ -1796,12 +1796,12 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
|
|||||||
return ProgressResult::Cancelled;
|
return ProgressResult::Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *id3buffer = NULL;
|
ArrayOf<char> id3buffer;
|
||||||
int id3len;
|
int id3len;
|
||||||
bool endOfFile;
|
bool endOfFile;
|
||||||
id3len = AddTags(project, &id3buffer, &endOfFile, metadata);
|
id3len = AddTags(project, id3buffer, &endOfFile, metadata);
|
||||||
if (id3len && !endOfFile) {
|
if (id3len && !endOfFile) {
|
||||||
outFile.Write(id3buffer, id3len);
|
outFile.Write(id3buffer.get(), id3len);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileOffset pos = outFile.Tell();
|
wxFileOffset pos = outFile.Tell();
|
||||||
@ -1890,11 +1890,7 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
|
|||||||
|
|
||||||
// Write ID3 tag if it was supposed to be at the end of the file
|
// Write ID3 tag if it was supposed to be at the end of the file
|
||||||
if (id3len && endOfFile) {
|
if (id3len && endOfFile) {
|
||||||
outFile.Write(id3buffer, id3len);
|
outFile.Write(id3buffer.get(), id3len);
|
||||||
}
|
|
||||||
|
|
||||||
if (id3buffer) {
|
|
||||||
free(id3buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always write the info (Xing/Lame) tag. Until we stop supporting Lame
|
// Always write the info (Xing/Lame) tag. Until we stop supporting Lame
|
||||||
@ -2008,11 +2004,16 @@ int ExportMP3::AskResample(int bitrate, int rate, int lowrate, int highrate)
|
|||||||
return wxAtoi(choice->GetStringSelection());
|
return wxAtoi(choice->GetStringSelection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct id3_tag_deleter {
|
||||||
|
void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
|
||||||
|
};
|
||||||
|
using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
|
||||||
|
|
||||||
// returns buffer len; caller frees
|
// returns buffer len; caller frees
|
||||||
int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *endOfFile, const Tags *tags)
|
int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags)
|
||||||
{
|
{
|
||||||
#ifdef USE_LIBID3TAG
|
#ifdef USE_LIBID3TAG
|
||||||
struct id3_tag *tp = id3_tag_new();
|
id3_tag_holder tp { id3_tag_new() };
|
||||||
|
|
||||||
for (const auto &pair : tags->GetRange()) {
|
for (const auto &pair : tags->GetRange()) {
|
||||||
const auto &n = pair.first;
|
const auto &n = pair.first;
|
||||||
@ -2031,7 +2032,7 @@ int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *
|
|||||||
else if (n.CmpNoCase(TAG_YEAR) == 0) {
|
else if (n.CmpNoCase(TAG_YEAR) == 0) {
|
||||||
// LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
|
// LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
|
||||||
// so we add old one as well.
|
// so we add old one as well.
|
||||||
AddFrame(tp, n, v, "TYER");
|
AddFrame(tp.get(), n, v, "TYER");
|
||||||
name = ID3_FRAME_YEAR;
|
name = ID3_FRAME_YEAR;
|
||||||
}
|
}
|
||||||
else if (n.CmpNoCase(TAG_GENRE) == 0) {
|
else if (n.CmpNoCase(TAG_GENRE) == 0) {
|
||||||
@ -2044,7 +2045,7 @@ int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *
|
|||||||
name = ID3_FRAME_TRACK;
|
name = ID3_FRAME_TRACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFrame(tp, n, v, name);
|
AddFrame(tp.get(), n, v, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
|
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
|
||||||
@ -2060,11 +2061,9 @@ int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *
|
|||||||
|
|
||||||
id3_length_t len;
|
id3_length_t len;
|
||||||
|
|
||||||
len = id3_tag_render(tp, 0);
|
len = id3_tag_render(tp.get(), 0);
|
||||||
*buffer = (char *)malloc(len);
|
buffer.reinit(len);
|
||||||
len = id3_tag_render(tp, (id3_byte_t *)*buffer);
|
len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get());
|
||||||
|
|
||||||
id3_tag_delete(tp);
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
#else //ifdef USE_LIBID3TAG
|
#else //ifdef USE_LIBID3TAG
|
||||||
@ -2084,8 +2083,8 @@ void ExportMP3::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
|
|||||||
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
|
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
id3_ucs4_t *ucs4 =
|
MallocString<id3_ucs4_t> ucs4{
|
||||||
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8));
|
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
|
||||||
|
|
||||||
if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
|
if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
|
||||||
// A hack to get around iTunes not recognizing the comment. The
|
// A hack to get around iTunes not recognizing the comment. The
|
||||||
@ -2094,27 +2093,25 @@ void ExportMP3::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
|
|||||||
// (which one???) or just clear it. Unfortunately, there's no supported
|
// (which one???) or just clear it. Unfortunately, there's no supported
|
||||||
// way of clearing the field, so do it directly.
|
// way of clearing the field, so do it directly.
|
||||||
struct id3_frame *frame2 = id3_frame_new(name);
|
struct id3_frame *frame2 = id3_frame_new(name);
|
||||||
id3_field_setfullstring(id3_frame_field(frame2, 3), ucs4);
|
id3_field_setfullstring(id3_frame_field(frame2, 3), ucs4.get());
|
||||||
id3_field *f2 = id3_frame_field(frame2, 1);
|
id3_field *f2 = id3_frame_field(frame2, 1);
|
||||||
memset(f2->immediate.value, 0, sizeof(f2->immediate.value));
|
memset(f2->immediate.value, 0, sizeof(f2->immediate.value));
|
||||||
id3_tag_attachframe(tp, frame2);
|
id3_tag_attachframe(tp, frame2);
|
||||||
// Now install a second frame with the standard default language = "XXX"
|
// Now install a second frame with the standard default language = "XXX"
|
||||||
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4);
|
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "TXXX") == 0) {
|
else if (strcmp(name, "TXXX") == 0) {
|
||||||
id3_field_setstring(id3_frame_field(frame, 2), ucs4);
|
id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
|
||||||
free(ucs4);
|
|
||||||
|
|
||||||
ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8));
|
ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
|
||||||
|
|
||||||
id3_field_setstring(id3_frame_field(frame, 1), ucs4);
|
id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
id3_field_setstrings(id3_frame_field(frame, 1), 1, &ucs4);
|
auto addr = ucs4.get();
|
||||||
|
id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ucs4);
|
|
||||||
|
|
||||||
id3_tag_attachframe(tp, frame);
|
id3_tag_attachframe(tp, frame);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -121,7 +121,7 @@ bool ExportOGGOptions::TransferDataFromWindow()
|
|||||||
// ExportOGG
|
// ExportOGG
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
#define SAMPLES_PER_RUN 8192
|
#define SAMPLES_PER_RUN 8192u
|
||||||
|
|
||||||
class ExportOGG final : public ExportPlugin
|
class ExportOGG final : public ExportPlugin
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "../FileFormats.h"
|
#include "../FileFormats.h"
|
||||||
#include "../Internat.h"
|
#include "../Internat.h"
|
||||||
|
#include "../MemoryX.h"
|
||||||
#include "../Mix.h"
|
#include "../Mix.h"
|
||||||
#include "../Prefs.h"
|
#include "../Prefs.h"
|
||||||
#include "../Project.h"
|
#include "../Project.h"
|
||||||
@ -328,7 +329,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
char *AdjustString(const wxString & wxStr, int sf_format);
|
ArrayOf<char> AdjustString(const wxString & wxStr, int sf_format);
|
||||||
bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format);
|
bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format);
|
||||||
void AddID3Chunk(wxString fName, const Tags *tags, int sf_format);
|
void AddID3Chunk(wxString fName, const Tags *tags, int sf_format);
|
||||||
|
|
||||||
@ -472,7 +473,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
|
|||||||
else
|
else
|
||||||
format = int16Sample;
|
format = int16Sample;
|
||||||
|
|
||||||
int maxBlockLen = 44100 * 5;
|
size_t maxBlockLen = 44100 * 5;
|
||||||
|
|
||||||
const WaveTrackConstArray waveTracks =
|
const WaveTrackConstArray waveTracks =
|
||||||
tracks->GetWaveTrackConstArray(selectionOnly, false);
|
tracks->GetWaveTrackConstArray(selectionOnly, false);
|
||||||
@ -538,7 +539,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
|
|||||||
return updateResult;
|
return updateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
|
ArrayOf<char> ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
|
||||||
{
|
{
|
||||||
bool b_aiff = false;
|
bool b_aiff = false;
|
||||||
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
|
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
|
||||||
@ -547,34 +548,26 @@ char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
|
|||||||
// We must convert the string to 7 bit ASCII
|
// We must convert the string to 7 bit ASCII
|
||||||
size_t sz = wxStr.length();
|
size_t sz = wxStr.length();
|
||||||
if(sz == 0)
|
if(sz == 0)
|
||||||
return NULL;
|
return {};
|
||||||
// Size for secure malloc in case of local wide char usage
|
// Size for secure allocation in case of local wide char usage
|
||||||
size_t sr = (sz+4) * 2;
|
size_t sr = (sz+4) * 2;
|
||||||
|
|
||||||
char *pDest = (char *)malloc(sr);
|
ArrayOf<char> pDest{ sr, true };
|
||||||
if (!pDest)
|
if (!pDest)
|
||||||
return NULL;
|
return {};
|
||||||
char *pSrc = (char *)malloc(sr);
|
ArrayOf<char> pSrc{ sr, true };
|
||||||
if (!pSrc)
|
if (!pSrc)
|
||||||
{
|
return {};
|
||||||
free(pDest);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(pDest, 0, sr);
|
|
||||||
memset(pSrc, 0, sr);
|
|
||||||
|
|
||||||
if(wxStr.mb_str(wxConvISO8859_1))
|
if(wxStr.mb_str(wxConvISO8859_1))
|
||||||
strncpy(pSrc, wxStr.mb_str(wxConvISO8859_1), sz);
|
strncpy(pSrc.get(), wxStr.mb_str(wxConvISO8859_1), sz);
|
||||||
else if(wxStr.mb_str())
|
else if(wxStr.mb_str())
|
||||||
strncpy(pSrc, wxStr.mb_str(), sz);
|
strncpy(pSrc.get(), wxStr.mb_str(), sz);
|
||||||
else {
|
else
|
||||||
free(pDest);
|
return {};
|
||||||
free(pSrc);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *pD = pDest;
|
char *pD = pDest.get();
|
||||||
char *pS = pSrc;
|
char *pS = pSrc.get();
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
|
|
||||||
// ISO Latin to 7 bit ascii conversion table (best approximation)
|
// ISO Latin to 7 bit ascii conversion table (best approximation)
|
||||||
@ -622,13 +615,11 @@ char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
|
|||||||
}
|
}
|
||||||
*pD = '\0';
|
*pD = '\0';
|
||||||
|
|
||||||
free(pSrc);
|
|
||||||
|
|
||||||
if(b_aiff) {
|
if(b_aiff) {
|
||||||
int len = (int)strlen(pDest);
|
int len = (int)strlen(pDest.get());
|
||||||
if((len % 2) != 0) {
|
if((len % 2) != 0) {
|
||||||
// In case of an odd length string, add a space char
|
// In case of an odd length string, add a space char
|
||||||
strcat(pDest, " ");
|
strcat(pDest.get(), " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,84 +629,80 @@ char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
|
|||||||
bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, const Tags *tags, int sf_format)
|
bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, const Tags *tags, int sf_format)
|
||||||
{
|
{
|
||||||
if (tags->HasTag(TAG_TITLE)) {
|
if (tags->HasTag(TAG_TITLE)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_TITLE), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_TITLE), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_TITLE, ascii7Str);
|
sf_set_string(sf, SF_STR_TITLE, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags->HasTag(TAG_ALBUM)) {
|
if (tags->HasTag(TAG_ALBUM)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_ALBUM), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_ALBUM), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_ALBUM, ascii7Str);
|
sf_set_string(sf, SF_STR_ALBUM, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags->HasTag(TAG_ARTIST)) {
|
if (tags->HasTag(TAG_ARTIST)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_ARTIST), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_ARTIST), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_ARTIST, ascii7Str);
|
sf_set_string(sf, SF_STR_ARTIST, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags->HasTag(TAG_COMMENTS)) {
|
if (tags->HasTag(TAG_COMMENTS)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_COMMENTS), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_COMMENTS), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_COMMENT, ascii7Str);
|
sf_set_string(sf, SF_STR_COMMENT, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags->HasTag(TAG_YEAR)) {
|
if (tags->HasTag(TAG_YEAR)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_YEAR), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_YEAR), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_DATE, ascii7Str);
|
sf_set_string(sf, SF_STR_DATE, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags->HasTag(TAG_GENRE)) {
|
if (tags->HasTag(TAG_GENRE)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_GENRE), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_GENRE), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_GENRE, ascii7Str);
|
sf_set_string(sf, SF_STR_GENRE, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags->HasTag(TAG_COPYRIGHT)) {
|
if (tags->HasTag(TAG_COPYRIGHT)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_COPYRIGHT), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_COPYRIGHT), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str);
|
sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags->HasTag(TAG_SOFTWARE)) {
|
if (tags->HasTag(TAG_SOFTWARE)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_SOFTWARE), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_SOFTWARE), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str);
|
sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags->HasTag(TAG_TRACK)) {
|
if (tags->HasTag(TAG_TRACK)) {
|
||||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_TRACK), sf_format);
|
auto ascii7Str = AdjustString(tags->GetTag(TAG_TRACK), sf_format);
|
||||||
if (ascii7Str) {
|
if (ascii7Str) {
|
||||||
sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str);
|
sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str.get());
|
||||||
free(ascii7Str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct id3_tag_deleter {
|
||||||
|
void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
|
||||||
|
};
|
||||||
|
using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
|
||||||
|
|
||||||
void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
||||||
{
|
{
|
||||||
#ifdef USE_LIBID3TAG
|
#ifdef USE_LIBID3TAG
|
||||||
struct id3_tag *tp = id3_tag_new();
|
id3_tag_holder tp { id3_tag_new() };
|
||||||
|
|
||||||
for (const auto &pair : tags->GetRange()) {
|
for (const auto &pair : tags->GetRange()) {
|
||||||
const auto &n = pair.first;
|
const auto &n = pair.first;
|
||||||
@ -756,8 +743,8 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
|||||||
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
|
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
id3_ucs4_t *ucs4 =
|
MallocString<id3_ucs4_t> ucs4{
|
||||||
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8));
|
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
|
||||||
|
|
||||||
if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
|
if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
|
||||||
// A hack to get around iTunes not recognizing the comment. The
|
// A hack to get around iTunes not recognizing the comment. The
|
||||||
@ -767,23 +754,21 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
|||||||
// way of clearing the field, so do it directly.
|
// way of clearing the field, so do it directly.
|
||||||
id3_field *f = id3_frame_field(frame, 1);
|
id3_field *f = id3_frame_field(frame, 1);
|
||||||
memset(f->immediate.value, 0, sizeof(f->immediate.value));
|
memset(f->immediate.value, 0, sizeof(f->immediate.value));
|
||||||
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4);
|
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "TXXX") == 0) {
|
else if (strcmp(name, "TXXX") == 0) {
|
||||||
id3_field_setstring(id3_frame_field(frame, 2), ucs4);
|
id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
|
||||||
free(ucs4);
|
|
||||||
|
|
||||||
ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8));
|
ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
|
||||||
|
|
||||||
id3_field_setstring(id3_frame_field(frame, 1), ucs4);
|
id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
id3_field_setstrings(id3_frame_field(frame, 1), 1, &ucs4);
|
auto addr = ucs4.get();
|
||||||
|
id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ucs4);
|
id3_tag_attachframe(tp.get(), frame);
|
||||||
|
|
||||||
id3_tag_attachframe(tp, frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
|
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
|
||||||
@ -797,24 +782,19 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
|||||||
|
|
||||||
id3_length_t len;
|
id3_length_t len;
|
||||||
|
|
||||||
len = id3_tag_render(tp, 0);
|
len = id3_tag_render(tp.get(), 0);
|
||||||
if (len == 0) {
|
if (len == 0)
|
||||||
id3_tag_delete(tp);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if ((len % 2) != 0) len++; // Length must be even.
|
if ((len % 2) != 0) len++; // Length must be even.
|
||||||
id3_byte_t *buffer = (id3_byte_t *)malloc(len);
|
ArrayOf<id3_byte_t> buffer { len, true };
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL)
|
||||||
id3_tag_delete(tp);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
// Zero all locations, for ending odd UTF16 content
|
// Zero all locations, for ending odd UTF16 content
|
||||||
// correctly, i.e., two '\0's at the end.
|
// correctly, i.e., two '\0's at the end.
|
||||||
memset(buffer, 0, len);
|
|
||||||
|
|
||||||
id3_tag_render(tp, buffer);
|
id3_tag_render(tp.get(), buffer.get());
|
||||||
|
|
||||||
id3_tag_delete(tp);
|
|
||||||
|
|
||||||
wxFFile f(fName, wxT("r+b"));
|
wxFFile f(fName, wxT("r+b"));
|
||||||
// FIXME: TRAP_ERR wxFFILE ops in Export PCM ID3 could fail.
|
// FIXME: TRAP_ERR wxFFILE ops in Export PCM ID3 could fail.
|
||||||
@ -831,7 +811,7 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
|||||||
}
|
}
|
||||||
f.Write(&sz, 4);
|
f.Write(&sz, 4);
|
||||||
|
|
||||||
f.Write(buffer, len);
|
f.Write(buffer.get(), len);
|
||||||
|
|
||||||
sz = (wxUint32) f.Tell() - 8;
|
sz = (wxUint32) f.Tell() - 8;
|
||||||
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
|
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
|
||||||
@ -842,8 +822,6 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
|||||||
|
|
||||||
f.Close();
|
f.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -732,13 +732,10 @@ ProgressResult FFmpegImportFileHandle::WriteData(streamContext *sc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the buffer to store audio.
|
// Allocate the buffer to store audio.
|
||||||
int insamples = sc->m_decodedAudioSamplesValidSiz / sc->m_samplesize;
|
auto insamples = sc->m_decodedAudioSamplesValidSiz / sc->m_samplesize;
|
||||||
int nChannels = sc->m_stream->codec->channels < sc->m_initialchannels ? sc->m_stream->codec->channels : sc->m_initialchannels;
|
size_t nChannels = std::min(sc->m_stream->codec->channels, sc->m_initialchannels);
|
||||||
uint8_t **tmp = (uint8_t **) malloc(sizeof(uint8_t *) * nChannels);
|
|
||||||
for (int chn = 0; chn < nChannels; chn++)
|
ArraysOf<uint8_t> tmp{ nChannels, sc->m_osamplesize * (insamples / nChannels) };
|
||||||
{
|
|
||||||
tmp[chn] = (uint8_t *) malloc(sc->m_osamplesize * (insamples / nChannels));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Separate the channels and convert input sample format to 16-bit
|
// Separate the channels and convert input sample format to 16-bit
|
||||||
uint8_t *in = sc->m_decodedAudioSamples.get();
|
uint8_t *in = sc->m_decodedAudioSamples.get();
|
||||||
@ -754,36 +751,31 @@ ProgressResult FFmpegImportFileHandle::WriteData(streamContext *sc)
|
|||||||
{
|
{
|
||||||
case AV_SAMPLE_FMT_U8:
|
case AV_SAMPLE_FMT_U8:
|
||||||
case AV_SAMPLE_FMT_U8P:
|
case AV_SAMPLE_FMT_U8P:
|
||||||
((int16_t *)tmp[chn])[index] = (int16_t) (*(uint8_t *)in - 0x80) << 8;
|
((int16_t *)tmp[chn].get())[index] = (int16_t) (*(uint8_t *)in - 0x80) << 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_S16:
|
case AV_SAMPLE_FMT_S16:
|
||||||
case AV_SAMPLE_FMT_S16P:
|
case AV_SAMPLE_FMT_S16P:
|
||||||
((int16_t *)tmp[chn])[index] = (int16_t) *(int16_t *)in;
|
((int16_t *)tmp[chn].get())[index] = (int16_t) *(int16_t *)in;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_S32:
|
case AV_SAMPLE_FMT_S32:
|
||||||
case AV_SAMPLE_FMT_S32P:
|
case AV_SAMPLE_FMT_S32P:
|
||||||
((float *)tmp[chn])[index] = (float) *(int32_t *)in * (1.0 / (1u << 31));
|
((float *)tmp[chn].get())[index] = (float) *(int32_t *)in * (1.0 / (1u << 31));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_FLT:
|
case AV_SAMPLE_FMT_FLT:
|
||||||
case AV_SAMPLE_FMT_FLTP:
|
case AV_SAMPLE_FMT_FLTP:
|
||||||
((float *)tmp[chn])[index] = (float) *(float *)in;
|
((float *)tmp[chn].get())[index] = (float) *(float *)in;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_DBL:
|
case AV_SAMPLE_FMT_DBL:
|
||||||
case AV_SAMPLE_FMT_DBLP:
|
case AV_SAMPLE_FMT_DBLP:
|
||||||
((float *)tmp[chn])[index] = (float) *(double *)in;
|
((float *)tmp[chn].get())[index] = (float) *(double *)in;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
wxLogError(wxT("Stream %d has unrecognized sample format %d."), streamid, sc->m_samplefmt);
|
wxLogError(wxT("Stream %d has unrecognized sample format %d."), streamid, sc->m_samplefmt);
|
||||||
for (int chn=0; chn < nChannels; chn++)
|
|
||||||
{
|
|
||||||
free(tmp[chn]);
|
|
||||||
}
|
|
||||||
free(tmp);
|
|
||||||
return ProgressResult::Success;
|
return ProgressResult::Success;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -798,12 +790,9 @@ ProgressResult FFmpegImportFileHandle::WriteData(streamContext *sc)
|
|||||||
auto iter2 = iter->begin();
|
auto iter2 = iter->begin();
|
||||||
for (int chn=0; chn < nChannels; ++iter2, ++chn)
|
for (int chn=0; chn < nChannels; ++iter2, ++chn)
|
||||||
{
|
{
|
||||||
iter2->get()->Append((samplePtr)tmp[chn],sc->m_osamplefmt,index);
|
iter2->get()->Append((samplePtr)tmp[chn].get(), sc->m_osamplefmt, index);
|
||||||
free(tmp[chn]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
// Try to update the progress indicator (and see if user wants to cancel)
|
// Try to update the progress indicator (and see if user wants to cancel)
|
||||||
auto updateResult = ProgressResult::Success;
|
auto updateResult = ProgressResult::Success;
|
||||||
int64_t filesize = avio_size(mFormatContext->pb);
|
int64_t filesize = avio_size(mFormatContext->pb);
|
||||||
|
@ -356,9 +356,8 @@ void MP3ImportFileHandle::ImportID3(Tags *tags)
|
|||||||
else if (frame->nfields == 3) {
|
else if (frame->nfields == 3) {
|
||||||
ustr = id3_field_getstring(&frame->fields[1]);
|
ustr = id3_field_getstring(&frame->fields[1]);
|
||||||
if (ustr) {
|
if (ustr) {
|
||||||
char *str = (char *)id3_ucs4_utf8duplicate(ustr);
|
MallocString<> str{ (char *)id3_ucs4_utf8duplicate(ustr) };
|
||||||
n = UTF8CTOWX(str);
|
n = UTF8CTOWX(str.get());
|
||||||
free(str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ustr = id3_field_getstring(&frame->fields[2]);
|
ustr = id3_field_getstring(&frame->fields[2]);
|
||||||
@ -368,9 +367,8 @@ void MP3ImportFileHandle::ImportID3(Tags *tags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ustr) {
|
if (ustr) {
|
||||||
char *str = (char *)id3_ucs4_utf8duplicate(ustr);
|
MallocString<> str{ (char *)id3_ucs4_utf8duplicate(ustr) };
|
||||||
v = UTF8CTOWX(str);
|
v = UTF8CTOWX(str.get());
|
||||||
free(str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!n.IsEmpty() && !v.IsEmpty()) {
|
if (!n.IsEmpty() && !v.IsEmpty()) {
|
||||||
|
@ -324,6 +324,11 @@ How do you want to import the current file(s)?"), oldCopyPref == wxT("copy") ? _
|
|||||||
return oldCopyPref;
|
return oldCopyPref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct id3_tag_deleter {
|
||||||
|
void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
|
||||||
|
};
|
||||||
|
using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
|
||||||
|
|
||||||
ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
|
ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
|
||||||
TrackHolders &outTracks,
|
TrackHolders &outTracks,
|
||||||
Tags *tags)
|
Tags *tags)
|
||||||
@ -584,14 +589,17 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
id3_byte_t *buffer = (id3_byte_t *)malloc(len);
|
|
||||||
if (!buffer) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Read(buffer, len);
|
id3_tag_holder tp;
|
||||||
struct id3_tag *tp = id3_tag_parse(buffer, len);
|
{
|
||||||
free(buffer);
|
ArrayOf<id3_byte_t> buffer{ len };
|
||||||
|
if (!buffer) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Read(buffer.get(), len);
|
||||||
|
tp.reset( id3_tag_parse(buffer.get(), len) );
|
||||||
|
}
|
||||||
|
|
||||||
if (!tp) {
|
if (!tp) {
|
||||||
break;
|
break;
|
||||||
@ -662,9 +670,8 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
|
|||||||
else if (frame->nfields == 3) {
|
else if (frame->nfields == 3) {
|
||||||
ustr = id3_field_getstring(&frame->fields[1]);
|
ustr = id3_field_getstring(&frame->fields[1]);
|
||||||
if (ustr) {
|
if (ustr) {
|
||||||
char *str = (char *)id3_ucs4_utf8duplicate(ustr);
|
MallocString<> str{ (char *)id3_ucs4_utf8duplicate(ustr) };
|
||||||
n = UTF8CTOWX(str);
|
n = UTF8CTOWX(str.get());
|
||||||
free(str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ustr = id3_field_getstring(&frame->fields[2]);
|
ustr = id3_field_getstring(&frame->fields[2]);
|
||||||
@ -674,9 +681,8 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ustr) {
|
if (ustr) {
|
||||||
char *str = (char *)id3_ucs4_utf8duplicate(ustr);
|
MallocString<> str{ (char *)id3_ucs4_utf8duplicate(ustr) };
|
||||||
v = UTF8CTOWX(str);
|
v = UTF8CTOWX(str.get());
|
||||||
free(str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!n.IsEmpty() && !v.IsEmpty()) {
|
if (!n.IsEmpty() && !v.IsEmpty()) {
|
||||||
@ -692,7 +698,6 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
id3_tag_delete(tp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,18 +319,22 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory,
|
|||||||
format = floatSample;
|
format = floatSample;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBufferList *abl = (AudioBufferList *)
|
std::unique_ptr<AudioBufferList, freer> abl
|
||||||
calloc(1, offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * numchan));
|
{ static_cast<AudioBufferList *>
|
||||||
|
(calloc(1, offsetof(AudioBufferList, mBuffers) +
|
||||||
|
(sizeof(AudioBuffer) * numchan))) };
|
||||||
abl->mNumberBuffers = numchan;
|
abl->mNumberBuffers = numchan;
|
||||||
|
|
||||||
TrackHolders channels{ numchan };
|
TrackHolders channels{ numchan };
|
||||||
|
|
||||||
|
ArraysOf<unsigned char> holders{ numchan, sizeof(float) * bufsize };
|
||||||
int c;
|
int c;
|
||||||
for (c = 0; c < numchan; c++) {
|
for (c = 0; c < numchan; c++) {
|
||||||
abl->mBuffers[c].mNumberChannels = 1;
|
abl->mBuffers[c].mNumberChannels = 1;
|
||||||
abl->mBuffers[c].mDataByteSize = sizeof(float) * bufsize;
|
abl->mBuffers[c].mDataByteSize = sizeof(float) * bufsize;
|
||||||
abl->mBuffers[c].mData = malloc(abl->mBuffers[c].mDataByteSize);
|
|
||||||
|
abl->mBuffers[c].mData = holders[c].get();
|
||||||
|
|
||||||
channels[c] = trackFactory->NewWaveTrack(format);
|
channels[c] = trackFactory->NewWaveTrack(format);
|
||||||
channels[c]->SetRate(desc.mSampleRate);
|
channels[c]->SetRate(desc.mSampleRate);
|
||||||
@ -352,7 +356,7 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory,
|
|||||||
|
|
||||||
err = MovieAudioExtractionFillBuffer(maer,
|
err = MovieAudioExtractionFillBuffer(maer,
|
||||||
&numFrames,
|
&numFrames,
|
||||||
abl,
|
abl.get(),
|
||||||
&flags);
|
&flags);
|
||||||
if (err != noErr) {
|
if (err != noErr) {
|
||||||
wxMessageBox(_("Unable to get fill buffer"));
|
wxMessageBox(_("Unable to get fill buffer"));
|
||||||
@ -383,12 +387,7 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory,
|
|||||||
|
|
||||||
outTracks.swap(channels);
|
outTracks.swap(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (c = 0; c < numchan; c++) {
|
|
||||||
free(abl->mBuffers[c].mData);
|
|
||||||
}
|
|
||||||
free(abl);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Extract any metadata
|
// Extract any metadata
|
||||||
//
|
//
|
||||||
@ -463,7 +462,6 @@ void QTImportFileHandle::AddMetadata(Tags *tags)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTPropertyValuePtr outValPtr = nil;
|
|
||||||
QTPropertyValueType outPropType;
|
QTPropertyValueType outPropType;
|
||||||
::ByteCount outPropValueSize;
|
::ByteCount outPropValueSize;
|
||||||
::ByteCount outPropValueSizeUsed = 0;
|
::ByteCount outPropValueSizeUsed = 0;
|
||||||
@ -495,7 +493,7 @@ void QTImportFileHandle::AddMetadata(Tags *tags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Alloc memory for it
|
// Alloc memory for it
|
||||||
outValPtr = malloc(outPropValueSize);
|
ArrayOf<char> outVals{ outPropValueSize };
|
||||||
|
|
||||||
// Retrieve the data
|
// Retrieve the data
|
||||||
err = QTMetaDataGetItemProperty(metaDataRef,
|
err = QTMetaDataGetItemProperty(metaDataRef,
|
||||||
@ -503,24 +501,22 @@ void QTImportFileHandle::AddMetadata(Tags *tags)
|
|||||||
kPropertyClass_MetaDataItem,
|
kPropertyClass_MetaDataItem,
|
||||||
kQTMetaDataItemPropertyID_Value,
|
kQTMetaDataItemPropertyID_Value,
|
||||||
outPropValueSize,
|
outPropValueSize,
|
||||||
outValPtr,
|
outVals.get(),
|
||||||
&outPropValueSizeUsed);
|
&outPropValueSizeUsed);
|
||||||
if (err != noErr) {
|
if (err != noErr)
|
||||||
free(outValPtr);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
wxString v = wxT("");
|
wxString v = wxT("");
|
||||||
|
|
||||||
switch (dataType)
|
switch (dataType)
|
||||||
{
|
{
|
||||||
case kQTMetaDataTypeUTF8:
|
case kQTMetaDataTypeUTF8:
|
||||||
v = wxString((char *)outValPtr, wxConvUTF8);
|
v = wxString(outVals.get(), wxConvUTF8);
|
||||||
break;
|
break;
|
||||||
case kQTMetaDataTypeUTF16BE:
|
case kQTMetaDataTypeUTF16BE:
|
||||||
{
|
{
|
||||||
wxMBConvUTF16BE conv;
|
wxMBConvUTF16BE conv;
|
||||||
v = wxString((char *)outValPtr, conv);
|
v = wxString(outVals.get(), conv);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -528,8 +524,6 @@ void QTImportFileHandle::AddMetadata(Tags *tags)
|
|||||||
if (!v.IsEmpty()) {
|
if (!v.IsEmpty()) {
|
||||||
tags->SetTag(names[i].name, v);
|
tags->SetTag(names[i].name, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(outValPtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are done so release our metadata object
|
// we are done so release our metadata object
|
||||||
|
@ -13,7 +13,9 @@
|
|||||||
|
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "../Audacity.h"
|
||||||
#include "RawAudioGuess.h"
|
#include "RawAudioGuess.h"
|
||||||
|
#include "../MemoryX.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -31,10 +33,9 @@
|
|||||||
static FILE *g_raw_debug_file = NULL;
|
static FILE *g_raw_debug_file = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static float AmpStat(float *data, int len)
|
static float AmpStat(float *data, size_t len)
|
||||||
{
|
{
|
||||||
float sum, sumofsquares, avg, variance, dev;
|
float sum, sumofsquares, avg, variance, dev;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return 1.0;
|
return 1.0;
|
||||||
@ -44,7 +45,7 @@ static float AmpStat(float *data, int len)
|
|||||||
sum = 0.0;
|
sum = 0.0;
|
||||||
sumofsquares = 0.0;
|
sumofsquares = 0.0;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
float x = fabs(data[i]);
|
float x = fabs(data[i]);
|
||||||
sum += x;
|
sum += x;
|
||||||
sumofsquares += x * x;
|
sumofsquares += x * x;
|
||||||
@ -58,31 +59,29 @@ static float AmpStat(float *data, int len)
|
|||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float JumpStat(float *data, int len)
|
static float JumpStat(float *data, size_t len)
|
||||||
{
|
{
|
||||||
float avg;
|
float avg;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Calculate 1.0 - avg jump
|
/* Calculate 1.0 - avg jump
|
||||||
* A score near 1.0 means avg jump is pretty small
|
* A score near 1.0 means avg jump is pretty small
|
||||||
*/
|
*/
|
||||||
|
|
||||||
avg = 0.0;
|
avg = 0.0;
|
||||||
for (i = 0; i < len - 1; i++)
|
for (size_t i = 0; i + 1 < len; i++)
|
||||||
avg += fabs(data[i + 1] - data[i]);
|
avg += fabs(data[i + 1] - data[i]);
|
||||||
avg = 1.0 - (avg / (len - 1) / 2.0);
|
avg = 1.0 - (avg / (len - 1) / 2.0);
|
||||||
|
|
||||||
return avg;
|
return avg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float SecondDStat(float *data, int len)
|
static float SecondDStat(float *data, size_t len)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
float v1=0, v2=0;
|
float v1=0, v2=0;
|
||||||
float a1=0, a2=0;
|
float a1=0, a2=0;
|
||||||
float sum=0;
|
float sum=0;
|
||||||
|
|
||||||
for (i = 1; i < len; i++) {
|
for (size_t i = 1; i < len; i++) {
|
||||||
a2 = a1;
|
a2 = a1;
|
||||||
v2 = v1;
|
v2 = v1;
|
||||||
v1 = data[i]-data[i-1];
|
v1 = data[i]-data[i-1];
|
||||||
@ -93,12 +92,11 @@ static float SecondDStat(float *data, int len)
|
|||||||
return sum/len;
|
return sum/len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float RedundantStereo(float *data, int len)
|
static float RedundantStereo(float *data, size_t len)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int c = 0;
|
int c = 0;
|
||||||
|
|
||||||
for (i = 1; i < len - 1; i += 2)
|
for (size_t i = 1; i + 1 < len; i += 2)
|
||||||
if (fabs(data[i + 1] - data[i]) > 2*fabs(data[i] - data[i - 1]) ||
|
if (fabs(data[i + 1] - data[i]) > 2*fabs(data[i] - data[i - 1]) ||
|
||||||
2*fabs(data[i + 1] - data[i]) < fabs(data[i] - data[i - 1]))
|
2*fabs(data[i + 1] - data[i]) < fabs(data[i] - data[i - 1]))
|
||||||
c++;
|
c++;
|
||||||
@ -109,14 +107,13 @@ static float RedundantStereo(float *data, int len)
|
|||||||
static void ExtractFloats(bool doublePrec,
|
static void ExtractFloats(bool doublePrec,
|
||||||
bool bigendian,
|
bool bigendian,
|
||||||
bool stereo,
|
bool stereo,
|
||||||
int offset,
|
size_t offset,
|
||||||
char *rawData, int dataSize,
|
char *rawData, size_t dataSize,
|
||||||
float *data1, float *data2, int *len1, int *len2)
|
float *data1, float *data2, size_t *len1, size_t *len2)
|
||||||
{
|
{
|
||||||
int rawCount = 0;
|
size_t rawCount = 0;
|
||||||
int dataCount1 = 0;
|
size_t dataCount1 = 0;
|
||||||
int dataCount2 = 0;
|
size_t dataCount2 = 0;
|
||||||
int i;
|
|
||||||
bool swap;
|
bool swap;
|
||||||
|
|
||||||
*len1 = 0;
|
*len1 = 0;
|
||||||
@ -124,7 +121,7 @@ static void ExtractFloats(bool doublePrec,
|
|||||||
|
|
||||||
if (offset) {
|
if (offset) {
|
||||||
rawData += offset;
|
rawData += offset;
|
||||||
dataSize -= offset;
|
dataSize -= std::min(dataSize, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WORDS_BIGENDIAN
|
#if WORDS_BIGENDIAN
|
||||||
@ -142,10 +139,10 @@ static void ExtractFloats(bool doublePrec,
|
|||||||
u.d = 0.0f;
|
u.d = 0.0f;
|
||||||
while (rawCount + 7 < dataSize) {
|
while (rawCount + 7 < dataSize) {
|
||||||
if (swap)
|
if (swap)
|
||||||
for(i=0; i<8; i++)
|
for(size_t i = 0; i < 8; i++)
|
||||||
u.c[7-i] = rawData[rawCount+i];
|
u.c[7-i] = rawData[rawCount+i];
|
||||||
else
|
else
|
||||||
for(i=0; i<8; i++)
|
for(size_t i = 0; i < 8; i++)
|
||||||
u.c[i] = rawData[rawCount+i];
|
u.c[i] = rawData[rawCount+i];
|
||||||
data1[dataCount1] = (float)u.d;
|
data1[dataCount1] = (float)u.d;
|
||||||
dataCount1++;
|
dataCount1++;
|
||||||
@ -161,10 +158,10 @@ static void ExtractFloats(bool doublePrec,
|
|||||||
u.f = 0.0f;
|
u.f = 0.0f;
|
||||||
while (rawCount + 3 < dataSize) {
|
while (rawCount + 3 < dataSize) {
|
||||||
if (swap)
|
if (swap)
|
||||||
for(i=0; i<4; i++)
|
for(size_t i = 0; i < 4; i++)
|
||||||
u.c[3-i] = rawData[rawCount+i];
|
u.c[3-i] = rawData[rawCount+i];
|
||||||
else
|
else
|
||||||
for(i=0; i<4; i++)
|
for(size_t i = 0; i < 4; i++)
|
||||||
u.c[i] = rawData[rawCount+i];
|
u.c[i] = rawData[rawCount+i];
|
||||||
data1[dataCount1] = u.f;
|
data1[dataCount1] = u.f;
|
||||||
dataCount1++;
|
dataCount1++;
|
||||||
@ -174,7 +171,7 @@ static void ExtractFloats(bool doublePrec,
|
|||||||
|
|
||||||
if (stereo) {
|
if (stereo) {
|
||||||
dataCount1 /= 2;
|
dataCount1 /= 2;
|
||||||
for(i=0; i<dataCount1; i++) {
|
for(size_t i = 0; i < dataCount1; i++) {
|
||||||
data2[i] = data1[2*i+1];
|
data2[i] = data1[2*i+1];
|
||||||
data1[i] = data1[2*i];
|
data1[i] = data1[2*i];
|
||||||
}
|
}
|
||||||
@ -191,12 +188,11 @@ static void Extract(bool bits16,
|
|||||||
bool bigendian,
|
bool bigendian,
|
||||||
bool offset,
|
bool offset,
|
||||||
char *rawData, int dataSize,
|
char *rawData, int dataSize,
|
||||||
float *data1, float *data2, int *len1, int *len2)
|
float *data1, float *data2, size_t *len1, size_t *len2)
|
||||||
{
|
{
|
||||||
int rawCount = 0;
|
size_t rawCount = 0;
|
||||||
int dataCount1 = 0;
|
size_t dataCount1 = 0;
|
||||||
int dataCount2 = 0;
|
size_t dataCount2 = 0;
|
||||||
int i;
|
|
||||||
|
|
||||||
*len1 = 0;
|
*len1 = 0;
|
||||||
*len2 = 0;
|
*len2 = 0;
|
||||||
@ -275,7 +271,7 @@ static void Extract(bool bits16,
|
|||||||
|
|
||||||
if (stereo) {
|
if (stereo) {
|
||||||
dataCount1 /= 2;
|
dataCount1 /= 2;
|
||||||
for(i=0; i<dataCount1; i++) {
|
for(size_t i = 0; i < dataCount1; i++) {
|
||||||
data2[i] = data1[2*i+1];
|
data2[i] = data1[2*i+1];
|
||||||
data1[i] = data1[2*i];
|
data1[i] = data1[2*i];
|
||||||
}
|
}
|
||||||
@ -286,33 +282,27 @@ static void Extract(bool bits16,
|
|||||||
*len2 = dataCount2;
|
*len2 = dataCount2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
static int GuessFloatFormats(unsigned numTests, const ArrayOf<char> rawData[], size_t dataSize,
|
||||||
int *out_offset, unsigned *out_channels)
|
size_t *out_offset, unsigned *out_channels)
|
||||||
{
|
{
|
||||||
int format;
|
int format;
|
||||||
int bestOffset = 0;
|
size_t bestOffset = 0;
|
||||||
int bestEndian = 0;
|
int bestEndian = 0;
|
||||||
int bestPrec = 0;
|
int bestPrec = 0;
|
||||||
float bestSmoothAvg = 1000.0;
|
float bestSmoothAvg = 1000.0;
|
||||||
int offset;
|
size_t len1;
|
||||||
int endian;
|
size_t len2;
|
||||||
int prec;
|
|
||||||
float *data1, *data2;
|
|
||||||
int len1;
|
|
||||||
int len2;
|
|
||||||
int test;
|
|
||||||
int i;
|
|
||||||
bool guessStereo = false;
|
bool guessStereo = false;
|
||||||
int stereoVotes = 0;
|
unsigned stereoVotes = 0;
|
||||||
int monoVotes = 0;
|
unsigned monoVotes = 0;
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
FILE *af = g_raw_debug_file;
|
FILE *af = g_raw_debug_file;
|
||||||
fprintf(af, "Testing float\n");
|
fprintf(af, "Testing float\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
data1 = (float *)malloc((dataSize + 4) * sizeof(float));
|
ArrayOf<float> data1{ dataSize + 4 };
|
||||||
data2 = (float *)malloc((dataSize + 4) * sizeof(float));
|
ArrayOf<float> data2{ dataSize + 4 };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First determine if it is possibly in a floating-point
|
* First determine if it is possibly in a floating-point
|
||||||
@ -332,28 +322,29 @@ static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
|||||||
* floats with a 1-byte offset.
|
* floats with a 1-byte offset.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for(prec=0; prec<2; prec++) {
|
for(int prec = 0; prec < 2; prec++) {
|
||||||
for(endian=0; endian<2; endian++) {
|
for(int endian = 0; endian < 2; endian++) {
|
||||||
for(offset=0; offset<(4*prec+4); offset++) {
|
for(size_t offset = 0; offset < (4 * prec + 4); offset++) {
|
||||||
int finiteVotes = 0;
|
unsigned finiteVotes = 0;
|
||||||
int maxminVotes = 0;
|
unsigned maxminVotes = 0;
|
||||||
float smoothAvg = 0;
|
float smoothAvg = 0;
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "prec=%d endian=%d offset=%d\n",
|
fprintf(af, "prec=%d endian=%d offset=%d\n",
|
||||||
prec, endian, offset);
|
prec, endian, (int)offset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(test=0; test<numTests; test++) {
|
for(unsigned test = 0; test < numTests; test++) {
|
||||||
float min, max;
|
float min, max;
|
||||||
|
|
||||||
ExtractFloats(prec?true:false, endian?true:false,
|
ExtractFloats(prec == 1, endian == 1,
|
||||||
true, /* stereo */
|
true, /* stereo */
|
||||||
offset,
|
offset,
|
||||||
rawData[test], dataSize,
|
rawData[test].get(), dataSize,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
|
|
||||||
for(i=0; i<len1; i++)
|
size_t i = 0;
|
||||||
|
for(; i < len1; i++)
|
||||||
if (!(data1[i]>=0 || data1[i]<=0) ||
|
if (!(data1[i]>=0 || data1[i]<=0) ||
|
||||||
!(data2[i]>=0 || data2[i]<=0))
|
!(data2[i]>=0 || data2[i]<=0))
|
||||||
break;
|
break;
|
||||||
@ -362,13 +353,13 @@ static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
|||||||
|
|
||||||
min = data1[0];
|
min = data1[0];
|
||||||
max = data1[0];
|
max = data1[0];
|
||||||
for(i=1; i<len1; i++) {
|
for(i = 1; i < len1; i++) {
|
||||||
if (data1[i]<min)
|
if (data1[i]<min)
|
||||||
min = data1[i];
|
min = data1[i];
|
||||||
if (data1[i]>max)
|
if (data1[i]>max)
|
||||||
max = data1[i];
|
max = data1[i];
|
||||||
}
|
}
|
||||||
for(i=1; i<len2; i++) {
|
for(i = 1; i < len2; i++) {
|
||||||
if (data2[i]<min)
|
if (data2[i]<min)
|
||||||
min = data2[i];
|
min = data2[i];
|
||||||
if (data2[i]>max)
|
if (data2[i]>max)
|
||||||
@ -379,13 +370,13 @@ static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
|||||||
max > 0.01 && max <= 100000)
|
max > 0.01 && max <= 100000)
|
||||||
maxminVotes++;
|
maxminVotes++;
|
||||||
|
|
||||||
smoothAvg += SecondDStat(data1, len1) / max;
|
smoothAvg += SecondDStat(data1.get(), len1) / max;
|
||||||
}
|
}
|
||||||
|
|
||||||
smoothAvg /= numTests;
|
smoothAvg /= numTests;
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "finite: %d/%d maxmin: %d/%d smooth: %f\n",
|
fprintf(af, "finite: %ud/%ud maxmin: %ud/%ud smooth: %f\n",
|
||||||
finiteVotes, numTests, maxminVotes, numTests,
|
finiteVotes, numTests, maxminVotes, numTests,
|
||||||
smoothAvg);
|
smoothAvg);
|
||||||
#endif
|
#endif
|
||||||
@ -410,11 +401,8 @@ static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
|||||||
* main function will try guessing an integer format.
|
* main function will try guessing an integer format.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (bestSmoothAvg >= 1000.0) {
|
if (bestSmoothAvg >= 1000.0)
|
||||||
free(data1);
|
|
||||||
free(data2);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We still have to test for mono/stereo. For an explanation
|
* We still have to test for mono/stereo. For an explanation
|
||||||
@ -422,22 +410,22 @@ static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
|||||||
* tests for 8-bit or 16-bit data.
|
* tests for 8-bit or 16-bit data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
float leftChannel, rightChannel, combinedChannel;
|
float leftChannel, rightChannel, combinedChannel;
|
||||||
|
|
||||||
ExtractFloats(bestPrec?true:false, bestEndian?true:false,
|
ExtractFloats(bestPrec == 1, bestEndian == 1,
|
||||||
true, /* stereo */
|
true, /* stereo */
|
||||||
bestOffset,
|
bestOffset,
|
||||||
rawData[test], dataSize,
|
rawData[test].get(), dataSize,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
leftChannel = JumpStat(data1, len1);
|
leftChannel = JumpStat(data1.get(), len1);
|
||||||
rightChannel = JumpStat(data2, len2);
|
rightChannel = JumpStat(data2.get(), len2);
|
||||||
ExtractFloats(bestPrec?true:false, bestEndian?true:false,
|
ExtractFloats(bestPrec == 1, bestEndian == 1,
|
||||||
false, /* stereo */
|
false, /* stereo */
|
||||||
bestOffset,
|
bestOffset,
|
||||||
rawData[test], dataSize,
|
rawData[test].get(), dataSize,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
combinedChannel = JumpStat(data1, len1);
|
combinedChannel = JumpStat(data1.get(), len1);
|
||||||
|
|
||||||
if (leftChannel > combinedChannel
|
if (leftChannel > combinedChannel
|
||||||
&& rightChannel > combinedChannel)
|
&& rightChannel > combinedChannel)
|
||||||
@ -447,30 +435,27 @@ static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "stereo: %d mono: %d\n", stereoVotes, monoVotes);
|
fprintf(af, "stereo: %ud mono: %ud\n", stereoVotes, monoVotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (stereoVotes > monoVotes)
|
guessStereo = (stereoVotes > monoVotes);
|
||||||
guessStereo = true;
|
|
||||||
else
|
|
||||||
guessStereo = false;
|
|
||||||
|
|
||||||
if (guessStereo == false) {
|
if (!guessStereo) {
|
||||||
|
|
||||||
/* test for repeated-byte, redundant stereo */
|
/* test for repeated-byte, redundant stereo */
|
||||||
|
|
||||||
int rstereoVotes = 0;
|
unsigned rstereoVotes = 0;
|
||||||
int rmonoVotes = 0;
|
unsigned rmonoVotes = 0;
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
float redundant;
|
float redundant;
|
||||||
|
|
||||||
ExtractFloats(bestPrec?true:false, bestEndian?true:false,
|
ExtractFloats(bestPrec == 1, bestEndian == 1,
|
||||||
false, /* stereo */
|
false, /* stereo */
|
||||||
bestOffset,
|
bestOffset,
|
||||||
rawData[test], dataSize,
|
rawData[test].get(), dataSize,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
redundant = RedundantStereo(data1, len1);
|
redundant = RedundantStereo(data1.get(), len1);
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "redundant: %f\n", redundant);
|
fprintf(af, "redundant: %f\n", redundant);
|
||||||
@ -483,11 +468,10 @@ static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "rstereo: %d rmono: %d\n", rstereoVotes, rmonoVotes);
|
fprintf(af, "rstereo: %ud rmono: %ud\n", rstereoVotes, rmonoVotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (rstereoVotes > rmonoVotes)
|
guessStereo = (rstereoVotes > rmonoVotes);
|
||||||
guessStereo = true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,25 +499,22 @@ static int GuessFloatFormats(int numTests, char **rawData, int dataSize,
|
|||||||
else
|
else
|
||||||
format |= SF_ENDIAN_LITTLE;
|
format |= SF_ENDIAN_LITTLE;
|
||||||
|
|
||||||
free(data1);
|
|
||||||
free(data2);
|
|
||||||
|
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Guess8Bit(int numTests, char **rawData, int dataSize, unsigned *out_channels)
|
static int Guess8Bit(unsigned numTests, const ArrayOf<char> rawData[], size_t dataSize, unsigned *out_channels)
|
||||||
{
|
{
|
||||||
bool guessSigned = false;
|
bool guessSigned = false;
|
||||||
bool guessStereo = false;
|
bool guessStereo = false;
|
||||||
int signvotes = 0;
|
unsigned signvotes = 0;
|
||||||
int unsignvotes = 0;
|
unsigned unsignvotes = 0;
|
||||||
int stereoVotes = 0;
|
unsigned stereoVotes = 0;
|
||||||
int monoVotes = 0;
|
unsigned monoVotes = 0;
|
||||||
float *data1 = (float *)malloc((dataSize + 4) * sizeof(float));
|
|
||||||
float *data2 = (float *)malloc((dataSize + 4) * sizeof(float));
|
ArrayOf<float> data1 { dataSize + 4 };
|
||||||
int len1;
|
ArrayOf<float> data2 { dataSize + 4 };
|
||||||
int len2;
|
size_t len1;
|
||||||
int test;
|
size_t len2;
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
FILE *af = g_raw_debug_file;
|
FILE *af = g_raw_debug_file;
|
||||||
@ -551,19 +532,19 @@ static int Guess8Bit(int numTests, char **rawData, int dataSize, unsigned *out_c
|
|||||||
* and returns a value 0-1. 0 is maximally discontinuous, 1 is smooth.
|
* and returns a value 0-1. 0 is maximally discontinuous, 1 is smooth.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
float signL, signR, unsignL, unsignR;
|
float signL, signR, unsignL, unsignR;
|
||||||
|
|
||||||
Extract(0, 1, 1, 0, /* 8-bit signed stereo */
|
Extract(0, 1, 1, 0, /* 8-bit signed stereo */
|
||||||
false, rawData[test], dataSize,
|
false, rawData[test].get(), dataSize,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
signL = JumpStat(data1, len1);
|
signL = JumpStat(data1.get(), len1);
|
||||||
signR = JumpStat(data2, len2);
|
signR = JumpStat(data2.get(), len2);
|
||||||
Extract(0, 0, 1, 0, /* 8-bit unsigned stereo */
|
Extract(0, 0, 1, 0, /* 8-bit unsigned stereo */
|
||||||
false, rawData[test], dataSize,
|
false, rawData[test].get(), dataSize,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
unsignL = JumpStat(data1, len1);
|
unsignL = JumpStat(data1.get(), len1);
|
||||||
unsignR = JumpStat(data2, len2);
|
unsignR = JumpStat(data2.get(), len2);
|
||||||
|
|
||||||
if (signL > unsignL)
|
if (signL > unsignL)
|
||||||
signvotes++;
|
signvotes++;
|
||||||
@ -577,13 +558,10 @@ static int Guess8Bit(int numTests, char **rawData, int dataSize, unsigned *out_c
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "sign: %d unsign: %d\n", signvotes, unsignvotes);
|
fprintf(af, "sign: %ud unsign: %ud\n", signvotes, unsignvotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (signvotes > unsignvotes)
|
guessSigned = (signvotes > unsignvotes);
|
||||||
guessSigned = true;
|
|
||||||
else
|
|
||||||
guessSigned = false;
|
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
if (guessSigned)
|
if (guessSigned)
|
||||||
@ -598,16 +576,16 @@ static int Guess8Bit(int numTests, char **rawData, int dataSize, unsigned *out_c
|
|||||||
* the entire stream interpreted as one channel.
|
* the entire stream interpreted as one channel.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
float leftChannel, rightChannel, combinedChannel;
|
float leftChannel, rightChannel, combinedChannel;
|
||||||
|
|
||||||
Extract(0, guessSigned, 1, 0, 0, rawData[test], dataSize, data1,
|
Extract(0, guessSigned, 1, 0, 0, rawData[test].get(), dataSize, data1.get(),
|
||||||
data2, &len1, &len2);
|
data2.get(), &len1, &len2);
|
||||||
leftChannel = JumpStat(data1, len1);
|
leftChannel = JumpStat(data1.get(), len1);
|
||||||
rightChannel = JumpStat(data2, len2);
|
rightChannel = JumpStat(data2.get(), len2);
|
||||||
Extract(0, guessSigned, 0, 0, 0, rawData[test], dataSize, data1,
|
Extract(0, guessSigned, 0, 0, 0, rawData[test].get(), dataSize, data1.get(),
|
||||||
data2, &len1, &len2);
|
data2.get(), &len1, &len2);
|
||||||
combinedChannel = JumpStat(data1, len1);
|
combinedChannel = JumpStat(data1.get(), len1);
|
||||||
|
|
||||||
if (leftChannel > combinedChannel
|
if (leftChannel > combinedChannel
|
||||||
&& rightChannel > combinedChannel)
|
&& rightChannel > combinedChannel)
|
||||||
@ -617,27 +595,24 @@ static int Guess8Bit(int numTests, char **rawData, int dataSize, unsigned *out_c
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "stereo: %d mono: %d\n", stereoVotes, monoVotes);
|
fprintf(af, "stereo: %ud mono: %ud\n", stereoVotes, monoVotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (stereoVotes > monoVotes)
|
guessStereo = (stereoVotes > monoVotes);
|
||||||
guessStereo = true;
|
|
||||||
else
|
|
||||||
guessStereo = false;
|
|
||||||
|
|
||||||
if (guessStereo == false) {
|
if (!guessStereo) {
|
||||||
|
|
||||||
/* test for repeated-byte, redundant stereo */
|
/* test for repeated-byte, redundant stereo */
|
||||||
|
|
||||||
int rstereoVotes = 0;
|
unsigned rstereoVotes = 0;
|
||||||
int rmonoVotes = 0;
|
unsigned rmonoVotes = 0;
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
float redundant;
|
float redundant;
|
||||||
|
|
||||||
Extract(0, guessSigned, 0, 0, 0, rawData[test], dataSize,
|
Extract(0, guessSigned, 0, 0, 0, rawData[test].get(), dataSize,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
redundant = RedundantStereo(data1, len1);
|
redundant = RedundantStereo(data1.get(), len1);
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "redundant: %f\n", redundant);
|
fprintf(af, "redundant: %f\n", redundant);
|
||||||
@ -650,11 +625,10 @@ static int Guess8Bit(int numTests, char **rawData, int dataSize, unsigned *out_c
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "rstereo: %d rmono: %d\n", rstereoVotes, rmonoVotes);
|
fprintf(af, "rstereo: %ud rmono: %ud\n", rstereoVotes, rmonoVotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (rstereoVotes > rmonoVotes)
|
guessStereo = (rstereoVotes > rmonoVotes);
|
||||||
guessStereo = true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,9 +639,6 @@ static int Guess8Bit(int numTests, char **rawData, int dataSize, unsigned *out_c
|
|||||||
fprintf(af, "mono\n");
|
fprintf(af, "mono\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
free(data1);
|
|
||||||
free(data2);
|
|
||||||
|
|
||||||
if (guessStereo)
|
if (guessStereo)
|
||||||
*out_channels = 2;
|
*out_channels = 2;
|
||||||
else
|
else
|
||||||
@ -679,27 +650,26 @@ static int Guess8Bit(int numTests, char **rawData, int dataSize, unsigned *out_c
|
|||||||
return SF_FORMAT_RAW | SF_FORMAT_PCM_U8;
|
return SF_FORMAT_RAW | SF_FORMAT_PCM_U8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Guess16Bit(int numTests, char **rawData,
|
static int Guess16Bit(unsigned numTests, const ArrayOf<char> rawData[],
|
||||||
int dataSize, bool evenMSB,
|
size_t dataSize, bool evenMSB,
|
||||||
int *out_offset, unsigned *out_channels)
|
size_t *out_offset, unsigned *out_channels)
|
||||||
{
|
{
|
||||||
int format;
|
int format;
|
||||||
bool guessSigned = false;
|
bool guessSigned = false;
|
||||||
bool guessStereo = false;
|
bool guessStereo = false;
|
||||||
bool guessBigEndian = false;
|
bool guessBigEndian = false;
|
||||||
bool guessOffset = false;
|
bool guessOffset = false;
|
||||||
int signvotes = 0;
|
unsigned signvotes = 0;
|
||||||
int unsignvotes = 0;
|
unsigned unsignvotes = 0;
|
||||||
int stereoVotes = 0;
|
unsigned stereoVotes = 0;
|
||||||
int monoVotes = 0;
|
unsigned monoVotes = 0;
|
||||||
int formerVotes = 0;
|
unsigned formerVotes = 0;
|
||||||
int latterVotes = 0;
|
unsigned latterVotes = 0;
|
||||||
char *rawData2 = (char *)malloc(dataSize + 4);
|
ArrayOf<char> rawData2{ dataSize + 4 };
|
||||||
float *data1 = (float *)malloc((dataSize + 4) * sizeof(float));
|
ArrayOf<float> data1{ dataSize + 4 };
|
||||||
float *data2 = (float *)malloc((dataSize + 4) * sizeof(float));
|
ArrayOf<float> data2{ dataSize + 4 };
|
||||||
int len1;
|
size_t len1;
|
||||||
int len2;
|
size_t len2;
|
||||||
int test;
|
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
FILE *af = g_raw_debug_file;
|
FILE *af = g_raw_debug_file;
|
||||||
@ -710,26 +680,25 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
* Do the signed/unsigned test by using only the MSB.
|
* Do the signed/unsigned test by using only the MSB.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
|
|
||||||
float signL, signR, unsignL, unsignR;
|
float signL, signR, unsignL, unsignR;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Extract a NEW array of the MSBs only: */
|
/* Extract a NEW array of the MSBs only: */
|
||||||
|
|
||||||
for (i = 0; i < dataSize / 2; i++)
|
for (size_t i = 0; i < dataSize / 2; i++)
|
||||||
rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
|
rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
|
||||||
|
|
||||||
/* Test signed/unsigned of the MSB */
|
/* Test signed/unsigned of the MSB */
|
||||||
|
|
||||||
Extract(0, 1, 1, 0, /* 8-bit signed stereo */
|
Extract(0, 1, 1, 0, /* 8-bit signed stereo */
|
||||||
0, rawData2, dataSize / 2, data1, data2, &len1, &len2);
|
0, rawData2.get(), dataSize / 2, data1.get(), data2.get(), &len1, &len2);
|
||||||
signL = JumpStat(data1, len1);
|
signL = JumpStat(data1.get(), len1);
|
||||||
signR = JumpStat(data2, len2);
|
signR = JumpStat(data2.get(), len2);
|
||||||
Extract(0, 0, 1, 0, /* 8-bit unsigned stereo */
|
Extract(0, 0, 1, 0, /* 8-bit unsigned stereo */
|
||||||
0, rawData2, dataSize / 2, data1, data2, &len1, &len2);
|
0, rawData2.get(), dataSize / 2, data1.get(), data2.get(), &len1, &len2);
|
||||||
unsignL = JumpStat(data1, len1);
|
unsignL = JumpStat(data1.get(), len1);
|
||||||
unsignR = JumpStat(data2, len2);
|
unsignR = JumpStat(data2.get(), len2);
|
||||||
|
|
||||||
if (signL > unsignL)
|
if (signL > unsignL)
|
||||||
signvotes++;
|
signvotes++;
|
||||||
@ -743,13 +712,10 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "sign: %d unsign: %d\n", signvotes, unsignvotes);
|
fprintf(af, "sign: %ud unsign: %ud\n", signvotes, unsignvotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (signvotes > unsignvotes)
|
guessSigned = (signvotes > unsignvotes);
|
||||||
guessSigned = true;
|
|
||||||
else
|
|
||||||
guessSigned = false;
|
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
if (guessSigned)
|
if (guessSigned)
|
||||||
@ -762,22 +728,21 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
* Test mono/stereo using only the MSB
|
* Test mono/stereo using only the MSB
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
float leftChannel, rightChannel, combinedChannel;
|
float leftChannel, rightChannel, combinedChannel;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Extract a NEW array of the MSBs only: */
|
/* Extract a NEW array of the MSBs only: */
|
||||||
|
|
||||||
for (i = 0; i < dataSize / 2; i++)
|
for (size_t i = 0; i < dataSize / 2; i++)
|
||||||
rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
|
rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
|
||||||
|
|
||||||
Extract(0, guessSigned, 1, 0, 0,
|
Extract(0, guessSigned, 1, 0, 0,
|
||||||
rawData2, dataSize / 2, data1, data2, &len1, &len2);
|
rawData2.get(), dataSize / 2, data1.get(), data2.get(), &len1, &len2);
|
||||||
leftChannel = JumpStat(data1, len1);
|
leftChannel = JumpStat(data1.get(), len1);
|
||||||
rightChannel = JumpStat(data2, len2);
|
rightChannel = JumpStat(data2.get(), len2);
|
||||||
Extract(0, guessSigned, 0, 0, 0,
|
Extract(0, guessSigned, 0, 0, 0,
|
||||||
rawData2, dataSize / 2, data1, data2, &len1, &len2);
|
rawData2.get(), dataSize / 2, data1.get(), data2.get(), &len1, &len2);
|
||||||
combinedChannel = JumpStat(data1, len1);
|
combinedChannel = JumpStat(data1.get(), len1);
|
||||||
|
|
||||||
if (leftChannel > combinedChannel
|
if (leftChannel > combinedChannel
|
||||||
&& rightChannel > combinedChannel)
|
&& rightChannel > combinedChannel)
|
||||||
@ -787,35 +752,31 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "stereoVotes: %d monoVotes: %d\n", stereoVotes, monoVotes);
|
fprintf(af, "stereoVotes: %ud monoVotes: %ud\n", stereoVotes, monoVotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (stereoVotes > monoVotes)
|
guessStereo = (stereoVotes > monoVotes);
|
||||||
guessStereo = true;
|
|
||||||
else
|
|
||||||
guessStereo = false;
|
|
||||||
|
|
||||||
if (guessStereo == false) {
|
if (!guessStereo) {
|
||||||
|
|
||||||
/* Test for repeated-byte, redundant stereo */
|
/* Test for repeated-byte, redundant stereo */
|
||||||
|
|
||||||
int rstereoVotes = 0;
|
unsigned rstereoVotes = 0;
|
||||||
int rmonoVotes = 0;
|
unsigned rmonoVotes = 0;
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
|
|
||||||
float redundant;
|
float redundant;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Extract a NEW array of the MSBs only: */
|
/* Extract a NEW array of the MSBs only: */
|
||||||
|
|
||||||
for (i = 0; i < dataSize / 2; i++)
|
for (size_t i = 0; i < dataSize / 2; i++)
|
||||||
rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
|
rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
|
||||||
|
|
||||||
Extract(0, guessSigned, 0, 0, 0, rawData2, dataSize / 2,
|
Extract(0, guessSigned, 0, 0, 0, rawData2.get(), dataSize / 2,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
|
|
||||||
redundant = RedundantStereo(data1, len1);
|
redundant = RedundantStereo(data1.get(), len1);
|
||||||
|
|
||||||
if (redundant > 0.8)
|
if (redundant > 0.8)
|
||||||
rstereoVotes++;
|
rstereoVotes++;
|
||||||
@ -824,12 +785,11 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "rstereoVotes: %d rmonoVotes: %d\n",
|
fprintf(af, "rstereoVotes: %ud rmonoVotes: %ud\n",
|
||||||
rstereoVotes, rmonoVotes);
|
rstereoVotes, rmonoVotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (rstereoVotes > rmonoVotes)
|
guessStereo = (rstereoVotes > rmonoVotes);
|
||||||
guessStereo = true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -854,29 +814,29 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
fprintf(af, "evenMSB: %d BE: %d\n", evenMSB, guessBigEndian);
|
fprintf(af, "evenMSB: %d BE: %d\n", evenMSB, guessBigEndian);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
|
|
||||||
float former, latter;
|
float former, latter;
|
||||||
int i, offs;
|
int offs;
|
||||||
|
|
||||||
/* Extract a NEW array of the MSBs only: */
|
/* Extract a NEW array of the MSBs only: */
|
||||||
|
|
||||||
if (guessStereo)
|
if (guessStereo)
|
||||||
for (i = 0; i < (dataSize/4)-1; i++)
|
for (size_t i = 0; i + 1 < (dataSize / 4); i++)
|
||||||
rawData2[i] =
|
rawData2[i] =
|
||||||
rawData[test][4 * i + (evenMSB ? 0 : 1)];
|
rawData[test][4 * i + (evenMSB ? 0 : 1)];
|
||||||
else
|
else
|
||||||
for (i = 0; i < (dataSize/2)-1; i++)
|
for (size_t i = 0; i + 1 < (dataSize / 2); i++)
|
||||||
rawData2[i] =
|
rawData2[i] =
|
||||||
rawData[test][2 * i + (evenMSB ? 0 : 1)];
|
rawData[test][2 * i + (evenMSB ? 0 : 1)];
|
||||||
|
|
||||||
former = 0.0;
|
former = 0.0;
|
||||||
Extract(1, guessSigned, guessStereo, guessBigEndian, guessOffset,
|
Extract(1, guessSigned, guessStereo, guessBigEndian, guessOffset,
|
||||||
rawData[test], dataSize-4, data1, data2, &len1, &len2);
|
rawData[test].get(), dataSize-4, data1.get(), data2.get(), &len1, &len2);
|
||||||
|
|
||||||
offs=(!guessBigEndian);
|
offs=(!guessBigEndian);
|
||||||
|
|
||||||
for(i=3; i<len1-4; i++) {
|
for(size_t i = 3; i + 4 < len1; i++) {
|
||||||
if (rawData2[offs+i-2]==rawData2[offs+i-1] &&
|
if (rawData2[offs+i-2]==rawData2[offs+i-1] &&
|
||||||
rawData2[offs+i]==rawData2[offs+i-1]+1 &&
|
rawData2[offs+i]==rawData2[offs+i-1]+1 &&
|
||||||
rawData2[offs+i]==rawData2[offs+i+1]) {
|
rawData2[offs+i]==rawData2[offs+i+1]) {
|
||||||
@ -886,12 +846,12 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
|
|
||||||
latter = 0.0;
|
latter = 0.0;
|
||||||
Extract(1, guessSigned, guessStereo, !guessBigEndian,
|
Extract(1, guessSigned, guessStereo, !guessBigEndian,
|
||||||
!guessOffset, rawData[test], dataSize, data1, data2,
|
!guessOffset, rawData[test].get(), dataSize, data1.get(), data2.get(),
|
||||||
&len1, &len2);
|
&len1, &len2);
|
||||||
|
|
||||||
offs=(guessBigEndian);
|
offs=(guessBigEndian);
|
||||||
|
|
||||||
for(i=3; i<len1-4; i++) {
|
for(size_t i = 3; i + 4 < len1; i++) {
|
||||||
if (rawData2[offs+i-2]==rawData2[offs+i-1] &&
|
if (rawData2[offs+i-2]==rawData2[offs+i-1] &&
|
||||||
rawData2[offs+i]==rawData2[offs+i-1]+1 &&
|
rawData2[offs+i]==rawData2[offs+i-1]+1 &&
|
||||||
rawData2[offs+i]==rawData2[offs+i+1]) {
|
rawData2[offs+i]==rawData2[offs+i+1]) {
|
||||||
@ -911,7 +871,7 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "former (BE/LE): %d latter (LE+/BE+): %d\n",
|
fprintf(af, "former (BE/LE): %ud latter (LE+/BE+): %ud\n",
|
||||||
formerVotes, latterVotes);
|
formerVotes, latterVotes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -950,29 +910,23 @@ static int Guess16Bit(int numTests, char **rawData,
|
|||||||
else
|
else
|
||||||
*out_channels = 1;
|
*out_channels = 1;
|
||||||
|
|
||||||
free(rawData2);
|
|
||||||
|
|
||||||
free(data1);
|
|
||||||
free(data2);
|
|
||||||
|
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GuessIntFormats(int numTests, char **rawData, int dataSize,
|
static int GuessIntFormats(unsigned numTests, const ArrayOf<char> rawData[], size_t dataSize,
|
||||||
int *out_offset, unsigned *out_channels)
|
size_t *out_offset, unsigned *out_channels)
|
||||||
{
|
{
|
||||||
int format = SF_FORMAT_RAW;
|
int format = SF_FORMAT_RAW;
|
||||||
bool guess16bit = false;
|
bool guess16bit = false;
|
||||||
bool evenMSB;
|
bool evenMSB;
|
||||||
float *data1 = (float *)malloc((dataSize + 4) * sizeof(float));
|
ArrayOf<float> data1{ dataSize + 4 };
|
||||||
float *data2 = (float *)malloc((dataSize + 4) * sizeof(float));
|
ArrayOf<float> data2{ dataSize + 4 };
|
||||||
int len1;
|
size_t len1;
|
||||||
int len2;
|
size_t len2;
|
||||||
int vote8 = 0;
|
unsigned vote8 = 0;
|
||||||
int vote16 = 0;
|
unsigned vote16 = 0;
|
||||||
int evenMSBVotes = 0;
|
unsigned evenMSBVotes = 0;
|
||||||
int oddMSBVotes = 0;
|
unsigned oddMSBVotes = 0;
|
||||||
int test;
|
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
FILE *af = g_raw_debug_file;
|
FILE *af = g_raw_debug_file;
|
||||||
@ -993,14 +947,14 @@ static int GuessIntFormats(int numTests, char **rawData, int dataSize,
|
|||||||
* with mono or stereo data.
|
* with mono or stereo data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
float even, odd;
|
float even, odd;
|
||||||
|
|
||||||
Extract(0, 1, 1, 0, /* 8-bit signed stereo */
|
Extract(0, 1, 1, 0, /* 8-bit signed stereo */
|
||||||
false, rawData[test], dataSize,
|
false, rawData[test].get(), dataSize,
|
||||||
data1, data2, &len1, &len2);
|
data1.get(), data2.get(), &len1, &len2);
|
||||||
even = AmpStat(data1, len1);
|
even = AmpStat(data1.get(), len1);
|
||||||
odd = AmpStat(data2, len2);
|
odd = AmpStat(data2.get(), len2);
|
||||||
if ((even > 0.15) && (odd > 0.15)) {
|
if ((even > 0.15) && (odd > 0.15)) {
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "Both appear random: %.2f, %.2f.\n", even, odd);
|
fprintf(af, "Both appear random: %.2f, %.2f.\n", even, odd);
|
||||||
@ -1021,15 +975,12 @@ static int GuessIntFormats(int numTests, char **rawData, int dataSize,
|
|||||||
evenMSB = (evenMSBVotes > oddMSBVotes);
|
evenMSB = (evenMSBVotes > oddMSBVotes);
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fprintf(af, "evenMSBVote: %d oddMSBVote: %d\n",
|
fprintf(af, "evenMSBVote: %ud oddMSBVote: %ud\n",
|
||||||
evenMSBVotes, oddMSBVotes);
|
evenMSBVotes, oddMSBVotes);
|
||||||
fprintf(af, "vote8: %d vote16: %d\n", vote8, vote16);
|
fprintf(af, "vote8: %ud vote16: %ud\n", vote8, vote16);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (vote8 > vote16)
|
guess16bit = (vote8 <= vote16);
|
||||||
guess16bit = false;
|
|
||||||
else
|
|
||||||
guess16bit = true;
|
|
||||||
|
|
||||||
if (!guess16bit)
|
if (!guess16bit)
|
||||||
format = Guess8Bit(numTests, rawData, dataSize, out_channels);
|
format = Guess8Bit(numTests, rawData, dataSize, out_channels);
|
||||||
@ -1038,23 +989,18 @@ static int GuessIntFormats(int numTests, char **rawData, int dataSize,
|
|||||||
dataSize, evenMSB,
|
dataSize, evenMSB,
|
||||||
out_offset, out_channels);
|
out_offset, out_channels);
|
||||||
|
|
||||||
free(data1);
|
|
||||||
free(data2);
|
|
||||||
|
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawAudioGuess(const wxString &in_fname,
|
int RawAudioGuess(const wxString &in_fname,
|
||||||
int *out_offset, unsigned *out_channels)
|
size_t *out_offset, unsigned *out_channels)
|
||||||
{
|
{
|
||||||
const int numTests = 11;
|
const unsigned numTests = 11;
|
||||||
size_t headerSkipSize = 64;
|
size_t headerSkipSize = 64;
|
||||||
size_t dataSize = 16384;
|
size_t dataSize = 16384;
|
||||||
int format = SF_FORMAT_RAW;
|
int format = SF_FORMAT_RAW;
|
||||||
FILE *inf;
|
FILE *inf;
|
||||||
size_t fileLen;
|
size_t fileLen;
|
||||||
char *rawData[numTests];
|
|
||||||
int test;
|
|
||||||
size_t read_data;
|
size_t read_data;
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
@ -1095,10 +1041,14 @@ int RawAudioGuess(const wxString &in_fname,
|
|||||||
if (fileLen < dataSize)
|
if (fileLen < dataSize)
|
||||||
dataSize = fileLen / 2;
|
dataSize = fileLen / 2;
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++) {
|
wxASSERT( dataSize >= 4 );
|
||||||
|
wxASSERT( dataSize <= fileLen );
|
||||||
|
|
||||||
|
ArraysOf<char> rawData{ numTests, dataSize + 4 };
|
||||||
|
|
||||||
|
for (unsigned test = 0; test < numTests; test++) {
|
||||||
int startPoint;
|
int startPoint;
|
||||||
|
|
||||||
rawData[test] = (char *)malloc(dataSize + 4);
|
|
||||||
startPoint = (fileLen - dataSize) * (test + 1) / (numTests + 2);
|
startPoint = (fileLen - dataSize) * (test + 1) / (numTests + 2);
|
||||||
|
|
||||||
/* Make it a multiple of 16 (stereo double-precision) */
|
/* Make it a multiple of 16 (stereo double-precision) */
|
||||||
@ -1106,7 +1056,7 @@ int RawAudioGuess(const wxString &in_fname,
|
|||||||
|
|
||||||
// FIXME: TRAP_ERR fseek return in MultiFormatReader unchecked.
|
// FIXME: TRAP_ERR fseek return in MultiFormatReader unchecked.
|
||||||
fseek(inf, headerSkipSize + startPoint, SEEK_SET);
|
fseek(inf, headerSkipSize + startPoint, SEEK_SET);
|
||||||
read_data = fread(rawData[test], 1, dataSize, inf);
|
read_data = fread(rawData[test].get(), 1, dataSize, inf);
|
||||||
if (read_data != dataSize && ferror(inf)) {
|
if (read_data != dataSize && ferror(inf)) {
|
||||||
perror("fread error in RawAudioGuess");
|
perror("fread error in RawAudioGuess");
|
||||||
}
|
}
|
||||||
@ -1121,17 +1071,18 @@ int RawAudioGuess(const wxString &in_fname,
|
|||||||
* almost anything looks like it could be integer data...
|
* almost anything looks like it could be integer data...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
format = GuessFloatFormats(numTests, rawData, dataSize,
|
format = GuessFloatFormats(numTests,
|
||||||
|
rawData.get(),
|
||||||
|
dataSize,
|
||||||
out_offset, out_channels);
|
out_offset, out_channels);
|
||||||
|
|
||||||
if (format == 0) {
|
if (format == 0) {
|
||||||
format = GuessIntFormats(numTests, rawData, dataSize,
|
format = GuessIntFormats(numTests,
|
||||||
|
rawData.get(),
|
||||||
|
dataSize,
|
||||||
out_offset, out_channels);
|
out_offset, out_channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (test = 0; test < numTests; test++)
|
|
||||||
free(rawData[test]);
|
|
||||||
|
|
||||||
#if RAW_GUESS_DEBUG
|
#if RAW_GUESS_DEBUG
|
||||||
fclose(af);
|
fclose(af);
|
||||||
g_raw_debug_file = NULL;
|
g_raw_debug_file = NULL;
|
||||||
|
@ -25,4 +25,4 @@
|
|||||||
SF_FORMAT value
|
SF_FORMAT value
|
||||||
*/
|
*/
|
||||||
int RawAudioGuess(const wxString &in_fname,
|
int RawAudioGuess(const wxString &in_fname,
|
||||||
int *out_offset, unsigned *out_channels);
|
unsigned *out_offset, unsigned *out_channels);
|
||||||
|
@ -43,10 +43,7 @@ extern FFmpegLibs *FFmpegLibsInst();
|
|||||||
//struct for caching the decoded samples to be used over multiple blockfiles
|
//struct for caching the decoded samples to be used over multiple blockfiles
|
||||||
struct FFMpegDecodeCache
|
struct FFMpegDecodeCache
|
||||||
{
|
{
|
||||||
FFMpegDecodeCache() {}
|
ArrayOf<uint8_t> samplePtr;//interleaved samples
|
||||||
~FFMpegDecodeCache() { free(samplePtr); }
|
|
||||||
|
|
||||||
uint8_t* samplePtr{};//interleaved samples
|
|
||||||
sampleCount start;
|
sampleCount start;
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned numChannels;
|
unsigned numChannels;
|
||||||
@ -391,6 +388,7 @@ int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCo
|
|||||||
//if we've skipped over some samples, fill the gap with silence. This could happen often in the beginning of the file.
|
//if we've skipped over some samples, fill the gap with silence. This could happen often in the beginning of the file.
|
||||||
if(actualDecodeStart>start && firstpass) {
|
if(actualDecodeStart>start && firstpass) {
|
||||||
// find the number of samples for the leading silence
|
// find the number of samples for the leading silence
|
||||||
|
|
||||||
// UNSAFE_SAMPLE_COUNT_TRUNCATION
|
// UNSAFE_SAMPLE_COUNT_TRUNCATION
|
||||||
// -- but used only experimentally as of this writing
|
// -- but used only experimentally as of this writing
|
||||||
// Is there a proof size_t will not overflow size_t?
|
// Is there a proof size_t will not overflow size_t?
|
||||||
@ -402,7 +400,7 @@ int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCo
|
|||||||
|
|
||||||
//put it in the cache so the other channels can use it.
|
//put it in the cache so the other channels can use it.
|
||||||
// wxASSERT(sc->m_stream->codec->channels > 0);
|
// wxASSERT(sc->m_stream->codec->channels > 0);
|
||||||
cache->numChannels = sc->m_stream->codec->channels;
|
cache->numChannels = std::max<unsigned>(0, sc->m_stream->codec->channels);
|
||||||
cache->len = amt;
|
cache->len = amt;
|
||||||
cache->start=start;
|
cache->start=start;
|
||||||
// 8 bit and 16 bit audio output from ffmpeg means
|
// 8 bit and 16 bit audio output from ffmpeg means
|
||||||
@ -413,9 +411,7 @@ int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCo
|
|||||||
else
|
else
|
||||||
cache->samplefmt = AV_SAMPLE_FMT_FLT;
|
cache->samplefmt = AV_SAMPLE_FMT_FLT;
|
||||||
|
|
||||||
cache->samplePtr = (uint8_t*) malloc(amt * cache->numChannels * SAMPLE_SIZE(format));
|
cache->samplePtr.reinit(amt * cache->numChannels * SAMPLE_SIZE(format), true);
|
||||||
|
|
||||||
memset(cache->samplePtr, 0, amt * cache->numChannels * SAMPLE_SIZE(format));
|
|
||||||
|
|
||||||
InsertCache(std::move(cache));
|
InsertCache(std::move(cache));
|
||||||
}
|
}
|
||||||
@ -538,27 +534,27 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
|||||||
{
|
{
|
||||||
case AV_SAMPLE_FMT_U8:
|
case AV_SAMPLE_FMT_U8:
|
||||||
//printf("u8 in %lu out %lu cachelen %lu outLen %lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
//printf("u8 in %lu out %lu cachelen %lu outLen %lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||||
((int16_t *)outBuf)[outIndex] = (int16_t) (((uint8_t*)mDecodeCache[i]->samplePtr)[inIndex] - 0x80) << 8;
|
((int16_t *)outBuf)[outIndex] = (int16_t) (((uint8_t*)mDecodeCache[i]->samplePtr.get())[inIndex] - 0x80) << 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_S16:
|
case AV_SAMPLE_FMT_S16:
|
||||||
//printf("u16 in %lu out %lu cachelen %lu outLen % lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
//printf("u16 in %lu out %lu cachelen %lu outLen % lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||||
((int16_t *)outBuf)[outIndex] = ((int16_t*)mDecodeCache[i]->samplePtr)[inIndex];
|
((int16_t *)outBuf)[outIndex] = ((int16_t*)mDecodeCache[i]->samplePtr.get())[inIndex];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_S32:
|
case AV_SAMPLE_FMT_S32:
|
||||||
//printf("s32 in %lu out %lu cachelen %lu outLen %lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
//printf("s32 in %lu out %lu cachelen %lu outLen %lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||||
((float *)outBuf)[outIndex] = (float) ((int32_t*)mDecodeCache[i]->samplePtr)[inIndex] * (1.0 / (1u << 31));
|
((float *)outBuf)[outIndex] = (float) ((int32_t*)mDecodeCache[i]->samplePtr.get())[inIndex] * (1.0 / (1u << 31));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_FLT:
|
case AV_SAMPLE_FMT_FLT:
|
||||||
//printf("f in %lu out %lu cachelen %lu outLen %lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
//printf("f in %lu out %lu cachelen %lu outLen %lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||||
((float *)outBuf)[outIndex] = (float) ((float*)mDecodeCache[i]->samplePtr)[inIndex];
|
((float *)outBuf)[outIndex] = (float) ((float*)mDecodeCache[i]->samplePtr.get())[inIndex];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_DBL:
|
case AV_SAMPLE_FMT_DBL:
|
||||||
//printf("dbl in %lu out %lu cachelen %lu outLen %lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
//printf("dbl in %lu out %lu cachelen %lu outLen %lu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
|
||||||
((float *)outBuf)[outIndex] = (float) ((double*)mDecodeCache[i]->samplePtr)[inIndex];
|
((float *)outBuf)[outIndex] = (float) ((double*)mDecodeCache[i]->samplePtr.get())[inIndex];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -614,13 +610,13 @@ int ODFFmpegDecoder::DecodeFrame(streamContext *sc, bool flushing)
|
|||||||
auto cache = make_movable<FFMpegDecodeCache>();
|
auto cache = make_movable<FFMpegDecodeCache>();
|
||||||
//len is number of samples per channel
|
//len is number of samples per channel
|
||||||
// wxASSERT(sc->m_stream->codec->channels > 0);
|
// wxASSERT(sc->m_stream->codec->channels > 0);
|
||||||
cache->numChannels = sc->m_stream->codec->channels;
|
cache->numChannels = std::max<unsigned>(0, sc->m_stream->codec->channels);
|
||||||
|
|
||||||
cache->len = (sc->m_decodedAudioSamplesValidSiz / sc->m_samplesize) / cache->numChannels;
|
cache->len = (sc->m_decodedAudioSamplesValidSiz / sc->m_samplesize) / cache->numChannels;
|
||||||
cache->start = mCurrentPos;
|
cache->start = mCurrentPos;
|
||||||
cache->samplePtr = (uint8_t*) malloc(sc->m_decodedAudioSamplesValidSiz);
|
cache->samplePtr.reinit(sc->m_decodedAudioSamplesValidSiz);
|
||||||
cache->samplefmt = sc->m_samplefmt;
|
cache->samplefmt = sc->m_samplefmt;
|
||||||
memcpy(cache->samplePtr, sc->m_decodedAudioSamples.get(), sc->m_decodedAudioSamplesValidSiz);
|
memcpy(cache->samplePtr.get(), sc->m_decodedAudioSamples.get(), sc->m_decodedAudioSamplesValidSiz);
|
||||||
|
|
||||||
InsertCache(std::move(cache));
|
InsertCache(std::move(cache));
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ class ODLock {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ODCondition; //needs friendship for wait()
|
friend class ODCondition; //needs friendship for wait()
|
||||||
pthread_mutex_t mutex ;
|
pthread_mutex_t mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ODCondition
|
class ODCondition
|
||||||
|
@ -348,10 +348,7 @@ SpectrogramSettings::~SpectrogramSettings()
|
|||||||
|
|
||||||
void SpectrogramSettings::DestroyWindows()
|
void SpectrogramSettings::DestroyWindows()
|
||||||
{
|
{
|
||||||
if (hFFT != NULL) {
|
hFFT.reset();
|
||||||
EndFFT(hFFT);
|
|
||||||
hFFT = NULL;
|
|
||||||
}
|
|
||||||
window.reset();
|
window.reset();
|
||||||
dWindow.reset();
|
dWindow.reset();
|
||||||
tWindow.reset();
|
tWindow.reset();
|
||||||
@ -420,9 +417,7 @@ void SpectrogramSettings::CacheWindows() const
|
|||||||
const auto fftLen = WindowSize() * ZeroPaddingFactor();
|
const auto fftLen = WindowSize() * ZeroPaddingFactor();
|
||||||
const auto padding = (WindowSize() * (zeroPaddingFactor - 1)) / 2;
|
const auto padding = (WindowSize() * (zeroPaddingFactor - 1)) / 2;
|
||||||
|
|
||||||
if (hFFT != NULL)
|
hFFT = GetFFT(fftLen);
|
||||||
EndFFT(hFFT);
|
|
||||||
hFFT = InitializeFFT(fftLen);
|
|
||||||
RecreateWindow(window, WINDOW, fftLen, padding, windowType, windowSize, scale);
|
RecreateWindow(window, WINDOW, fftLen, padding, windowType, windowSize, scale);
|
||||||
if (algorithm == algReassignment) {
|
if (algorithm == algReassignment) {
|
||||||
RecreateWindow(tWindow, TWINDOW, fftLen, padding, windowType, windowSize, scale);
|
RecreateWindow(tWindow, TWINDOW, fftLen, padding, windowType, windowSize, scale);
|
||||||
|
@ -13,6 +13,7 @@ Paul Licameli
|
|||||||
|
|
||||||
#include "../Experimental.h"
|
#include "../Experimental.h"
|
||||||
#include "../SampleFormat.h"
|
#include "../SampleFormat.h"
|
||||||
|
#include "../RealFFTf.h"
|
||||||
|
|
||||||
#undef SPECTRAL_SELECTION_GLOBAL_SWITCH
|
#undef SPECTRAL_SELECTION_GLOBAL_SWITCH
|
||||||
|
|
||||||
@ -153,7 +154,7 @@ public:
|
|||||||
// Following fields are derived from preferences.
|
// Following fields are derived from preferences.
|
||||||
|
|
||||||
// Variables used for computing the spectrum
|
// Variables used for computing the spectrum
|
||||||
mutable FFTParam *hFFT{};
|
mutable HFFT hFFT;
|
||||||
mutable Floats window;
|
mutable Floats window;
|
||||||
|
|
||||||
// Two other windows for computing reassigned spectrogram
|
// Two other windows for computing reassigned spectrogram
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
\brief An array of these created by the Ruler is used to determine
|
\brief An array of these created by the Ruler is used to determine
|
||||||
what and where text annotations to the numbers on the Ruler get drawn.
|
what and where text annotations to the numbers on the Ruler get drawn.
|
||||||
|
|
||||||
\todo Check whether Ruler is costing too much time in malloc/free of
|
\todo Check whether Ruler is costing too much time in allocation/free of
|
||||||
array of Ruler::Label.
|
array of Ruler::Label.
|
||||||
|
|
||||||
*//******************************************************************/
|
*//******************************************************************/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user