[Solved] Strange Problem with sine

Hi all, got a strange problem I can’t work out. Might (probably) be just me being daft.

I’ve made several sine oscillator classes and not had issues. However lately whenever I’ve done it they keep outputting a sawtooth instead!

Debugger shows that the sine function is in fact just outputting its input (not doing anything) and so I’m instead getting the output of the ramp generator (T). I’ve reinstalled the JUCE libraries and tried different variations (for example, including JUCE header or math header) and still no luck.

Any help appreciated. Below are the Oscillator class and the Processor cpp. Only change in Processor header is the creation of the 2 Osc objects

#pragma once



class Oscillators
{
public:
    void setSampleRate(float host_samplerate) {
        sample_rate = host_samplerate;
        Ts = 1.0f / sample_rate;
    }
    void setFrequency(float host_frequency) {
        F = host_frequency;
    }
    float getSample() {
        T = T + (Ts * F);
        if (T >= 1.0f) {
            T = T - 2.0f;
        }
        return sinf(T);
    }

private:
    float sample_rate = 0.0f;
    float Ts = 0.0f;
    float T = 0.0f;
    float F = 0.0f;
};

And the processor:

#include "PluginProcessor.h"
#include "PluginEditor.h"

//==============================================================================
TemplateAudioProcessor::TemplateAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  juce::AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", juce::AudioChannelSet::stereo(), true)
                     #endif
                       )
#endif
{
}

TemplateAudioProcessor::~TemplateAudioProcessor()
{
}

//==============================================================================
const juce::String TemplateAudioProcessor::getName() const
{
    return JucePlugin_Name;
}

bool TemplateAudioProcessor::acceptsMidi() const
{
   #if JucePlugin_WantsMidiInput
    return true;
   #else
    return false;
   #endif
}

bool TemplateAudioProcessor::producesMidi() const
{
   #if JucePlugin_ProducesMidiOutput
    return true;
   #else
    return false;
   #endif
}

bool TemplateAudioProcessor::isMidiEffect() const
{
   #if JucePlugin_IsMidiEffect
    return true;
   #else
    return false;
   #endif
}

double TemplateAudioProcessor::getTailLengthSeconds() const
{
    return 0.0;
}

int TemplateAudioProcessor::getNumPrograms()
{
    return 1;   // NB: some hosts don't cope very well if you tell them there are 0 programs,
                // so this should be at least 1, even if you're not really implementing programs.
}

int TemplateAudioProcessor::getCurrentProgram()
{
    return 0;
}

void TemplateAudioProcessor::setCurrentProgram (int index)
{
}

const juce::String TemplateAudioProcessor::getProgramName (int index)
{
    return {};
}

void TemplateAudioProcessor::changeProgramName (int index, const juce::String& newName)
{
}

//==============================================================================
void TemplateAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    Osc[0].setSampleRate(sampleRate);
    Osc[1].setSampleRate(sampleRate);


    // Use this method as the place to do any pre-playback
    // initialisation that you need..
}

void TemplateAudioProcessor::releaseResources()
{
    // When playback stops, you can use this as an opportunity to free up any
    // spare memory, etc.
}

#ifndef JucePlugin_PreferredChannelConfigurations
bool TemplateAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
  #if JucePlugin_IsMidiEffect
    juce::ignoreUnused (layouts);
    return true;
  #else
    // This is the place where you check if the layout is supported.
    // In this template code we only support mono or stereo.
    // Some plugin hosts, such as certain GarageBand versions, will only
    // load plugins that support stereo bus layouts.
    if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono()
     && layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
        return false;

    // This checks if the input layout matches the output layout
   #if ! JucePlugin_IsSynth
    if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
        return false;
   #endif

    return true;
  #endif
}
#endif

void TemplateAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
    juce::ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    // In case we have more outputs than inputs, this code clears any output
    // channels that didn't contain input data, (because these aren't
    // guaranteed to be empty - they may contain garbage).
    // This is here to avoid people getting screaming feedback
    // when they first compile a plugin, but obviously you don't need to keep
    // this code if your algorithm always overwrites all the output channels.
    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());

    // This is the place where you'd normally do the guts of your plugin's
    // audio processing...
    // Make sure to reset the state if your inner loop is processing
    // the samples and the outer loop is handling the channels.
    // Alternatively, you can process the samples with the channels
    // interleaved by keeping the same state.
    Osc[0].setFrequency(440);
    Osc[1].setFrequency(440);

  
        for (int spl = 0; spl < buffer.getNumSamples(); spl++) {
            buffer.setSample(0, spl, Osc[0].getSample());
        }

        for (int spl = 0; spl < buffer.getNumSamples(); spl++) {
            buffer.setSample(1, spl, Osc[1].getSample());
        }
    
    

}

//==============================================================================
bool TemplateAudioProcessor::hasEditor() const
{
    return true; // (change this to false if you choose to not supply an editor)
}

juce::AudioProcessorEditor* TemplateAudioProcessor::createEditor()
{
    return new TemplateAudioProcessorEditor (*this);
}

//==============================================================================
void TemplateAudioProcessor::getStateInformation (juce::MemoryBlock& destData)
{
    // You should use this method to store your parameters in the memory block.
    // You could do that either as raw data, or use the XML or ValueTree classes
    // as intermediaries to make it easy to save and load complex data.
}

void TemplateAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
    // You should use this method to restore your parameters from this memory block,
    // whose contents will have been created by the getStateInformation() call.
}

//==============================================================================
// This creates new instances of the plugin..
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
    return new TemplateAudioProcessor();
}

Ok, cosf works sort of…makes a slightly dirty (but nowhere near sawtoothed) sine wave…well, cosine wave. Problem seems to be specific to the 'sin’s

I forgot pi…idiot!!!

1 Like

Glad you found it - we’ve all been there!

1 Like