Simplify sample frame operations (make it a class) (#7156)

* Remove the struct StereoSample

Remove the struct `StereoSample`. Let `AudioEngine::getPeakValues` return a `sampleFrame` instead.

Adjust the calls in `Mixer`  and `Oscilloscope`.

* Simplify AudioEngine::getPeakValues

* Remove surroundSampleFrame

Some code assumes that `surroundSampleFrame` is interchangeable with `sampleFrame`. Thus, if the line `#define LMMS_DISABLE_SURROUND` is commented out in `lmms_basics.h` then the code does not compile anymore because `surroundSampleFrame` now is defined to be an array with four values instead of two. There also does not seem to be any support for surround sound (four channels instead of two) in the application. The faders and mixers do not seem to support more that two channels and the instruments and effects all expect a `sampleFrame`, i.e. stereo channels. It therefore makes sense to remove the "feature" because it also hinders the improvement of `sampleFrame`, e.g. by making it a class with some convenience methods that act on `sampleFrame` instances.

All occurrences of `surroundSampleFrame` are replaced with `sampleFrame`.

The version of `BufferManager::clear` that takes a `surroundSampleFrame` is removed completely.

The define `SURROUND_CHANNELS` is removed. All its occurrences are replaced with `DEFAULT_CHANNELS`.

Most of the audio devices classes, i.e. classes that inherit from `AudioDevice`, now clamp the configuration parameter between two values of `DEFAULT_CHANNELS`. This can be improved/streamlined later.

`BYTES_PER_SURROUND_FRAME` has been removed as it was not used anywhere anyway.

* Make sampleFrame a class

Make `sampleFrame` a class with several convenience methods. As a first step and demonstration adjust the follow methods to make use of the new functionality:
* `AudioEngine::getPeakValues`: Much more concise now.
* `lmms::MixHelpers::sanitize`: Better structure, better readable, less dereferencing and juggling with indices.
* `AddOp`, `AddMultipliedOp`, `multiply`: Make use of operators. Might become superfluous in the future.

* More operators and methods for sampleFrame

Add some more operators and methods to `sampleFrame`:
* Constructor which initializes both channels from a single sample value
* Assignment operator from a single sample value
* Addition/multiplication operators
* Scalar product

Adjust some more plugins to the new functionality of `sampleFrame`.

* Adjust DelayEffect to methods in sampleFrame

* Use composition instead of inheritance

Using inheritance was the quickest way to enable adding methods to `sampleFrame` without having to reimpement much of `std::array`s interface.

This is changed with this commit. The array is now a member of `sampleFrame` and the interface is extended with the necessary methods `data` and the index operator.

An `average` method was added so that no iterators need to be implemented (see changes in `SampleWaveform.cpp`).

* Apply suggestions from code review

Apply Veratil's suggestions from the code review

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Fix warnings: zeroing non-trivial type

Fix several warnings of the following form:

Warnung: »void* memset(void*, int, size_t)« Säubern eines Objekts von nichttrivialem Typ »class lmms::sampleFrame«; use assignment or value-initialization instead [-Wclass-memaccess]

* Remove unnecessary reinterpret_casts

Remove some unnecessary reinterpret_casts with regards to `sampleFrame` buffers.

`PlayHandle::m_playHandleBuffer` already is a `sampleFrame*` and does not need a reinterpret_cast anymore.

In `LadspaEffect::processAudioBuffer` the `QVarLengthArray` is now directly initialized as an array of `sampleFrame` instances.

I guess in both places the `sampleFrame` previously was a `surroundSampleFrame` which has been removed.

* Clean up zeroSampleFrames code

* Fix warnings in RemotePlugin

Fix some warnings related to calls to `memcpy` in conjunction with`sampleFrame` which is now a class.

Add the helper functions `copyToSampleFrames` and `copyFromSampleFrames` and use them. The first function copies data from a `float` buffer into a `sampleFrame` buffer and the second copies vice versa.

* Rename "sampleFrame" to "SampleFrame"

Uppercase the name of `sampleFrame` so that it uses UpperCamelCase convention.

* Move SampleFrame into its own file

Move the class `SampleFrame` into its own class and remove it from `lmms_basics.h`.

Add forward includes to all headers where possible or include the `SampleFrame` header if it's not just referenced but used.

Add include to all cpp files where necessary.

It's a bit surprising that the `SampleFrame` header does not need to be included much more often in the implementation/cpp files. This is an indicator that it seems to be included via an include chain that at one point includes one of the headers where an include instead of a forward declaration had to be added in this commit.

* Return reference for += and *=

Return a reference for the compound assignment operators `+=` and `-=`.

* Explicit float constructor

Make the  constructor that takes a `float` explicit.

Remove the assignment operator that takes a `float`. Clients must use the
explicit `float` constructor and assign the result.

Adjust the code in "BitInvader" accordingly.

* Use std::fill in zeroSampleFrames

* Use zeroSampleFrames in sanitize

* Replace max with absMax

Replace `SampleFrame::max` with `SampleFrame::absMax`.

Use `absMax` in `DelayEffect::processAudioBuffer`. This should also fix
a buggy implementation of the peak computation.

Add the function `getAbsPeakValues`. It  computes the absolute peak
values for a buffer.

Remove `AudioEngine::getPeakValues`. It's not really the business of the
audio engine. Let `Mixer` and `Oscilloscope` use `getAbsPeakValues`.

* Replace scalarProduct

Replace the rather mathematical method `scalarProduct` with
`sumOfSquaredAmplitudes`. It was always called on itself anyway.

* Remove comment/TODO

* Simplify sanitize

Simplify the `sanitize` function by getting rid of the `bool found` and
by zeroing the buffer as soon as a problem is found.

* Put pointer symbols next to type

* Code review adjustments

* Remove "#pragme once"
* Adjust name of include guard
* Remove superfluous includes (leftovers from previous code changes)

---------

Co-authored-by: Kevin Zander <veratil@gmail.com>
This commit is contained in:
Michael Gregorius
2024-06-30 20:21:19 +02:00
committed by GitHub
parent a0fbd7e7b4
commit 286e62adf5
199 changed files with 879 additions and 668 deletions

View File

@@ -37,6 +37,7 @@ namespace lmms
class AudioEngine;
class AudioPort;
class SampleFrame;
class AudioDevice
@@ -92,14 +93,14 @@ public:
protected:
// subclasses can re-implement this for being used in conjunction with
// processNextBuffer()
virtual void writeBuffer(const surroundSampleFrame* /* _buf*/, const fpp_t /*_frames*/) {}
virtual void writeBuffer(const SampleFrame* /* _buf*/, const fpp_t /*_frames*/) {}
// called by according driver for fetching new sound-data
fpp_t getNextBuffer( surroundSampleFrame * _ab );
fpp_t getNextBuffer(SampleFrame* _ab);
// convert a given audio-buffer to a buffer in signed 16-bit samples
// returns num of bytes in outbuf
int convertToS16( const surroundSampleFrame * _ab,
int convertToS16(const SampleFrame* _ab,
const fpp_t _frames,
int_sample_t * _output_buffer,
const bool _convert_endian = false );
@@ -133,7 +134,7 @@ private:
QMutex m_devMutex;
surroundSampleFrame * m_buffer;
SampleFrame* m_buffer;
};

View File

@@ -94,7 +94,7 @@ private:
while( true )
{
timer.reset();
const surroundSampleFrame* b = audioEngine()->nextBuffer();
const SampleFrame* b = audioEngine()->nextBuffer();
if( !b )
{
break;

View File

@@ -38,6 +38,7 @@
#include <vector>
#include "lmms_basics.h"
#include "SampleFrame.h"
#include "LocklessList.h"
#include "FifoBuffer.h"
#include "AudioEngineProfiler.h"
@@ -58,8 +59,7 @@ const fpp_t DEFAULT_BUFFER_SIZE = 256;
const int BYTES_PER_SAMPLE = sizeof( sample_t );
const int BYTES_PER_INT_SAMPLE = sizeof( int_sample_t );
const int BYTES_PER_FRAME = sizeof( sampleFrame );
const int BYTES_PER_SURROUND_FRAME = sizeof( surroundSampleFrame );
const int BYTES_PER_FRAME = sizeof( SampleFrame );
const float OUTPUT_SAMPLE_MULTIPLIER = 32767.0f;
@@ -267,15 +267,6 @@ public:
}
struct StereoSample
{
StereoSample(sample_t _left, sample_t _right) : left(_left), right(_right) {}
sample_t left;
sample_t right;
};
StereoSample getPeakValues(sampleFrame * ab, const f_cnt_t _frames) const;
bool criticalXRuns() const;
inline bool hasFifoWriter() const
@@ -283,9 +274,9 @@ public:
return m_fifoWriter != nullptr;
}
void pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames );
void pushInputFrames( SampleFrame* _ab, const f_cnt_t _frames );
inline const sampleFrame * inputBuffer()
inline const SampleFrame* inputBuffer()
{
return m_inputBuffer[ m_inputBufferRead ];
}
@@ -295,7 +286,7 @@ public:
return m_inputBufferFrames[ m_inputBufferRead ];
}
inline const surroundSampleFrame * nextBuffer()
inline const SampleFrame* nextBuffer()
{
return hasFifoWriter() ? m_fifo->read() : renderNextBuffer();
}
@@ -321,11 +312,11 @@ public:
signals:
void qualitySettingsChanged();
void sampleRateChanged();
void nextAudioBuffer( const lmms::surroundSampleFrame * buffer );
void nextAudioBuffer(const lmms::SampleFrame* buffer);
private:
using Fifo = FifoBuffer<surroundSampleFrame*>;
using Fifo = FifoBuffer<SampleFrame*>;
class fifoWriter : public QThread
{
@@ -342,7 +333,7 @@ private:
void run() override;
void write( surroundSampleFrame * buffer );
void write(SampleFrame* buffer);
} ;
@@ -361,7 +352,7 @@ private:
void renderStageEffects();
void renderStageMix();
const surroundSampleFrame * renderNextBuffer();
const SampleFrame* renderNextBuffer();
void swapBuffers();
@@ -375,14 +366,14 @@ private:
fpp_t m_framesPerPeriod;
sampleFrame * m_inputBuffer[2];
SampleFrame* m_inputBuffer[2];
f_cnt_t m_inputBufferFrames[2];
f_cnt_t m_inputBufferSize[2];
int m_inputBufferRead;
int m_inputBufferWrite;
std::unique_ptr<surroundSampleFrame[]> m_outputBufferRead;
std::unique_ptr<surroundSampleFrame[]> m_outputBufferWrite;
std::unique_ptr<SampleFrame[]> m_outputBufferRead;
std::unique_ptr<SampleFrame[]> m_outputBufferWrite;
// worker thread stuff
std::vector<AudioEngineWorkerThread *> m_workers;

