mirror of
https://github.com/RPCS3/soundtouch.git
synced 2024-11-08 12:02:28 +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
|
||||
filter cause slight click if the rate change crosses zero during
|
||||
processing</li>
|
||||
<li>Added script for building SoundTouchDll dynamic-link-library for GNU platforms</li>
|
||||
<li>Added BPM functions to SoundTouchDll API</li>
|
||||
</ul>
|
||||
<p><b>2.0:</b></p>
|
||||
<ul>
|
||||
|
@ -79,10 +79,10 @@ namespace soundtouch
|
||||
{
|
||||
|
||||
/// Soundtouch library version string
|
||||
#define SOUNDTOUCH_VERSION "2.0.0"
|
||||
#define SOUNDTOUCH_VERSION "2.0.1pre"
|
||||
|
||||
/// SoundTouch library version id
|
||||
#define SOUNDTOUCH_VERSION_ID (20000)
|
||||
#define SOUNDTOUCH_VERSION_ID (20001)
|
||||
|
||||
//
|
||||
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include <string.h>
|
||||
#include "SoundTouchDLL.h"
|
||||
#include "SoundTouch.h"
|
||||
#include "BPMDetect.h"
|
||||
|
||||
using namespace soundtouch;
|
||||
|
||||
@ -75,7 +76,15 @@ typedef struct
|
||||
SoundTouch *pst;
|
||||
} 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()
|
||||
{
|
||||
@ -359,6 +368,7 @@ SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples(HANDLE h,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// int16 version of soundtouch_receiveSamples(): This converts internal float samples
|
||||
/// into int16 (short) return data type
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
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_
|
||||
|
||||
|
@ -38,9 +38,12 @@ namespace soundtouch
|
||||
{
|
||||
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 bool IsDisposed = false;
|
||||
private IntPtr handle;
|
||||
@ -541,4 +544,138 @@ namespace soundtouch
|
||||
|
||||
#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