giuliomoro@193: /*
giuliomoro@193:  * PulseIn.h
giuliomoro@193:  *
giuliomoro@193:  *  Created on: 4 Feb 2016
giuliomoro@193:  *      Author: giulio
giuliomoro@193:  */
giuliomoro@193: 
giuliomoro@193: #ifndef PULSEIN_H_
giuliomoro@193: #define PULSEIN_H_
giuliomoro@193: 
giuliomoro@301: #include <Bela.h>
giuliomoro@193: #include <vector>
giuliomoro@193: class PulseIn {
giuliomoro@193: private:
giuliomoro@193: 	std::vector<int> _array;
giuliomoro@193: 	int _pulseOnState;
giuliomoro@193: 	int _digitalInput;
giuliomoro@193: 	bool _pulseIsOn;
giuliomoro@193: 	uint64_t _pulseStart;
giuliomoro@193: 	uint64_t _lastContext;
giuliomoro@193: public:
giuliomoro@193: 	PulseIn(){
giuliomoro@193: 		_digitalInput = -1;
giuliomoro@193: 	};
giuliomoro@193: 
giuliomoro@301: 	PulseIn(BelaContext* context, unsigned int digitalInput, int direction=1){
giuliomoro@193: 		init(context, digitalInput, direction);
giuliomoro@193: 	};
giuliomoro@193: 	/**
giuliomoro@193: 	 * Initializes the PulseIn object. Also takes care of initializing the digital pin as input.
giuliomoro@193: 	 *
giuliomoro@193: 	 * If the object has been created with the default constructor, the user will
giuliomoro@193: 	 * need to call init() before calling check() or hasPulsed().
giuliomoro@193: 	 * @param digitalInput the digital input where to activate a pulse detector
giuliomoro@193: 	 * @param direction the direction of the pulse,
giuliomoro@193: 	 *  can be 1 to detect positive pulses, e.g.:( 0 0 0 0 1 1 0 0 0 0 0)
giuliomoro@193: 	 *  or -1 to detect negative pulses, e.g.: ( 1 1 1 1 0 0 1 1 1 1)
giuliomoro@193: 	 */
giuliomoro@301: 	void init(BelaContext* context, unsigned int digitalInput, int direction=1);
giuliomoro@193: 
giuliomoro@193: 	/**
giuliomoro@193: 	 * Detects pulses.
giuliomoro@193: 	 *
giuliomoro@193: 	 * The user does not need to call this method as long as they call hasPulsed() at least once per context.
giuliomoro@193: 	 * The rationale why we check() for pulses in a different method
giuliomoro@193: 	 * than hasPulsed() is because user might not query for hasPulsed() every sample,
giuliomoro@193: 	 * so we are safe so long as they call hasPulsed() or check() at least once per buffer.
giuliomoro@193: 	 * Also, results are cached (i.e.: we do not check() for pulses twice for the same context.
andrewm@311: 	 * context->audioFramesElapsed is used as an identifier.
giuliomoro@193: 	 */
giuliomoro@301: 	void check(BelaContext* context);
giuliomoro@193: 
giuliomoro@193: 	/**
giuliomoro@193: 	 * Looks for the end of a pulse.
giuliomoro@193: 	 *
giuliomoro@301: 	 * @param context the current BelaContext
giuliomoro@193: 	 * @param frame the frame at which to check if a pulse was detected.
giuliomoro@193: 	 * @return the length of the pulse if a pulse ending was detected at sample n, zero otherwise.
giuliomoro@193: 	 */
giuliomoro@301: 	int hasPulsed(BelaContext* context, int frame){//let's leave this in PulseIn.h to allow the compiler to optimize out the call.
andrewm@311: 		if(_lastContext != context->audioFramesElapsed){ // check for pulses in the whole context and cache the result
giuliomoro@193: 			check(context);
giuliomoro@193: 		}
giuliomoro@193: 		return _array[frame];
giuliomoro@193: 	}
giuliomoro@193: 	virtual ~PulseIn();
giuliomoro@193: };
giuliomoro@193: 
giuliomoro@193: #endif /* PULSEIN_H_ */