181 lines
4.1 KiB
C++
Executable file
181 lines
4.1 KiB
C++
Executable file
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
|
//
|
|
// SAANoise.cpp: implementation of the CSAANoise class.
|
|
// One noise generator
|
|
//
|
|
// After construction, it's important to SetSampleRate before
|
|
// trying to use the generator.
|
|
// (Just because the CSAANoise object has a default samplerate
|
|
// doesn't mean you should rely on it)
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "SAASound.h"
|
|
|
|
#include "types.h"
|
|
#include "SAANoise.h"
|
|
#include "defns.h"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CSAANoise::CSAANoise()
|
|
:
|
|
m_nCounter(0),
|
|
m_nCounter_low(0),
|
|
m_nOversample(0),
|
|
m_nCounterLimit_low(1),
|
|
m_bSync(false),
|
|
m_nSampleRate(SAMPLE_RATE_HZ),
|
|
m_nSourceMode(0),
|
|
m_nRand(1)
|
|
{
|
|
_SetClockRate(EXTERNAL_CLK_HZ);
|
|
m_nAdd = m_nAddBase;
|
|
}
|
|
|
|
CSAANoise::CSAANoise(unsigned long seed)
|
|
:
|
|
m_nCounter(0),
|
|
m_nCounter_low(0),
|
|
m_nOversample(0),
|
|
m_nCounterLimit_low(1),
|
|
m_bSync(false),
|
|
m_nSampleRate(SAMPLE_RATE_HZ),
|
|
m_nSourceMode(0),
|
|
m_nRand(seed)
|
|
{
|
|
_SetClockRate(EXTERNAL_CLK_HZ);
|
|
m_nAdd = m_nAddBase;
|
|
}
|
|
|
|
CSAANoise::~CSAANoise()
|
|
{
|
|
// Nothing to do
|
|
}
|
|
|
|
void CSAANoise::_SetClockRate(int nClockRate)
|
|
{
|
|
// at 8MHz the clock rate is 31.250kHZ
|
|
// This is simply the clock rate divided by 256 i.e. 2^8
|
|
// We then shift this by 2^12 (like the Freq) for better
|
|
// period accuracy. So that's the same as shifting by (12-8)
|
|
m_nAddBase = nClockRate << (12 - 8);
|
|
}
|
|
|
|
void CSAANoise::Seed(unsigned long seed)
|
|
{
|
|
m_nRand = seed;
|
|
}
|
|
|
|
void CSAANoise::SetSource(int nSource)
|
|
{
|
|
m_nSourceMode = nSource;
|
|
m_nAdd = m_nAddBase >> m_nSourceMode;
|
|
}
|
|
|
|
void CSAANoise::Trigger(void)
|
|
{
|
|
// Trigger only does anything useful when we're
|
|
// clocking from the frequency generator - i.e
|
|
// if bUseFreqGen = true (i.e. SourceMode = 3)
|
|
|
|
// So if we're clocking from the noise generator
|
|
// clock (ie, SourceMode = 0, 1 or 2) then do nothing
|
|
|
|
// No point actually checking m_bSync here ... because if sync is true,
|
|
// then frequency generators won't actually be generating Trigger pulses
|
|
// so we wouldn't even get here!
|
|
// EXCEPT - cool edge case: if sync is set, then actually the Noise Generator
|
|
// is triggered on EVERY CLOCK PULSE (i.e. 8MHz noise). So indeed it is correct
|
|
// to not check for sync here. NEEDS TEST CASE.
|
|
|
|
if (m_nSourceMode == 3)
|
|
{
|
|
ChangeLevel();
|
|
}
|
|
}
|
|
|
|
void CSAANoise::Tick(void)
|
|
{
|
|
// Tick only does anything useful when we're
|
|
// clocking from the noise generator clock
|
|
// (ie, SourceMode = 0, 1 or 2)
|
|
|
|
// So, if SourceMode = 3 (ie, we're clocking from a
|
|
// frequency generator ==> bUseFreqGen = true)
|
|
// then do nothing
|
|
if ( (!m_bSync) && (m_nSourceMode!=3) )
|
|
{
|
|
m_nCounter += m_nAdd;
|
|
while (m_nCounter >= (m_nSampleRate<<12))
|
|
{
|
|
m_nCounter -= (m_nSampleRate<<12);
|
|
m_nCounter_low++;
|
|
if (m_nCounter_low >= m_nCounterLimit_low)
|
|
{
|
|
m_nCounter_low = 0;
|
|
ChangeLevel();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSAANoise::Sync(bool bSync)
|
|
{
|
|
if (bSync)
|
|
{
|
|
m_nCounter = 0;
|
|
m_nCounter_low = 0;
|
|
}
|
|
m_bSync = bSync;
|
|
}
|
|
|
|
|
|
void CSAANoise::_SetSampleRate(int nSampleRate)
|
|
{
|
|
m_nSampleRate = nSampleRate;
|
|
}
|
|
|
|
|
|
void CSAANoise::_SetOversample(unsigned int oversample)
|
|
{
|
|
// oversample is a power of 2 i.e.
|
|
// if oversample == 2 then 4x oversample
|
|
// if oversample == 6 then 64x oversample
|
|
if (oversample < m_nOversample)
|
|
{
|
|
m_nCounter_low <<= (m_nOversample - oversample);
|
|
}
|
|
else
|
|
{
|
|
m_nCounter_low >>= (oversample - m_nOversample);
|
|
}
|
|
|
|
m_nCounterLimit_low = 1<<oversample;
|
|
m_nOversample = oversample;
|
|
}
|
|
|
|
inline void CSAANoise::ChangeLevel(void)
|
|
{
|
|
/*
|
|
https://www.vogons.org/viewtopic.php?f=9&t=51695
|
|
SAA1099P noise generator as documented by Jepael
|
|
18-bit Galois LFSR
|
|
Feedback polynomial = x^18 + x^11 + x^1
|
|
Period = 2^18-1 = 262143 bits
|
|
Verified to match recorded noise from my SAA1099P
|
|
*/
|
|
|
|
if (m_nRand & 1)
|
|
{
|
|
m_nRand = (m_nRand >> 1) ^ 0x20400;
|
|
}
|
|
else
|
|
{
|
|
m_nRand >>= 1;
|
|
}
|
|
}
|