package nxm.train.prim;

import nxm.sys.inc.*;
import nxm.sys.lib.*;
import nxm.sys.libm.Waveform;

/** My first primitive. */
public final class primlab7 extends Primitive {
  private DataFile hcb;   // Output file
  private Data     data;  // Data buffer
  private double   size;  // Number of elements
  private double   amp;   // Amplitude of sinewave
  private double   freq;  // Frequency of sinewave
  private double   poff;  // Phase offset for sinewave
  private double   phase; // Phase of sinewave
  private double   chirp; // Chirp offset for sinewave
  private double   dt;    // Time delta (from file).

  public int open() {
    // Get parameters
    freq  = MA.getD("FREQ");
    amp   = MA.getD("AMP");
    poff  = 0.0;
    chirp = 0.0;
    size  = MA.getD("ELEM");

    // Open output file
    hcb = MA.getDataFile("OUT","1000","SF",0); 
    hcb.setXStart(MA.getD("START"));
    hcb.setXDelta(MA.getD("DELTA"));
    hcb.setXUnits(Units.TIME);
    hcb.setSize(size);
    hcb.open();

    // Setup processing
    xfer = MA.getL("/TL",4096);
    hcb.setTimeAt(Time.current());
    dt   = hcb.getXDelta();
    data = hcb.getDataBuffer(xfer);
    todo(size);

    return NORMAL;
  }
  
  public int process() {
    int ndo = todo();
    if (ndo==0) return FINISH;

    data.setSize(ndo);                  // size data object for this pass

    double p  = phase+poff;             // offset phase
    double dp = freq*dt;                // delta phase
    double ddp = chirp*dt*dt;           // delta phase delta

    if (poff!=0) p -= Math.floor(p);    // modulo 1.0 if necessary
    if (dp<0) dp = -dp;                 // no negative freqs except for SINs

    int mode = hcb.spa;
    float[] fbuf = data.castF(false);
    Waveform.sincos(fbuf,amp,p,dp,ndo,mode);
    data.uncast(fbuf,true);
    Time.sleep(dt*ndo);                 // Real-time throttling
    hcb.write(data,ndo);

    phase += dp*ndo;                    // increment phase
    phase -= Math.floor(phase);         // modulo 1.0

    return NORMAL;
  }

  public int close() {
    hcb.close();
    return NORMAL;
  }

  public int restart() {
    hcb.close();
    hcb = MA.getDataFile("OUT",hcb,0);
    hcb.setSize(todo);
    hcb.open();
    data = hcb.getDataBuffer(xfer,FLOAT);
    return NORMAL;
  }

  public int processReady() {
    if (state!=PROCESS) return 0;
    return hcb.processReady(xfer);
  }

  // ADD YOUR METHODS HERE
  /** Sets the amplitude of the sinewave. */
  public void setAmplitude(double value) {
    amp = value;
  }
  
  /** Sets the frequency of the sinewave. */
  public void setFrequency(double value) {
    freq = value;
  }

  /** Gets the amplitude of the sinewave. */
  public double getAmplitude() {
    return amp;
  }
  
  /** Gets the frequency of the sinewave. */
  public double getFrequency() {
    return freq;
  }
}
