mirror of
https://github.com/RPCS3/soundtouch.git
synced 2024-11-08 20:12:27 +01:00
Added BPMDetect functions to SoundTouchDll API
This commit is contained in:
parent
407f516e0d
commit
ec9ba968f5
@ -580,6 +580,8 @@ this corresponds to lowering the pitch by -0.318 semitones:</p>
|
|||||||
SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER defined because anti-alias
|
SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER defined because anti-alias
|
||||||
filter cause slight click if the rate change crosses zero during
|
filter cause slight click if the rate change crosses zero during
|
||||||
processing</li>
|
processing</li>
|
||||||
|
<li>Added script for building SoundTouchDll dynamic-link-library for GNU platforms</li>
|
||||||
|
<li>Added BPM functions to SoundTouchDll API</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p><b>2.0:</b></p>
|
<p><b>2.0:</b></p>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -79,10 +79,10 @@ namespace soundtouch
|
|||||||
{
|
{
|
||||||
|
|
||||||
/// Soundtouch library version string
|
/// Soundtouch library version string
|
||||||
#define SOUNDTOUCH_VERSION "2.0.0"
|
#define SOUNDTOUCH_VERSION "2.0.1pre"
|
||||||
|
|
||||||
/// SoundTouch library version id
|
/// SoundTouch library version id
|
||||||
#define SOUNDTOUCH_VERSION_ID (20000)
|
#define SOUNDTOUCH_VERSION_ID (20001)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "SoundTouchDLL.h"
|
#include "SoundTouchDLL.h"
|
||||||
#include "SoundTouch.h"
|
#include "SoundTouch.h"
|
||||||
|
#include "BPMDetect.h"
|
||||||
|
|
||||||
using namespace soundtouch;
|
using namespace soundtouch;
|
||||||
|
|
||||||
@ -75,7 +76,15 @@ typedef struct
|
|||||||
SoundTouch *pst;
|
SoundTouch *pst;
|
||||||
} STHANDLE;
|
} STHANDLE;
|
||||||
|
|
||||||
#define STMAGIC 0x1770C001
|
typedef struct
|
||||||
|
{
|
||||||
|
DWORD dwMagic;
|
||||||
|
BPMDetect *pbpm;
|
||||||
|
uint numChannels;
|
||||||
|
} BPMHANDLE;
|
||||||
|
|
||||||
|
#define STMAGIC 0x1770C001
|
||||||
|
#define BPMMAGIC 0x1771C10a
|
||||||
|
|
||||||
SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance()
|
SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance()
|
||||||
{
|
{
|
||||||
@ -359,6 +368,7 @@ SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples(HANDLE h,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// int16 version of soundtouch_receiveSamples(): This converts internal float samples
|
/// int16 version of soundtouch_receiveSamples(): This converts internal float samples
|
||||||
/// into int16 (short) return data type
|
/// into int16 (short) return data type
|
||||||
SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples_i16(HANDLE h,
|
SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples_i16(HANDLE h,
|
||||||
@ -429,3 +439,93 @@ SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h)
|
|||||||
|
|
||||||
return sth->pst->isEmpty();
|
return sth->pst->isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate)
|
||||||
|
{
|
||||||
|
BPMHANDLE *tmp = new BPMHANDLE;
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
tmp->dwMagic = BPMMAGIC;
|
||||||
|
tmp->pbpm = new BPMDetect(numChannels, sampleRate);
|
||||||
|
if (tmp->pbpm == NULL)
|
||||||
|
{
|
||||||
|
delete tmp;
|
||||||
|
tmp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (HANDLE)tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h)
|
||||||
|
{
|
||||||
|
BPMHANDLE *sth = (BPMHANDLE*)h;
|
||||||
|
if (sth->dwMagic != BPMMAGIC) return;
|
||||||
|
|
||||||
|
sth->dwMagic = 0;
|
||||||
|
if (sth->pbpm) delete sth->pbpm;
|
||||||
|
sth->pbpm = NULL;
|
||||||
|
delete sth;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Feed 'numSamples' sample frames from 'samples' into the BPM detection handler
|
||||||
|
SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h,
|
||||||
|
const float *samples,
|
||||||
|
unsigned int numSamples)
|
||||||
|
{
|
||||||
|
BPMHANDLE *bpmh = (BPMHANDLE*)h;
|
||||||
|
if (bpmh->dwMagic != BPMMAGIC) return;
|
||||||
|
|
||||||
|
bpmh->pbpm->inputSamples(samples, numSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Feed 'numSamples' sample frames from 'samples' into the BPM detection handler.
|
||||||
|
/// 16bit int sample format verson.
|
||||||
|
SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h,
|
||||||
|
const short *samples,
|
||||||
|
unsigned int numSamples)
|
||||||
|
{
|
||||||
|
BPMHANDLE *bpmh = (BPMHANDLE*)h;
|
||||||
|
if (bpmh->dwMagic != BPMMAGIC) return;
|
||||||
|
|
||||||
|
uint numChannels = bpmh->numChannels;
|
||||||
|
|
||||||
|
// iterate until all samples converted & put to SoundTouch object
|
||||||
|
while (numSamples > 0)
|
||||||
|
{
|
||||||
|
float convert[8192]; // allocate temporary conversion buffer from stack
|
||||||
|
|
||||||
|
// how many multichannel samples fit into 'convert' buffer:
|
||||||
|
uint convSamples = 8192 / numChannels;
|
||||||
|
|
||||||
|
// convert max 'nround' values at a time to guarantee that these fit in the 'convert' buffer
|
||||||
|
uint n = (numSamples > convSamples) ? convSamples : numSamples;
|
||||||
|
for (uint i = 0; i < n * numChannels; i++)
|
||||||
|
{
|
||||||
|
convert[i] = samples[i];
|
||||||
|
}
|
||||||
|
// put the converted samples into SoundTouch
|
||||||
|
bpmh->pbpm->inputSamples(convert, n);
|
||||||
|
|
||||||
|
numSamples -= n;
|
||||||
|
samples += n * numChannels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Analyzes the results and returns the BPM rate. Use this function to read result
|
||||||
|
/// after whole song data has been input to the class by consecutive calls of
|
||||||
|
/// 'inputSamples' function.
|
||||||
|
///
|
||||||
|
/// \return Beats-per-minute rate, or zero if detection failed.
|
||||||
|
SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h)
|
||||||
|
{
|
||||||
|
BPMHANDLE *bpmh = (BPMHANDLE*)h;
|
||||||
|
if (bpmh->dwMagic != BPMMAGIC) return 0;
|
||||||
|
|
||||||
|
return bpmh->pbpm->getBpm();
|
||||||
|
}
|
||||||
|
@ -199,5 +199,35 @@ SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numSamples(HANDLE h);
|
|||||||
/// Returns nonzero if there aren't any samples available for outputting.
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h);
|
SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h);
|
||||||
|
|
||||||
|
/// Create a new instance of BPM detector
|
||||||
|
SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate);
|
||||||
|
|
||||||
|
/// Destroys a BPM detector instance.
|
||||||
|
SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h);
|
||||||
|
|
||||||
|
/// Feed 'numSamples' sample frames from 'samples' into the BPM detector.
|
||||||
|
SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h,
|
||||||
|
const float *samples, ///< Pointer to sample buffer.
|
||||||
|
unsigned int numSamples ///< Number of samples in buffer. Notice
|
||||||
|
///< that in case of stereo-sound a single sample
|
||||||
|
///< contains data for both channels.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Feed 'numSamples' sample frames from 'samples' into the BPM detector.
|
||||||
|
/// 16bit int sample format verson.
|
||||||
|
SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h,
|
||||||
|
const short *samples, ///< Pointer to sample buffer.
|
||||||
|
unsigned int numSamples ///< Number of samples in buffer. Notice
|
||||||
|
///< that in case of stereo-sound a single sample
|
||||||
|
///< contains data for both channels.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Analyzes the results and returns the BPM rate. Use this function to read result
|
||||||
|
/// after whole song data has been input to the class by consecutive calls of
|
||||||
|
/// 'inputSamples' function.
|
||||||
|
///
|
||||||
|
/// \return Beats-per-minute rate, or zero if detection failed.
|
||||||
|
SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h);
|
||||||
|
|
||||||
#endif // _SoundTouchDLL_h_
|
#endif // _SoundTouchDLL_h_
|
||||||
|
|
||||||
|
@ -38,9 +38,12 @@ namespace soundtouch
|
|||||||
{
|
{
|
||||||
public sealed class SoundTouch : IDisposable
|
public sealed class SoundTouch : IDisposable
|
||||||
{
|
{
|
||||||
#region Private Members
|
#region Internal Members
|
||||||
|
internal const string SoundTouchLibrary = "SoundTouch.dll";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Members // hahaha what a curious region
|
||||||
|
|
||||||
private const string SoundTouchLibrary = "SoundTouch.dll";
|
|
||||||
private readonly object SyncRoot = new object();
|
private readonly object SyncRoot = new object();
|
||||||
private bool IsDisposed = false;
|
private bool IsDisposed = false;
|
||||||
private IntPtr handle;
|
private IntPtr handle;
|
||||||
@ -541,4 +544,138 @@ namespace soundtouch
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public sealed class BPMDetect : IDisposable
|
||||||
|
{
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
private readonly object SyncRoot = new object();
|
||||||
|
private bool IsDisposed = false;
|
||||||
|
private IntPtr handle;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BPMDetect"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public BPMDetect(int numChannels, int sampleRate)
|
||||||
|
{
|
||||||
|
handle = NativeMethods.BpmCreateInstance(numChannels, sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finalizes an instance of the <see cref="BPMDetect"/> class.
|
||||||
|
/// </summary>
|
||||||
|
~BPMDetect()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the analysed BPM rate.
|
||||||
|
/// </summary>
|
||||||
|
public float Bpm
|
||||||
|
{
|
||||||
|
get { lock (SyncRoot) { return NativeMethods.BpmGet(handle); } }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Sample Stream Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Feed 'numSamples' sample into the BPM detector
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="samples">Sample buffer to input</param>
|
||||||
|
/// <param name="numSamples">Number of sample frames in buffer. Notice
|
||||||
|
/// that in case of multi-channel sound a single sample frame contains
|
||||||
|
/// data for all channels</param>
|
||||||
|
public void PutSamples(float[] samples, uint numSamples)
|
||||||
|
{
|
||||||
|
lock (SyncRoot) { NativeMethods.BpmPutSamples(handle, samples, numSamples); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// int16 version of putSamples(): This accept int16 (short) sample data
|
||||||
|
/// and internally converts it to float format before processing
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="samples">Sample input buffer.</param>
|
||||||
|
/// <param name="numSamples">Number of sample frames in buffer. Notice
|
||||||
|
/// that in case of multi-channel sound a single
|
||||||
|
/// sample frame contains data for all channels.</param>
|
||||||
|
public void PutSamplesI16(short[] samples, uint numSamples)
|
||||||
|
{
|
||||||
|
lock (SyncRoot) { NativeMethods.BpmPutSamples_i16(handle, samples, numSamples); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable Support
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases unmanaged and - optionally - managed resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="alsoManaged"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||||
|
private void Dispose(bool alsoManaged)
|
||||||
|
{
|
||||||
|
if (!IsDisposed)
|
||||||
|
{
|
||||||
|
if (alsoManaged)
|
||||||
|
{
|
||||||
|
// NOTE: Placeholder, dispose managed state (managed objects).
|
||||||
|
// At this point, nothing managed to dispose
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeMethods.BpmDestroyInstance(handle);
|
||||||
|
handle = IntPtr.Zero;
|
||||||
|
|
||||||
|
IsDisposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Native Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides direct access to mapped DLL methods
|
||||||
|
/// </summary>
|
||||||
|
private static class NativeMethods
|
||||||
|
{
|
||||||
|
[DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_createInstance")]
|
||||||
|
public static extern IntPtr BpmCreateInstance(int numChannels, int sampleRate);
|
||||||
|
|
||||||
|
[DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_destroyInstance")]
|
||||||
|
public static extern void BpmDestroyInstance(IntPtr h);
|
||||||
|
|
||||||
|
[DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_putSamples")]
|
||||||
|
public static extern void BpmPutSamples(IntPtr h, float[] samples, uint numSamples);
|
||||||
|
|
||||||
|
[DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_putSamples_i16")]
|
||||||
|
public static extern void BpmPutSamples_i16(IntPtr h, short[] samples, uint numSamples);
|
||||||
|
|
||||||
|
[DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_getBpm")]
|
||||||
|
public static extern float BpmGet(IntPtr h);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user