View File

@@ -65,7 +65,7 @@ private:
SF_INFO m_sfinfo;
SNDFILE* m_sf;
void writeBuffer(surroundSampleFrame const* _ab, fpp_t const frames) override;
void writeBuffer(const SampleFrame* _ab, fpp_t const frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -58,7 +58,7 @@ public:
}
protected:
void writeBuffer(const surroundSampleFrame* /* _buf*/, const fpp_t /*_frames*/) override;
void writeBuffer(const SampleFrame* /* _buf*/, const fpp_t /*_frames*/) override;
private:
void flushRemainingBuffers();

View File

@@ -58,7 +58,7 @@ public:
private:
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
void writeBuffer(const SampleFrame* _ab, const fpp_t _frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -56,7 +56,7 @@ public:
private:
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
void writeBuffer(const SampleFrame* _ab, const fpp_t _frames) override;
bool startEncoding();
void finishEncoding();

View File

@@ -111,7 +111,7 @@ private:
std::atomic<MidiJack*> m_midiClient;
std::vector<jack_port_t*> m_outputPorts;
jack_default_audio_sample_t** m_tempOutBufs;
surroundSampleFrame* m_outBuf;
SampleFrame* m_outBuf;
f_cnt_t m_framesDoneInCurBuf;
f_cnt_t m_framesToDoInCurBuf;

View File

@@ -46,7 +46,7 @@ public:
BoolModel * mutedModel = nullptr );
virtual ~AudioPort();
inline sampleFrame * buffer()
inline SampleFrame* buffer()
{
return m_portBuffer;
}
@@ -112,7 +112,7 @@ public:
private:
volatile bool m_bufferUsage;
sampleFrame * m_portBuffer;
SampleFrame* m_portBuffer;
QMutex m_portBufferLock;
bool m_extOutputEnabled;

