mirror of https://github.com/probonopd/MiniDexed
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
4.9 KiB
194 lines
4.9 KiB
3 weeks ago
|
|
||
|
//
|
||
|
// utility.h
|
||
|
//
|
||
|
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||
|
// Copyright (C) 2020-2023 Dale Whinham <daleyo@gmail.com>
|
||
|
//
|
||
|
// This file is part of mt32-pi.
|
||
|
//
|
||
|
// mt32-pi is free software: you can redistribute it and/or modify it under the
|
||
|
// terms of the GNU General Public License as published by the Free Software
|
||
|
// Foundation, either version 3 of the License, or (at your option) any later
|
||
|
// version.
|
||
|
//
|
||
|
// mt32-pi is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||
|
// details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License along with
|
||
|
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
|
||
|
//
|
||
|
|
||
|
#ifndef _utility_h
|
||
|
#define _utility_h
|
||
|
|
||
|
#include <circle/string.h>
|
||
|
#include <circle/util.h>
|
||
|
|
||
|
// Macro to extract the string representation of an enum
|
||
|
#define CONFIG_ENUM_VALUE(VALUE, STRING) VALUE,
|
||
|
|
||
|
// Macro to extract the enum value
|
||
|
#define CONFIG_ENUM_STRING(VALUE, STRING) #STRING,
|
||
|
|
||
|
// Macro to declare the enum itself
|
||
|
#define CONFIG_ENUM(NAME, VALUES) enum class NAME { VALUES(CONFIG_ENUM_VALUE) }
|
||
|
|
||
|
// Macro to declare an array of string representations for an enum
|
||
|
#define CONFIG_ENUM_STRINGS(NAME, DATA) static const char* NAME##Strings[] = { DATA(CONFIG_ENUM_STRING) }
|
||
|
|
||
|
namespace Utility
|
||
|
{
|
||
|
// Templated function for clamping a value between a minimum and a maximum
|
||
|
template <class T>
|
||
|
constexpr T Clamp(const T& nValue, const T& nMin, const T& nMax)
|
||
|
{
|
||
|
return (nValue < nMin) ? nMin : (nValue > nMax) ? nMax : nValue;
|
||
|
}
|
||
|
|
||
|
// Templated function for taking the minimum of two values
|
||
|
template <class T>
|
||
|
constexpr T Min(const T& nLHS, const T& nRHS)
|
||
|
{
|
||
|
return nLHS < nRHS ? nLHS : nRHS;
|
||
|
}
|
||
|
|
||
|
// Templated function for taking the maximum of two values
|
||
|
template <class T>
|
||
|
constexpr T Max(const T& nLHS, const T& nRHS)
|
||
|
{
|
||
|
return nLHS > nRHS ? nLHS : nRHS;
|
||
|
}
|
||
|
|
||
|
// Function for performing a linear interpolation of a value
|
||
|
constexpr float Lerp(float nValue, float nMinA, float nMaxA, float nMinB, float nMaxB)
|
||
|
{
|
||
|
return nMinB + (nValue - nMinA) * ((nMaxB - nMinB) / (nMaxA - nMinA));
|
||
|
}
|
||
|
|
||
|
// Return number of elements in an array
|
||
|
template <class T, size_t N>
|
||
|
constexpr size_t ArraySize(const T(&)[N]) { return N; }
|
||
|
|
||
|
// Returns whether some value is a power of 2
|
||
|
template <class T>
|
||
|
constexpr bool IsPowerOfTwo(const T& nValue)
|
||
|
{
|
||
|
return nValue && ((nValue & (nValue - 1)) == 0);
|
||
|
}
|
||
|
|
||
|
// Rounds a number to a nearest multiple; only works for integer values/multiples
|
||
|
template <class T>
|
||
|
constexpr T RoundToNearestMultiple(const T& nValue, const T& nMultiple)
|
||
|
{
|
||
|
return ((nValue + nMultiple / 2) / nMultiple) * nMultiple;
|
||
|
}
|
||
|
|
||
|
// Convert between milliseconds and ticks of a 1MHz clock
|
||
|
template <class T>
|
||
|
constexpr T MillisToTicks(const T& nMillis)
|
||
|
{
|
||
|
return nMillis * 1000;
|
||
|
}
|
||
|
|
||
|
template <class T>
|
||
|
constexpr T TicksToMillis(const T& nTicks)
|
||
|
{
|
||
|
return nTicks / 1000;
|
||
|
}
|
||
|
|
||
|
// Computes the Roland checksum
|
||
|
constexpr u8 RolandChecksum(const u8* pData, size_t nSize)
|
||
|
{
|
||
|
u8 nSum = 0;
|
||
|
for (size_t i = 0; i < nSize; ++i)
|
||
|
nSum = (nSum + pData[i]) & 0x7F;
|
||
|
|
||
|
return 128 - nSum;
|
||
|
}
|
||
|
|
||
|
// Comparators for sorting
|
||
|
namespace Comparator
|
||
|
{
|
||
|
template<class T>
|
||
|
using TComparator = bool (*)(const T&, const T&);
|
||
|
|
||
|
template<class T>
|
||
|
inline bool LessThan(const T& ObjectA, const T& ObjectB)
|
||
|
{
|
||
|
return ObjectA < ObjectB;
|
||
|
}
|
||
|
|
||
|
template<class T>
|
||
|
inline bool GreaterThan(const T& ObjectA, const T& ObjectB)
|
||
|
{
|
||
|
return ObjectA > ObjectB;
|
||
|
}
|
||
|
|
||
|
inline bool CaseInsensitiveAscending(const CString& StringA, const CString& StringB)
|
||
|
{
|
||
|
return strcasecmp(StringA, StringB) < 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Swaps two objects in-place
|
||
|
template<class T>
|
||
|
inline void Swap(T& ObjectA, T& ObjectB)
|
||
|
{
|
||
|
u8 Buffer[sizeof(T)];
|
||
|
memcpy(Buffer, &ObjectA, sizeof(T));
|
||
|
memcpy(&ObjectA, &ObjectB, sizeof(T));
|
||
|
memcpy(&ObjectB, Buffer, sizeof(T));
|
||
|
}
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
// Quicksort partition function (private)
|
||
|
template<class T>
|
||
|
size_t Partition(T* Items, Comparator::TComparator<T> Comparator, size_t nLow, size_t nHigh)
|
||
|
{
|
||
|
const size_t nPivotIndex = (nHigh + nLow) / 2;
|
||
|
T* Pivot = &Items[nPivotIndex];
|
||
|
|
||
|
while (true)
|
||
|
{
|
||
|
while (Comparator(Items[nLow], *Pivot))
|
||
|
++nLow;
|
||
|
|
||
|
while (Comparator(*Pivot, Items[nHigh]))
|
||
|
--nHigh;
|
||
|
|
||
|
if (nLow >= nHigh)
|
||
|
return nHigh;
|
||
|
|
||
|
Swap(Items[nLow], Items[nHigh]);
|
||
|
|
||
|
// Update pointer if pivot was swapped
|
||
|
if (nPivotIndex == nLow)
|
||
|
Pivot = &Items[nHigh];
|
||
|
else if (nPivotIndex == nHigh)
|
||
|
Pivot = &Items[nLow];
|
||
|
|
||
|
++nLow;
|
||
|
--nHigh;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Sorts an array in-place using the Tony Hoare Quicksort algorithm
|
||
|
template <class T>
|
||
|
void QSort(T* Items, Comparator::TComparator<T> Comparator, size_t nLow, size_t nHigh)
|
||
|
{
|
||
|
if (nLow < nHigh)
|
||
|
{
|
||
|
size_t p = Partition(Items, Comparator, nLow, nHigh);
|
||
|
QSort(Items, Comparator, nLow, p);
|
||
|
QSort(Items, Comparator, p + 1, nHigh);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|