浏览代码

Adding Cpp files before modification

Kuba-Cpp 2 年之前
父节点
当前提交
0187b7c70f
共有 3 个文件被更改,包括 405 次插入0 次删除
  1. 315 0
      Imperfector.cpp
  2. 45 0
      Imperfector.h
  3. 45 0
      StdInclude.h

+ 315 - 0
Imperfector.cpp

@@ -0,0 +1,315 @@
+#include "Imperfector.h"
+#include "StdInclude.h"
+#include "Constants.h"
+#include <cmath>
+#include <vector>
+
+namespace {
+
+void SendNoteOffEvent(std::uint8_t iNoteNumber, std::uint16_t iFrameIndex) 
+{
+	JBOX_ASSERT(iNoteNumber < 128);
+	TJBox_NoteEvent event;
+	event.fNoteNumber = iNoteNumber;
+	event.fVelocity = 0;
+	event.fAtFrameIndex = iFrameIndex;
+	JBox_OutputNoteEvent(event);
+}
+	
+	 /// od tego wychodzić - debbug w reaconie dodaje nuty jeden nuty drugi często. 
+	 //Tryb synchronizacji tempo- 
+	 //Drugi tryb bez synchronizacji 
+
+void SendNoteOnEvent(std::uint8_t iNoteNumber, std::uint8_t iVelocity, std::uint16_t iFrameIndex)
+{
+	JBOX_ASSERT(iNoteNumber < 128);
+	TJBox_NoteEvent event;
+	event.fNoteNumber = iNoteNumber;
+	event.fVelocity = iVelocity;
+	event.fAtFrameIndex = iFrameIndex;
+	JBox_OutputNoteEvent(event);
+}
+
+
+std::uint16_t PPQToFrameIndex(TJBox_Float64 iPPQ, TJBox_Float64 iTempo, TJBox_Float64 iSampleRate)
+{
+	std::uint8_t frameIndex = 0;
+	const TJBox_Float64 beatsPerSecond = iTempo / 60;
+	const TJBox_Float64 numPPQsPerSecond = beatsPerSecond * kPPQResolution;
+	const TJBox_Float64 seconds =  iPPQ / numPPQsPerSecond;
+	const TJBox_Float64 frames = seconds * iSampleRate;
+	frameIndex = static_cast<std::uint16_t>(std::max<TJBox_Float64>(0, std::min<TJBox_Float64>(frames, 63)));
+	JBOX_ASSERT(frameIndex >= 0 && frameIndex < kBatchSize);
+	return frameIndex;
+}
+
+
+// skumać  
+
+
+std::int64_t FindNextBeat(std::int64_t iBeatLength, std::int64_t iMaxBeatPosition)
+{
+	JBOX_ASSERT(iBeatLength > 0);
+	const std::int64_t absolutePPQ = static_cast<std::int64_t>((iMaxBeatPosition) / iBeatLength) * iBeatLength;
+	return absolutePPQ;
+}
+
+
+std::uint8_t ConvertCVToNote(TJBox_Value iCVValue)
+{
+	const TJBox_Float64 value = JBox_GetNumber(iCVValue) * 127.f + 0.1f;
+	if (value < 0) {
+		return 0;
+	}
+	else if (value > 127) {
+		return 127;
+	}
+	return static_cast<std::uint8_t>(value);
+}
+
+bool IsInRange(std::int64_t iPosition, const TPPQRange& iRange) {
+	if (iPosition >= iRange.first && iPosition < iRange.second) {
+		return true;
+	}
+	return false;
+}
+
+bool IsEmptyRange(const TPPQRange& iRange) {
+	return iRange.first == iRange.second;
+}
+
+#if DEBUG
+bool IsValidRange(const TPPQRange& iRange) {
+	return iRange.first <= iRange.second;
+}
+#endif // DEBUG
+}
+
+CImperfector::CImperfector(TJBox_Float64 iSampleRate) :
+	fIsPlaying(false),
+	fSampleRate(iSampleRate),
+	fLastStringizeAmountNote(kInvalidNoteNumber),
+	fLastStringizeSpeedNote(kInvalidNoteNumber),
+	fLastPosition(0)
+{
+
+	fCustomPropertiesRef = JBox_GetMotherboardObjectRef("/custom_properties");
+	fTransportRef = JBox_GetMotherboardObjectRef("/transport");
+	fNoteStates = JBox_GetMotherboardObjectRef("/note_states");
+	fEnvironmenRef = JBox_GetMotherboardObjectRef("/environment");
+
+	// CV inputs
+	/*TJBox_ObjectRef numeratorNoteCVRef = JBox_GetMotherboardObjectRef("/cv_inputs/numerator_note_cv");
+	fNumeratorNoteCVInputRef = JBox_MakePropertyRef(numeratorNoteCVRef, "value");
+	fNumeratorNoteCVConnectedRef = JBox_MakePropertyRef(numeratorNoteCVRef, "connected");*/
+
+	TJBox_ObjectRef stringizeAmountNoteCVRef = JBox_GetMotherboardObjectRef("/cv_inputs/stringizeAmount_note_cv"); 
+	fstringizeAmountNoteCVInputRef = JBox_MakePropertyRef(stringizeAmountNoteCVRef, "value");
+	fstringizeAmountNoteCVConnectedRef = JBox_MakePropertyRef(stringizeAmountNoteCVRef, "connected");
+
+	TJBox_ObjectRef stringizeSpeedNoteCVRef = JBox_GetMotherboardObjectRef("/cv_inputs/stringizeSpeed_note_cv");
+	fstringizeSpeedNoteCVInputRef = JBox_MakePropertyRef(stringizeSpeedNoteCVRef, "value");
+	fstringizeSpeedNoteCVConnectedRef = JBox_MakePropertyRef(stringizeSpeedNoteCVRef, "connected");
+
+
+
+	/*TJBox_ObjectRef denominatorNoteCVRef = JBox_GetMotherboardObjectRef("/cv_inputs/denominator_note_cv");
+	fDenominatorNoteCVInputRef = JBox_MakePropertyRef(denominatorNoteCVRef, "value");
+	fDenominatorNoteCVConnectedRef = JBox_MakePropertyRef(denominatorNoteCVRef, "connected");*/
+}
+
+void CImperfector::HandleDiffs(const TJBox_PropertyDiff iPropertyDiffs[], TJBox_UInt32 iDiffCount)
+{
+	for (TJBox_UInt32 i = 0; i < iDiffCount; ++i) {
+		const TJBox_PropertyDiff& diff = iPropertyDiffs[i];
+
+		if (diff.fPropertyRef.fObject == fTransportRef && diff.fPropertyTag == kJBox_TransportPlaying)
+		{
+			fIsPlaying = JBox_GetBoolean(diff.fCurrentValue);
+		}
+		else if (diff.fPropertyRef.fObject == fTransportRef && diff.fPropertyTag == kJBox_TransportLoopEnabled)
+		{
+			fIsLooping = JBox_GetBoolean(diff.fCurrentValue);
+		}
+		else if (diff.fPropertyRef.fObject == fTransportRef && diff.fPropertyTag == kJBox_TransportTempo)
+		{
+			fTempo = JBox_GetNumber(diff.fCurrentValue);
+		}
+		else if (diff.fPropertyRef.fObject == fEnvironmenRef && diff.fPropertyTag == kJBox_EnvironmentPlayerBypassed)
+		{
+			fIsBypassedByHost = JBox_GetBoolean(diff.fCurrentValue);
+		}
+		else if (diff.fPropertyRef.fObject == fCustomPropertiesRef && diff.fPropertyTag == kOnOffTag)
+		{
+			fIsEnabled = JBox_GetBoolean(diff.fCurrentValue);
+		}
+	}
+}
+
+void CImperfector::ForwardNoteEvents(const TJBox_PropertyDiff iPropertyDiffs[], TJBox_UInt32 iDiffCount)
+{
+	for (TJBox_UInt32 i = 0; i < iDiffCount; ++i) {
+		const TJBox_PropertyDiff& propertyDiff = iPropertyDiffs[i];
+		if (propertyDiff.fPropertyRef.fObject == fNoteStates) {
+			const TJBox_NoteEvent& noteEvent = JBox_AsNoteEvent(propertyDiff);
+			JBox_OutputNoteEvent(noteEvent);
+		}
+	}
+}
+
+// Zobaczy jak wyglada event od tego każde nacisniecie korzysta z tej funkcji- player po nacisnieciu opoznienie 
+
+std::uint8_t CImperfector::NoteFromCV(std::uint16_t iDefaultNote,TJBox_PropertyRef iNoteCVConnectedRef, TJBox_PropertyRef iNoteCVInputRef)
+{
+	if (JBox_GetBoolean(JBox_LoadMOMProperty(iNoteCVConnectedRef))) {
+		const TJBox_Value noteCV = JBox_LoadMOMProperty(iNoteCVInputRef);
+		std::uint8_t newNote = ConvertCVToNote(noteCV);
+		return newNote;
+	}
+	return iDefaultNote;
+}
+
+TJBox_Float64 CImperfector::ComputeBatchLengthPPQ() const {
+	const TJBox_Float64 batchLengthPPQ = (kBatchSize / fSampleRate) * ((fTempo / 60) * kPPQResolution);
+	return batchLengthPPQ;
+}
+
+
+// Returns two ranges to support looping
+std::pair<TPPQRange, TPPQRange> CImperfector::ComputePPQRangesForCurrentBatch(TJBox_Float64 iBatchLengthPPQ) const
+{
+	TPPQRange firstRange;
+	TPPQRange secondRange; // Only used if the main seequencer has looped this batch
+
+	TJBox_Float64 batchBeginPPQ = JBox_LoadMOMPropertyAsNumber(fTransportRef, kJBox_TransportPlayPos);
+	const TJBox_Float64 batchEndPPQ = batchBeginPPQ + iBatchLengthPPQ;
+	firstRange.first = static_cast<std::int64_t>(batchBeginPPQ);
+	firstRange.second = static_cast<std::int64_t>(batchEndPPQ);
+
+	const TJBox_Float64 absDiff = std::abs(batchBeginPPQ - fLastPosition);
+	if (absDiff <= (iBatchLengthPPQ * 4)) {
+		// Sequencer pos has (probably) not jumped,
+		// adjust start of current batch to the end of previous batch
+		firstRange.first = fLastPosition;
+	}
+
+	// Handle main sequencer looping
+	if (fIsLooping) {
+		// Did the sequencer loop this batch?
+		const std::int64_t loopEndPPQ = static_cast<std::int64_t>(JBox_LoadMOMPropertyAsNumber(fTransportRef, kJBox_TransportLoopEndPos));
+
+		if (IsInRange(loopEndPPQ, firstRange)) {
+			const std::int64_t loopBeginPPQ = static_cast<std::int64_t>(JBox_LoadMOMPropertyAsNumber(fTransportRef, kJBox_TransportLoopStartPos));
+
+			firstRange.second = loopEndPPQ;
+			secondRange.first = loopBeginPPQ;
+			const TJBox_Float64 secondRangeLength = iBatchLengthPPQ - (loopEndPPQ - batchBeginPPQ);
+			JBOX_ASSERT(secondRangeLength >= 0);
+			secondRange.second = loopBeginPPQ + secondRangeLength;
+
+			if (IsEmptyRange(firstRange)) {
+				// Edge case, the sequencer looped at the end of the batch,
+				// just swap so that the first range is never empty
+				std::swap(firstRange, secondRange);
+			}
+		}
+	}
+
+	JBOX_ASSERT(IsValidRange(firstRange));
+	JBOX_ASSERT(!IsEmptyRange(firstRange) || (IsEmptyRange(firstRange) && IsEmptyRange(secondRange)));
+	JBOX_ASSERT(IsValidRange(secondRange));
+	return std::make_pair(firstRange, secondRange);
+}
+
+void CImperfector::PlayRange(const TPPQRange& iRange) {
+
+	// Output the numerator beat if it happens in the current batch
+	{
+		const TJBox_Float64 stringizeAmount = JBox_LoadMOMPropertyAsNumber(fCustomPropertiesRef, kStringizeAmountTag) + 1;
+		const TJBox_Float64 stringizeSpeed = JBox_LoadMOMPropertyAsNumber(fCustomPropertiesRef, kStringizeSpeedTag) + 1;
+		const std::int64_t beatLength = static_cast<std::int64_t>(kPPQResolution * (stringizeSpeed / stringizeAmount));
+		const std::int64_t nextBeat = FindNextBeat(beatLength, iRange.second);
+		if (IsInRange(nextBeat, iRange)) {
+			const std::int64_t offsetPPQ = nextBeat - iRange.first;
+			const std::uint16_t frameIndex = PPQToFrameIndex(offsetPPQ, fTempo, fSampleRate);
+
+			const std::uint8_t note = NoteFromCV(kDefaultNumeratorNote, fstringizeAmountNoteCVConnectedRef, fstringizeAmountNoteCVInputRef);
+			// Send a note off for the previously played note.
+			// This is a naive way of handling note off events to keep this example minimal.
+			if (fLastStringizeAmountNote != kInvalidNoteNumber) {
+				SendNoteOffEvent(fLastStringizeAmountNote, 0);
+			}
+			fLastStringizeAmountNote = note;
+			SendNoteOnEvent(note, kNoteVelocity, frameIndex);
+		}
+	}
+
+	// Output the denominator beat if it happens in the current batch
+	{
+		const std::int64_t beatLength = kPPQResolution; // Denominator is always on quarter note beats
+		const std::int64_t nextBeat = FindNextBeat(beatLength, iRange.second);
+		if (IsInRange(nextBeat, iRange)) {
+			const std::int64_t offsetPPQ = nextBeat - iRange.first;
+			const std::uint16_t frameIndex = PPQToFrameIndex(offsetPPQ, fTempo, fSampleRate);
+			const std::uint8_t note = NoteFromCV(kDefaultDenominatorNote, fstringizeSpeedNoteCVConnectedRef, fstringizeSpeedNoteCVInputRef);
+			if (fLastStringizeSpeedNote != kInvalidNoteNumber) {
+				SendNoteOffEvent(fLastStringizeSpeedNote, 0);
+			}
+			fLastStringizeSpeedNote = note;
+			SendNoteOnEvent(note, kNoteVelocity, frameIndex);
+		}
+	}
+	fLastPosition = iRange.second;
+}
+
+
+void CImperfector::StringizeAmount(TJBox_Float64 value, char* output) 
+{
+	{
+		const TJBox_Float64 stringizeAmount = JBox_LoadMOMPropertyAsNumber(fCustomPropertiesRef, kStringizeAmountTag) + 1;
+
+	}
+
+
+
+
+
+
+
+}
+
+void CImperfector::RenderBatch(const TJBox_PropertyDiff iPropertyDiffs[], TJBox_UInt32 iDiffCount)
+{
+	HandleDiffs(iPropertyDiffs, iDiffCount);
+
+	if (fIsBypassedByHost) {
+		// We don't have to do anything if the player is bypassed by the host
+		return;
+	}
+
+	if (!fIsEnabled || !fIsPlaying) {
+		if (fLastStringizeAmountNote != kInvalidNoteNumber) {
+			SendNoteOffEvent(fLastStringizeAmountNote, 0);
+			fLastStringizeAmountNote = kInvalidNoteNumber;
+		}
+		if (fLastStringizeSpeedNote != kInvalidNoteNumber) {
+			SendNoteOffEvent(fLastStringizeSpeedNote, 0);
+			fLastStringizeSpeedNote = kInvalidNoteNumber;
+		}
+		// Forward all note events if the player is turned off
+		// or if sequencer is not playing
+		ForwardNoteEvents(iPropertyDiffs, iDiffCount);
+		return;
+	}
+
+	// This player only adds note events, so we simply
+	// forward all incoming events
+	ForwardNoteEvents(iPropertyDiffs, iDiffCount);
+
+	const TJBox_Float64 batchLength = ComputeBatchLengthPPQ();
+	const std::pair<TPPQRange, TPPQRange> ranges = ComputePPQRangesForCurrentBatch(batchLength);
+	PlayRange(ranges.first);
+	if (!IsEmptyRange(ranges.second)) {
+		PlayRange(ranges.second);
+	}
+}