View File

@@ -150,7 +150,7 @@ private:
bool m_wasPAInitError;
surroundSampleFrame * m_outBuf;
SampleFrame* m_outBuf;
int m_outBufPos;
int m_outBufSize;

View File

@@ -48,9 +48,9 @@ public:
std::shared_ptr<const SampleBuffer> createSampleBuffer();
private:
void writeBuffer(const surroundSampleFrame* _ab, const fpp_t _frames) override;
void writeBuffer(const SampleFrame* _ab, const fpp_t _frames) override;
using BufferList = QList<QPair<sampleFrame*, fpp_t>>;
using BufferList = QList<QPair<SampleFrame*, fpp_t>>;
BufferList m_buffers;
} ;

View File

@@ -85,7 +85,7 @@ private:
SDL_AudioSpec m_audioHandle;
surroundSampleFrame * m_outBuf;
SampleFrame* m_outBuf;
#ifdef LMMS_HAVE_SDL2
size_t m_currentBufferFramePos;

View File

@@ -110,7 +110,7 @@ private:
SoundIo *m_soundio;
SoundIoOutStream *m_outstream;
surroundSampleFrame * m_outBuf;
SampleFrame* m_outBuf;
int m_outBufSize;
fpp_t m_outBufFramesTotal;
fpp_t m_outBufFrameIndex;

View File