+ 45 - 0
Imperfector.h

@@ -0,0 +1,45 @@
+#pragma once
+#include "Jukebox.h"
+#include <utility>
+
+typedef std::pair<std::int64_t, std::int64_t> TPPQRange;
+
+class CImperfector
+{
+	public: CImperfector(TJBox_Float64 iSampleRate);
+
+    private: void HandleDiffs(const TJBox_PropertyDiff iPropertyDiffs[], TJBox_UInt32 iDiffCount);
+    private: std::uint8_t NoteFromCV(std::uint16_t iDefaultNote,TJBox_PropertyRef iNoteCVConnectedRef, TJBox_PropertyRef iNoteCVInputRef);
+	private: TJBox_Float64 ComputeBatchLengthPPQ() const;
+	private: std::pair<TPPQRange, TPPQRange> ComputePPQRangesForCurrentBatch(TJBox_Float64 iBatchLengthPPQ) const;
+	private: void ForwardNoteEvents(const TJBox_PropertyDiff iPropertyDiffs[], TJBox_UInt32 iDiffCount);
+	private: bool IsPositionInCurrentBatch(std::int64_t iPosition, TPPQRange iCurrentBatchRange) const;
+	private: void PlayRange(const TPPQRange& iRange);
+
+    private: void StringizeAmount(TJBox_Float64 value, char* output);    //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+	
+	public: void RenderBatch(const TJBox_PropertyDiff iPropertyDiffs[], TJBox_UInt32 iDiffCount);
+
+    private: TJBox_ObjectRef fTransportRef;
+    private: TJBox_ObjectRef fCustomPropertiesRef;
+    private: TJBox_ObjectRef fNoteStates;
+    private: TJBox_ObjectRef fEnvironmenRef;
+
+    private: TJBox_PropertyRef fstringizeAmountNoteCVInputRef;
+    private: TJBox_PropertyRef fstringizeAmountNoteCVConnectedRef;
+    private: TJBox_PropertyRef fstringizeSpeedNoteCVInputRef;
+    private: TJBox_PropertyRef fstringizeSpeedNoteCVConnectedRef; 
+
+    private: bool fIsPlaying;
+    private: bool fIsLooping;
+    private: bool fIsBypassedByHost;
+    private: bool fIsEnabled;
+    private: TJBox_Float64 fSampleRate;
+    private: TJBox_Float64 fTempo;
+    private: std::uint8_t fStringizeAmountNote;
+    private: std::uint8_t fStringizeSpeedNote;
+    private: std::uint8_t fLastStringizeAmountNote;
+    private: std::uint8_t fLastStringizeSpeedNote;
+	private: std::int64_t fLastPosition;
+};
+