@@ -32,20 +32,18 @@
namespace lmms
{
class SampleFrame;
class LMMS_EXPORT BufferManager
{
public:
static void init( fpp_t fpp );
static sampleFrame * acquire();
static SampleFrame* acquire();
// audio-buffer-mgm
static void clear( sampleFrame * ab, const f_cnt_t frames,
static void clear( SampleFrame* ab, const f_cnt_t frames,
const f_cnt_t offset = 0 );
#ifndef LMMS_DISABLE_SURROUND
static void clear( surroundSampleFrame * ab, const f_cnt_t frames,
const f_cnt_t offset = 0 );
#endif
static void release( sampleFrame * buf );
static void release( SampleFrame* buf );
private:
static fpp_t s_framesPerPeriod;

View File

@@ -28,7 +28,7 @@
#include "lmms_math.h"
#include "lmms_constants.h"
#include "lmms_basics.h"
#include "SampleFrame.h"
namespace lmms::DspEffectLibrary
{
@@ -80,6 +80,17 @@ namespace lmms::DspEffectLibrary
{
}
void setGain(float gain)
{
leftFX().setGain(gain);
rightFX().setGain(gain);
}
void nextSample(SampleFrame & in)
{
nextSample(in.left(), in.right());
}
void nextSample( sample_t& inLeft, sample_t& inRight )
{
inLeft = m_leftFX.nextSample( inLeft );

View File

@@ -107,7 +107,7 @@ public:
return &m_controls;
}
bool processAudioBuffer( sampleFrame *, const fpp_t ) override
bool processAudioBuffer( SampleFrame*, const fpp_t ) override
{
return false;
}

View File

@@ -49,10 +49,9 @@ public:
~DummyInstrument() override = default;
void playNote( NotePlayHandle *, sampleFrame * buffer ) override
void playNote( NotePlayHandle*, SampleFrame* buffer ) override
{
memset( buffer, 0, sizeof( sampleFrame ) *
Engine::audioEngine()->framesPerPeriod() );
zeroSampleFrames(buffer, Engine::audioEngine()->framesPerPeriod());
}
void saveSettings( QDomDocument &, QDomElement & ) override

View File

@@ -64,7 +64,7 @@ public:
}
virtual bool processAudioBuffer( sampleFrame * _buf,
virtual bool processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames ) = 0;
inline ch_cnt_t processorCount() const
@@ -187,8 +187,8 @@ protected:
// some effects might not be capable of higher sample-rates so they can
// sample it down before processing and back after processing
inline void sampleDown( const sampleFrame * _src_buf,
sampleFrame * _dst_buf,
inline void sampleDown( const SampleFrame* _src_buf,
SampleFrame* _dst_buf,
sample_rate_t _dst_sr )
{
resample( 0, _src_buf,
@@ -197,8 +197,8 @@ protected:
Engine::audioEngine()->framesPerPeriod() );
}
inline void sampleBack( const sampleFrame * _src_buf,
sampleFrame * _dst_buf,
inline void sampleBack( const SampleFrame* _src_buf,
SampleFrame* _dst_buf,
sample_rate_t _src_sr )
{
resample( 1, _src_buf, _src_sr, _dst_buf,
@@ -213,9 +213,9 @@ protected:
private:
EffectChain * m_parent;
void resample( int _i, const sampleFrame * _src_buf,
void resample( int _i, const SampleFrame* _src_buf,
sample_rate_t _src_sr,
sampleFrame * _dst_buf, sample_rate_t _dst_sr,
SampleFrame* _dst_buf, sample_rate_t _dst_sr,
const f_cnt_t _frames );
ch_cnt_t m_processors;

View File

@@ -34,6 +34,7 @@ namespace lmms
{
class Effect;
class SampleFrame;
namespace gui
{
@@ -62,7 +63,7 @@ public:
void removeEffect( Effect * _effect );
void moveDown( Effect * _effect );
void moveUp( Effect * _effect );
bool processAudioBuffer( sampleFrame * _buf, const fpp_t _frames, bool hasInputNoise );
bool processAudioBuffer( SampleFrame* _buf, const fpp_t _frames, bool hasInputNoise );
void startRunning();
void clear();

View File

@@ -45,6 +45,7 @@ class InstrumentTrack;
class MidiEvent;
class NotePlayHandle;
class Track;
class SampleFrame;
class LMMS_EXPORT Instrument : public Plugin
@@ -75,11 +76,11 @@ public:
// if the plugin doesn't play each note, it can create an instrument-
// play-handle and re-implement this method, so that it mixes its
// output buffer only once per audio engine period
virtual void play( sampleFrame * _working_buffer );
virtual void play( SampleFrame* _working_buffer );
// to be implemented by actual plugin
virtual void playNote( NotePlayHandle * /* _note_to_play */,
sampleFrame * /* _working_buf */ )
SampleFrame* /* _working_buf */ )
{
}
@@ -160,12 +161,12 @@ public:
protected:
// fade in to prevent clicks
void applyFadeIn(sampleFrame * buf, NotePlayHandle * n);
void applyFadeIn(SampleFrame* buf, NotePlayHandle * n);
// instruments may use this to apply a soft fade out at the end of
// notes - method does this only if really less or equal
// desiredReleaseFrames() frames are left
void applyRelease( sampleFrame * buf, const NotePlayHandle * _n );
void applyRelease( SampleFrame* buf, const NotePlayHandle * _n );
float computeReleaseTimeMsByFrameCount(f_cnt_t frames) const;

View File

@@ -41,7 +41,7 @@ public:
~InstrumentPlayHandle() override = default;
void play(sampleFrame * working_buffer) override;
void play(SampleFrame* working_buffer) override;
bool isFinished() const override
{

View File

@@ -34,6 +34,7 @@ namespace lmms
class InstrumentTrack;
class EnvelopeAndLfoParameters;
class NotePlayHandle;
class SampleFrame;
namespace gui
{
@@ -48,7 +49,7 @@ public:
InstrumentSoundShaping( InstrumentTrack * _instrument_track );
~InstrumentSoundShaping() override = default;
void processAudioBuffer( sampleFrame * _ab, const fpp_t _frames,
void processAudioBuffer( SampleFrame* _ab, const fpp_t _frames,
NotePlayHandle * _n );
enum class Target

View File

@@ -66,7 +66,7 @@ public:
~InstrumentTrack() override;
// used by instrument
void processAudioBuffer( sampleFrame * _buf, const fpp_t _frames,
void processAudioBuffer( SampleFrame* _buf, const fpp_t _frames,
NotePlayHandle * _n );
MidiEvent applyMasterKey( const MidiEvent& event );
@@ -86,7 +86,7 @@ public:
// for capturing note-play-events -> need that for arpeggio,
// filter and so on
void playNote( NotePlayHandle * _n, sampleFrame * _working_buffer );
void playNote( NotePlayHandle * _n, SampleFrame* _working_buffer );
QString instrumentName() const;
const Instrument *instrument() const

View File

@@ -43,6 +43,7 @@ namespace lmms
class Lv2Proc;
class PluginIssue;
class SampleFrame;
/**
Common base class for Lv2 plugins
@@ -118,9 +119,9 @@ protected:
void copyModelsToLmms() const;
//! Copy buffer passed by LMMS into our ports
void copyBuffersFromLmms(const sampleFrame *buf, fpp_t frames);
void copyBuffersFromLmms(const SampleFrame* buf, fpp_t frames);
//! Copy our ports into buffers passed by LMMS
void copyBuffersToLmms(sampleFrame *buf, fpp_t frames) const;
void copyBuffersToLmms(SampleFrame* buf, fpp_t frames) const;
//! Run the Lv2 plugin instance for @param frames frames
void run(fpp_t frames);

View File

@@ -41,6 +41,7 @@
namespace lmms
{
class SampleFrame;
struct ConnectPortVisitor;
using LV2_Evbuf = struct LV2_Evbuf_Impl;
@@ -184,15 +185,15 @@ struct Audio : public VisitablePort<Audio, PortBase>
//! Copy buffer passed by LMMS into our ports
//! @param channel channel index into each sample frame
void copyBuffersFromCore(const sampleFrame *lmmsBuf,
void copyBuffersFromCore(const SampleFrame* lmmsBuf,
unsigned channel, fpp_t frames);
//! Add buffer passed by LMMS into our ports, and halve the result
//! @param channel channel index into each sample frame
void averageWithBuffersFromCore(const sampleFrame *lmmsBuf,
void averageWithBuffersFromCore(const SampleFrame* lmmsBuf,
unsigned channel, fpp_t frames);
//! Copy our ports into buffers passed by LMMS
//! @param channel channel index into each sample frame
void copyBuffersToCore(sampleFrame *lmmsBuf,
void copyBuffersToCore(SampleFrame* lmmsBuf,
unsigned channel, fpp_t frames) const;
bool isSideChain() const { return m_sidechain; }

View File

@@ -49,6 +49,7 @@ namespace lmms
{
class PluginIssue;
class SampleFrame;
// forward declare port structs/enums
namespace Lv2Ports
@@ -134,7 +135,7 @@ public:
* @param num Number of channels we must read from @param buf (starting at
* @p offset)
*/
void copyBuffersFromCore(const sampleFrame *buf,
void copyBuffersFromCore(const SampleFrame* buf,
unsigned firstChan, unsigned num, fpp_t frames);
/**
* Copy our ports into buffers passed by the core
@@ -147,7 +148,7 @@ public:
* @param num Number of channels we must write to @param buf (starting at
* @p offset)
*/
void copyBuffersToCore(sampleFrame *buf, unsigned firstChan, unsigned num,
void copyBuffersToCore(SampleFrame* buf, unsigned firstChan, unsigned num,
fpp_t frames) const;
//! Run the Lv2 plugin instance for @param frames frames
void run(fpp_t frames);

View File

@@ -31,52 +31,54 @@ namespace lmms
{
class ValueBuffer;
class SampleFrame;
namespace MixHelpers
{
bool isSilent( const sampleFrame* src, int frames );
bool isSilent( const SampleFrame* src, int frames );
bool useNaNHandler();
void setNaNHandler( bool use );
bool sanitize( sampleFrame * src, int frames );
bool sanitize( SampleFrame* src, int frames );
/*! \brief Add samples from src to dst */
void add( sampleFrame* dst, const sampleFrame* src, int frames );
void add( SampleFrame* dst, const SampleFrame* src, int frames );
/*! \brief Multiply samples from `dst` by `coeff` */
void multiply(sampleFrame* dst, float coeff, int frames);
void multiply(SampleFrame* dst, float coeff, int frames);
/*! \brief Add samples from src multiplied by coeffSrc to dst */
void addMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );
void addMultiplied( SampleFrame* dst, const SampleFrame* src, float coeffSrc, int frames );
/*! \brief Add samples from src multiplied by coeffSrc to dst, swap inputs */
void addSwappedMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );
void addSwappedMultiplied( SampleFrame* dst, const SampleFrame* src, float coeffSrc, int frames );
/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst */
void addMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames );
void addMultipliedByBuffer( SampleFrame* dst, const SampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames );
/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst */
void addMultipliedByBuffers( sampleFrame* dst, const sampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames );
void addMultipliedByBuffers( SampleFrame* dst, const SampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames );
/*! \brief Same as addMultiplied, but sanitize output (strip out infs/nans) */
void addSanitizedMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames );
void addSanitizedMultiplied( SampleFrame* dst, const SampleFrame* src, float coeffSrc, int frames );
/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst - sanitized version */
void addSanitizedMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames );
void addSanitizedMultipliedByBuffer( SampleFrame* dst, const SampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames );
/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst - sanitized version */
void addSanitizedMultipliedByBuffers( sampleFrame* dst, const sampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames );
void addSanitizedMultipliedByBuffers( SampleFrame* dst, const SampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames );
/*! \brief Add samples from src multiplied by coeffSrcLeft/coeffSrcRight to dst */
void addMultipliedStereo( sampleFrame* dst, const sampleFrame* src, float coeffSrcLeft, float coeffSrcRight, int frames );
void addMultipliedStereo( SampleFrame* dst, const SampleFrame* src, float coeffSrcLeft, float coeffSrcRight, int frames );
/*! \brief Multiply dst by coeffDst and add samples from src multiplied by coeffSrc */
void multiplyAndAddMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffDst, float coeffSrc, int frames );
void multiplyAndAddMultiplied( SampleFrame* dst, const SampleFrame* src, float coeffDst, float coeffSrc, int frames );
/*! \brief Multiply dst by coeffDst and add samples from srcLeft/srcRight multiplied by coeffSrc */
void multiplyAndAddMultipliedJoined( sampleFrame* dst, const sample_t* srcLeft, const sample_t* srcRight, float coeffDst, float coeffSrc, int frames );
void multiplyAndAddMultipliedJoined( SampleFrame* dst, const sample_t* srcLeft, const sample_t* srcRight, float coeffDst, float coeffSrc, int frames );
} // namespace MixHelpers

View File

@@ -56,7 +56,7 @@ class MixerChannel : public ThreadableJob
float m_peakLeft;
float m_peakRight;
sampleFrame * m_buffer;
SampleFrame* m_buffer;
bool m_muteBeforeSolo;
BoolModel m_muteModel;
BoolModel m_soloModel;
@@ -137,10 +137,10 @@ public:
Mixer();
~Mixer() override;
void mixToChannel( const sampleFrame * _buf, mix_ch_t _ch );
void mixToChannel( const SampleFrame* _buf, mix_ch_t _ch );
void prepareMasterMix();
void masterMix( sampleFrame * _buf );
void masterMix( SampleFrame* _buf );
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;

View File

@@ -110,7 +110,7 @@ public:
float currentDetuning() const { return m_baseDetuning->value(); }
/*! Renders one chunk using the attached instrument into the buffer */
void play( sampleFrame* buffer ) override;
void play( SampleFrame* buffer ) override;
/*! Returns whether playback of note is finished and thus handle can be deleted */
bool isFinished() const override

View File

@@ -109,7 +109,7 @@ public:
m_userAntiAliasWaveTable = waveform;
}
void update(sampleFrame* ab, const fpp_t frames, const ch_cnt_t chnl, bool modulator = false);
void update(SampleFrame* ab, const fpp_t frames, const ch_cnt_t chnl, bool modulator = false);
// now follow the wave-shape-routines...
static inline sample_t sinSample( const float _sample )
@@ -282,40 +282,40 @@ private:
/* End Multiband wavetable */
void updateNoSub( sampleFrame * _ab, const fpp_t _frames,
void updateNoSub( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
void updatePM( sampleFrame * _ab, const fpp_t _frames,
void updatePM( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
void updateAM( sampleFrame * _ab, const fpp_t _frames,
void updateAM( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
void updateMix( sampleFrame * _ab, const fpp_t _frames,
void updateMix( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
void updateSync( sampleFrame * _ab, const fpp_t _frames,
void updateSync( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
void updateFM( sampleFrame * _ab, const fpp_t _frames,
void updateFM( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
float syncInit( sampleFrame * _ab, const fpp_t _frames,
float syncInit( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
inline bool syncOk( float _osc_coeff );
template<WaveShape W>
void updateNoSub( sampleFrame * _ab, const fpp_t _frames,
void updateNoSub( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
template<WaveShape W>
void updatePM( sampleFrame * _ab, const fpp_t _frames,
void updatePM( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
template<WaveShape W>
void updateAM( sampleFrame * _ab, const fpp_t _frames,
void updateAM( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
template<WaveShape W>
void updateMix( sampleFrame * _ab, const fpp_t _frames,
void updateMix( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
template<WaveShape W>
void updateSync( sampleFrame * _ab, const fpp_t _frames,
void updateSync( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
template<WaveShape W>
void updateFM( sampleFrame * _ab, const fpp_t _frames,
void updateFM( SampleFrame* _ab, const fpp_t _frames,
const ch_cnt_t _chnl );
template<WaveShape W>

View File

@@ -30,6 +30,13 @@
#include "lmms_basics.h"
namespace lmms
{
class SampleFrame;
}
namespace lmms::gui
{
@@ -67,7 +74,7 @@ protected:
protected slots:
void updateAudioBuffer( const lmms::surroundSampleFrame * buffer );
void updateAudioBuffer(const lmms::SampleFrame* buffer);
private:
bool clips(float level) const;
@@ -76,7 +83,7 @@ private:
QPixmap m_background;
QPointF * m_points;
sampleFrame * m_buffer;
SampleFrame* m_buffer;
bool m_active;
QColor m_leftChannelColor;

View File

@@ -41,6 +41,7 @@ namespace lmms
class Track;
class AudioPort;
class SampleFrame;
class LMMS_EXPORT PlayHandle : public ThreadableJob
{
@@ -105,7 +106,7 @@ public:
{
return m_processingLock.tryLock();
}
virtual void play( sampleFrame* buffer ) = 0;
virtual void play( SampleFrame* buffer ) = 0;
virtual bool isFinished() const = 0;
// returns the frameoffset at the start of the playhandle,
@@ -145,14 +146,14 @@ public:
void releaseBuffer();
sampleFrame * buffer();
SampleFrame* buffer();
private:
Type m_type;
f_cnt_t m_offset;
QThread* m_affinity;
QMutex m_processingLock;
sampleFrame* m_playHandleBuffer;
SampleFrame* m_playHandleBuffer;
bool m_bufferReleased;
bool m_usesBuffer;
AudioPort * m_audioPort;

View File

@@ -47,7 +47,7 @@ public:
return true;
}
void play( sampleFrame* buffer ) override;
void play( SampleFrame* buffer ) override;
bool isFinished() const override;
bool isFromTrack( const Track * _track ) const override;

View File

@@ -37,6 +37,7 @@ namespace lmms
class RemotePlugin;
class SampleFrame;
class ProcessWatcher : public QThread
{
@@ -96,7 +97,7 @@ public:
bool processMessage( const message & _m ) override;
bool process( const sampleFrame * _in_buf, sampleFrame * _out_buf );
bool process( const SampleFrame* _in_buf, SampleFrame* _out_buf );
void processMidiEvent( const MidiEvent&, const f_cnt_t _offset );

View File

@@ -44,6 +44,8 @@
namespace lmms
{
class SampleFrame;
class RemotePluginClient : public RemotePluginBase
{
public:
@@ -58,8 +60,8 @@ public:
bool processMessage( const message & _m ) override;
virtual void process( const sampleFrame * _in_buf,
sampleFrame * _out_buf ) = 0;
virtual void process( const SampleFrame* _in_buf,
SampleFrame* _out_buf ) = 0;
virtual void processMidiEvent( const MidiEvent&, const f_cnt_t /* _offset */ )
{
@@ -342,8 +344,8 @@ void RemotePluginClient::doProcessing()
{
if (m_audioBuffer)
{
process( (sampleFrame *)( m_inputCount > 0 ? m_audioBuffer.get() : nullptr ),
(sampleFrame *)( m_audioBuffer.get() +
process( (SampleFrame*)( m_inputCount > 0 ? m_audioBuffer.get() : nullptr ),
(SampleFrame*)( m_audioBuffer.get() +
( m_inputCount*m_bufferSize ) ) );
}
else

View File

@@ -35,6 +35,7 @@
namespace lmms
{
class SampleFrame;
/** \brief A basic LMMS ring buffer for single-thread use. For thread and realtime safe alternative see LocklessRingBuffer.
*/
@@ -105,7 +106,7 @@ public:
* to a specified destination, and advances the position by one period
* \param dst Destination pointer
*/
void pop( sampleFrame * dst );
void pop( SampleFrame* dst );
// note: ringbuffer position is unaffected by all other read functions beside pop()
@@ -113,27 +114,27 @@ public:
* \param dst Destination pointer
* \param offset Offset in frames against current position, may be negative
*/
void read( sampleFrame * dst, f_cnt_t offset=0 );
void read( SampleFrame* dst, f_cnt_t offset = 0 );
/** \brief Reads a period-sized buffer from the ringbuffer and writes it to a specified destination
* \param dst Destination pointer
* \param offset Offset in milliseconds against current position, may be negative
*/
void read( sampleFrame * dst, float offset );
void read( SampleFrame* dst, float offset );
/** \brief Reads a buffer of specified size from the ringbuffer and writes it to a specified destination
* \param dst Destination pointer
* \param offset Offset in frames against current position, may be negative
* \param length Length in frames of the buffer to read - must not be higher than the size of the ringbuffer!
*/
void read( sampleFrame * dst, f_cnt_t offset, f_cnt_t length );
void read( SampleFrame* dst, f_cnt_t offset, f_cnt_t length );
/** \brief Reads a buffer of specified size from the ringbuffer and writes it to a specified destination
* \param dst Destination pointer
* \param offset Offset in milliseconds against current position, may be negative
* \param length Length in frames of the buffer to read - must not be higher than the size of the ringbuffer!
*/
void read( sampleFrame * dst, float offset, f_cnt_t length );
void read( SampleFrame* dst, float offset, f_cnt_t length );
// write functions
@@ -143,28 +144,28 @@ public:
* \param offset Offset in frames against current position, may *NOT* be negative
* \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer!
*/
void write( sampleFrame * src, f_cnt_t offset=0, f_cnt_t length=0 );
void write( SampleFrame* src, f_cnt_t offset=0, f_cnt_t length=0 );
/** \brief Writes a buffer of sampleframes to the ringbuffer at specified position
* \param src Pointer to the source buffer
* \param offset Offset in milliseconds against current position, may *NOT* be negative
* \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer!
*/
void write( sampleFrame * src, float offset, f_cnt_t length=0 );
void write( SampleFrame* src, float offset, f_cnt_t length=0 );
/** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position
* \param src Pointer to the source buffer
* \param offset Offset in frames against current position, may *NOT* be negative
* \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer!
*/
void writeAdding( sampleFrame * src, f_cnt_t offset=0, f_cnt_t length=0 );
void writeAdding( SampleFrame* src, f_cnt_t offset=0, f_cnt_t length=0 );
/** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position
* \param src Pointer to the source buffer
* \param offset Offset in milliseconds against current position, may *NOT* be negative
* \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer!
*/
void writeAdding( sampleFrame * src, float offset, f_cnt_t length=0 );
void writeAdding( SampleFrame* src, float offset, f_cnt_t length=0 );
/** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with
* a specified multiplier applied to the frames
@@ -173,7 +174,7 @@ public:
* \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer!
* \param level Multiplier applied to the frames before they're written to the ringbuffer
*/
void writeAddingMultiplied( sampleFrame * src, f_cnt_t offset, f_cnt_t length, float level );
void writeAddingMultiplied( SampleFrame* src, f_cnt_t offset, f_cnt_t length, float level );
/** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with
* a specified multiplier applied to the frames
@@ -182,7 +183,7 @@ public:
* \param length Length of the source buffer, if zero, period size is used
* \param level Multiplier applied to the frames before they're written to the ringbuffer
*/
void writeAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level );
void writeAddingMultiplied( SampleFrame* src, float offset, f_cnt_t length, float level );
/** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with
* a specified multiplier applied to the frames, with swapped channels
@@ -191,7 +192,7 @@ public:
* \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer!
* \param level Multiplier applied to the frames before they're written to the ringbuffer
*/
void writeSwappedAddingMultiplied( sampleFrame * src, f_cnt_t offset, f_cnt_t length, float level );
void writeSwappedAddingMultiplied( SampleFrame* src, f_cnt_t offset, f_cnt_t length, float level );
/** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with
* a specified multiplier applied to the frames, with swapped channels
@@ -200,7 +201,7 @@ public:
* \param length Length of the source buffer, if zero, period size is used
* \param level Multiplier applied to the frames before they're written to the ringbuffer
*/
void writeSwappedAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level );
void writeSwappedAddingMultiplied( SampleFrame* src, float offset, f_cnt_t length, float level );
protected slots:
@@ -215,7 +216,7 @@ private:
const fpp_t m_fpp;
sample_rate_t m_samplerate;
size_t m_size;
sampleFrame * m_buffer;
SampleFrame* m_buffer;
volatile unsigned int m_position;
};

View File

@@ -78,7 +78,7 @@ public:
Sample() = default;
Sample(const QByteArray& base64, int sampleRate = Engine::audioEngine()->outputSampleRate());
Sample(const sampleFrame* data, size_t numFrames, int sampleRate = Engine::audioEngine()->outputSampleRate());
Sample(const SampleFrame* data, size_t numFrames, int sampleRate = Engine::audioEngine()->outputSampleRate());
Sample(const Sample& other);
Sample(Sample&& other);
explicit Sample(const QString& audioFile);
@@ -87,7 +87,7 @@ public:
auto operator=(const Sample&) -> Sample&;
auto operator=(Sample&&) -> Sample&;
auto play(sampleFrame* dst, PlaybackState* state, size_t numFrames, float desiredFrequency = DefaultBaseFreq,
auto play(SampleFrame* dst, PlaybackState* state, size_t numFrames, float desiredFrequency = DefaultBaseFreq,
Loop loopMode = Loop::Off) const -> bool;
auto sampleDuration() const -> std::chrono::milliseconds;
@@ -97,7 +97,7 @@ public:
auto toBase64() const -> QString { return m_buffer->toBase64(); }
auto data() const -> const sampleFrame* { return m_buffer->data(); }
auto data() const -> const SampleFrame* { return m_buffer->data(); }
auto buffer() const -> std::shared_ptr<const SampleBuffer> { return m_buffer; }
auto startFrame() const -> int { return m_startFrame.load(std::memory_order_relaxed); }
auto endFrame() const -> int { return m_endFrame.load(std::memory_order_relaxed); }
@@ -117,7 +117,7 @@ public:
void setReversed(bool reversed) { m_reversed.store(reversed, std::memory_order_relaxed); }
private:
void playRaw(sampleFrame* dst, size_t numFrames, const PlaybackState* state, Loop loopMode) const;
void playRaw(SampleFrame* dst, size_t numFrames, const PlaybackState* state, Loop loopMode) const;
void advance(PlaybackState* state, size_t advanceAmount, Loop loopMode) const;
private:

View File

@@ -41,22 +41,22 @@ namespace lmms {
class LMMS_EXPORT SampleBuffer
{
public:
using value_type = sampleFrame;
using reference = sampleFrame&;
using const_reference = const sampleFrame&;
using iterator = std::vector<sampleFrame>::iterator;
using const_iterator = std::vector<sampleFrame>::const_iterator;
using difference_type = std::vector<sampleFrame>::difference_type;
using size_type = std::vector<sampleFrame>::size_type;
using reverse_iterator = std::vector<sampleFrame>::reverse_iterator;
using const_reverse_iterator = std::vector<sampleFrame>::const_reverse_iterator;
using value_type = SampleFrame;
using reference = SampleFrame&;
using const_reference = const SampleFrame&;
using iterator = std::vector<SampleFrame>::iterator;
using const_iterator = std::vector<SampleFrame>::const_iterator;
using difference_type = std::vector<SampleFrame>::difference_type;
using size_type = std::vector<SampleFrame>::size_type;
using reverse_iterator = std::vector<SampleFrame>::reverse_iterator;
using const_reverse_iterator = std::vector<SampleFrame>::const_reverse_iterator;
SampleBuffer() = default;
explicit SampleBuffer(const QString& audioFile);
SampleBuffer(const QString& base64, int sampleRate);
SampleBuffer(std::vector<sampleFrame> data, int sampleRate);
SampleBuffer(std::vector<SampleFrame> data, int sampleRate);
SampleBuffer(
const sampleFrame* data, size_t numFrames, int sampleRate = Engine::audioEngine()->outputSampleRate());
const SampleFrame* data, size_t numFrames, int sampleRate = Engine::audioEngine()->outputSampleRate());
friend void swap(SampleBuffer& first, SampleBuffer& second) noexcept;
auto toBase64() const -> QString;
@@ -82,14 +82,14 @@ public:
auto crbegin() const -> const_reverse_iterator { return m_data.crbegin(); }
auto crend() const -> const_reverse_iterator { return m_data.crend(); }
auto data() const -> const sampleFrame* { return m_data.data(); }
auto data() const -> const SampleFrame* { return m_data.data(); }
auto size() const -> size_type { return m_data.size(); }
auto empty() const -> bool { return m_data.empty(); }
static auto emptyBuffer() -> std::shared_ptr<const SampleBuffer>;
private:
std::vector<sampleFrame> m_data;
std::vector<SampleFrame> m_data;
QString m_audioFile;
sample_rate_t m_sampleRate = Engine::audioEngine()->outputSampleRate();
};

View File

@@ -32,6 +32,7 @@
#include <vector>
#include "lmms_basics.h"
#include "SampleFrame.h"
namespace lmms {
class SampleDecoder
@@ -39,7 +40,7 @@ class SampleDecoder
public:
struct Result
{
std::vector<sampleFrame> data;
std::vector<SampleFrame> data;
int sampleRate;
};

229
include/SampleFrame.h Normal file
View File

@@ -0,0 +1,229 @@
/*
* SampleFrame.h - Representation of a stereo sample
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2024- Michael Gregorius
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LMMS_SAMPLEFRAME_H
#define LMMS_SAMPLEFRAME_H
#include "lmms_basics.h"
#include <array>
namespace lmms
{
class SampleFrame
{
public:
SampleFrame() : SampleFrame(0., 0.)
{
}
explicit SampleFrame(sample_t value) : SampleFrame(value, value)
{
}
SampleFrame(sample_t left, sample_t right) :
m_samples({ left, right })
{
}
sample_t* data()
{
return m_samples.data();
}
const sample_t* data() const
{
return m_samples.data();
}
sample_t& left()
{
return m_samples[0];
}
const sample_t& left() const
{
return m_samples[0];
}
void setLeft(const sample_t& value)
{
m_samples[0] = value;
}
sample_t& right()
{
return m_samples[1];
}
const sample_t& right() const
{
return m_samples[1];
}
void setRight(const sample_t& value)
{
m_samples[1] = value;
}
sample_t& operator[](size_t index)
{
return m_samples[index];
}
const sample_t& operator[](size_t index) const
{
return m_samples[index];
}
SampleFrame operator+(const SampleFrame& other) const
{
return SampleFrame(left() + other.left(), right() + other.right());
}
SampleFrame& operator+=(const SampleFrame& other)
{
auto & l = left();
auto & r = right();
l += other.left();
r += other.right();
return *this;
}
SampleFrame operator*(float value) const
{
return SampleFrame(left() * value, right() * value);
}
SampleFrame& operator*=(float value)
{
setLeft(left() * value);
setRight(right() * value);
return *this;
}
SampleFrame operator*(const SampleFrame& other) const
{
return SampleFrame(left() * other.left(), right() * other.right());
}
void operator*=(const SampleFrame& other)
{
left() *= other.left();
right() *= other.right();
}
sample_t sumOfSquaredAmplitudes() const
{
return left() * left() + right() * right();
}
SampleFrame abs() const
{
return SampleFrame{std::abs(this->left()), std::abs(this->right())};
}
SampleFrame absMax(const SampleFrame& other)
{
const auto a = abs();
const auto b = other.abs();
return SampleFrame(std::max(a.left(), b.left()), std::max(a.right(), b.right()));
}
sample_t average() const
{
return (left() + right()) / 2;
}
void clamp(sample_t low, sample_t high)
{
auto & l = left();
l = std::clamp(l, low, high);
auto & r = right();
r = std::clamp(r, low, high);
}
bool containsInf() const
{
return std::isinf(left()) || std::isinf(right());
}
bool containsNaN() const
{
return std::isnan(left()) || std::isnan(right());
}
private:
std::array<sample_t, DEFAULT_CHANNELS> m_samples;
};
inline void zeroSampleFrames(SampleFrame* buffer, fpp_t frames)
{
// The equivalent of the following operation which yields compiler warnings
// memset(buffer, 0, sizeof(SampleFrame) * frames);
std::fill(buffer, buffer + frames, SampleFrame());
}
inline SampleFrame getAbsPeakValues(SampleFrame* buffer, fpp_t frames)
{
SampleFrame peaks;
for (f_cnt_t i = 0; i < frames; ++i)
{
peaks = peaks.absMax(buffer[i]);
}
return peaks;
}
inline void copyToSampleFrames(SampleFrame* target, const float* source, fpp_t frames)
{
for (fpp_t i = 0; i < frames; ++i)
{
target[i].setLeft(source[2*i]);
target[i].setRight(source[2*i + 1]);
}
}
inline void copyFromSampleFrames(float* target, const SampleFrame* source, fpp_t frames)
{
for (fpp_t i = 0; i < frames; ++i)
{
target[2*i] = source[i].left();
target[2*i + 1] = source[i].right();
}
}
} // namespace lmms
#endif // LMMS_SAMPLEFRAME_H

View File

@@ -55,7 +55,7 @@ public:
}
void play( sampleFrame * buffer ) override;
void play( SampleFrame* buffer ) override;
bool isFinished() const override;
bool isFromTrack( const Track * _track ) const override;

View File

@@ -48,7 +48,7 @@ public:
SampleRecordHandle( SampleClip* clip );
~SampleRecordHandle() override;
void play( sampleFrame * _working_buffer ) override;
void play( SampleFrame* _working_buffer ) override;
bool isFinished() const override;
bool isFromTrack( const Track * _track ) const override;
@@ -58,10 +58,10 @@ public:
private:
virtual void writeBuffer( const sampleFrame * _ab,
virtual void writeBuffer( const SampleFrame* _ab,
const f_cnt_t _frames );
using bufferList = QList<QPair<sampleFrame*, f_cnt_t>>;
using bufferList = QList<QPair<SampleFrame*, f_cnt_t>>;
bufferList m_buffers;
f_cnt_t m_framesRecorded;
TimePos m_minLength;

View File

@@ -36,7 +36,7 @@ class LMMS_EXPORT SampleWaveform
public:
struct Parameters
{
const sampleFrame* buffer;
const SampleFrame* buffer;
size_t size;
float amplification;
bool reversed;

View File

@@ -43,7 +43,7 @@ public:
virtual ~SweepOscillator() = default;
void update( sampleFrame* buf, const fpp_t frames, const float freq1, const float freq2, const float sampleRate )
void update( SampleFrame* buf, const fpp_t frames, const float freq1, const float freq2, const float sampleRate )
{
const float df = freq2 - freq1;
for( fpp_t frame = 0; frame < frames; ++frame )

View File

@@ -33,6 +33,9 @@
#include <cstdint>
#include <array>
#include <cmath>
#include <algorithm>
namespace lmms
{
@@ -48,7 +51,7 @@ using int_sample_t = int16_t; // 16-bit-int-sample
using sample_rate_t = uint32_t; // sample-rate
using fpp_t = int16_t; // frames per period (0-16384)
using f_cnt_t = int32_t; // standard frame-count
using ch_cnt_t = uint8_t; // channel-count (0-SURROUND_CHANNELS)
using ch_cnt_t = uint8_t; // channel-count (0-DEFAULT_CHANNELS)
using bpm_t = uint16_t; // tempo (MIN_BPM to MAX_BPM)
using bitrate_t = uint16_t; // bitrate in kbps
using mix_ch_t = uint16_t; // Mixer-channel (0 to MAX_CHANNEL)
@@ -109,14 +112,6 @@ inline bool typeInfo<float>::isEqual( float x, float y )
constexpr ch_cnt_t DEFAULT_CHANNELS = 2;
constexpr ch_cnt_t SURROUND_CHANNELS =
#define LMMS_DISABLE_SURROUND
#ifndef LMMS_DISABLE_SURROUND
4;
#else
2;
#endif
constexpr char LADSPA_PATH_SEPERATOR =
#ifdef LMMS_BUILD_WIN32
';';
@@ -126,10 +121,6 @@ constexpr char LADSPA_PATH_SEPERATOR =
using sampleFrame = std::array<sample_t, DEFAULT_CHANNELS>;
using surroundSampleFrame = std::array<sample_t, SURROUND_CHANNELS>;
#define LMMS_STRINGIFY(s) LMMS_STR(s)
#define LMMS_STR(PN) #PN