+ 45 - 0
StdInclude.h

@@ -0,0 +1,45 @@
+#pragma once
+
+
+#ifdef _MSC_VER
+	// This is just a dummy to get intellisense for JukeBox stuff
+	#include "../JukeboxSDK/SDK/API/Jukebox.h"
+	#include "../JukeboxSDK/SDK/API/JukeboxTypes.h" 
+	#ifndef JUKEBOX_VISUALDEBUG
+		// We still want to be able to compile VisualDebug configuration
+		static_assert(false, "This shouldnt be compiled with Visual Studio");
+	#endif //JUKEBOX_VISUALDEBUG
+
+#else
+	#include "Jukebox.h"
+#endif
+
+#ifndef DEBUG
+	#ifdef NDEBUG
+		#define DEBUG 0
+	#else
+		#define DEBUG 1
+	#endif
+#endif
+
+
+#if DEBUG
+	#define CHECKINVARIANT() CheckInvariant(__FUNCTION__)
+	#define CHECKINVARIANT_OTHER() iOther.CheckInvariant("iOther")
+	#define IF_DEBUG(x) x
+	#define ASSERT JBOX_ASSERT
+	#define ASSERT_INVARIANT(x) JBOX_ASSERT_MESSAGE(x, iFunctionName)
+	#define ASSERT_MSG JBOX_ASSERT_MESSAGE
+#else
+	#define CHECKINVARIANT()
+	#define CHECKINVARIANT_OTHER()
+	#define IF_DEBUG(x)
+	#define ASSERT(x)
+	#define ASSERT_INVARIANT(x)
+	#define ASSERT_MSG(x, y)
+#endif
+
+#include <cstring>
+#include <cstdint>
+#include <cmath>
+