Skip to content

A type-safe, header-only C++20 library for frequency handling, modeled after `std::chrono::duration`.

License

Notifications You must be signed in to change notification settings

cleishm/frequency-cpp

Repository files navigation

frequency

A type-safe, header-only C++20 library for frequency handling, modeled after std::chrono::duration.

📚 Full API Documentation

Features

  • Type-safe frequencies with distinct types for different precisions
  • Standard SI units: millihertz, hertz, kilohertz, megahertz, gigahertz, terahertz
  • Integer and floating-point representations for exact or fractional precision
  • Automatic conversions between precisions
  • Lossless implicit conversions (lossy conversions require explicit casts)
  • User-defined literals for concise notation
  • std::format support (when available)
  • Fully constexpr - all operations can be evaluated at compile time

Requirements

  • C++20 compiler (GCC 10+, Clang 10+, MSVC 19.26+)

Installation

CMake FetchContent

include(FetchContent)
FetchContent_Declare(
    frequency
    GIT_REPOSITORY https://github.com/cleishm/frequency-cpp.git
    GIT_TAG v1.0.0
)
FetchContent_MakeAvailable(frequency)

target_link_libraries(your_target PRIVATE frequency::frequency)

vcpkg

vcpkg install cleishm-frequency-cpp
find_package(frequency CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE frequency::frequency)

Manual

Copy include/frequency/frequency.hpp to your project.

Usage

#include <frequency/frequency.hpp>

using namespace freq;
using namespace frequency_literals;

// Basic frequencies
hertz audio_sample_rate{44100};
kilohertz cpu_clock{3200};
megahertz radio_freq{88};
gigahertz wifi{2};

// Using literals
auto f1 = 1000_Hz;
auto f2 = 80_kHz;
auto f3 = 2400_MHz;
auto f4 = 5_GHz;

// Precision control
millihertz precise{44100000};  // 44100 Hz
hertz coarse = hertz(precise);  // explicit lossy conversion
millihertz back = coarse;  // implicit lossless conversion

// Arithmetic
auto sum = 1000_Hz + 500_Hz;     // 1500 Hz
auto diff = 5_GHz - 2400_MHz;    // common type conversion
auto scaled = 100_Hz * 3;        // 300 Hz
auto ratio = 1000_Hz / 100_Hz;   // 10 (scalar)

// Comparisons work across precisions
if (kilohertz{1} == hertz{1000}) {
    // true - same frequency, different precision
}

// String conversion
std::string s = to_string(kilohertz(80));  // "80kHz"

Frequency Types

Type Unit Precision
millihertz mHz 0.001 Hz
hertz Hz 1 Hz
kilohertz kHz 1,000 Hz
megahertz MHz 1,000,000 Hz
gigahertz GHz 1,000,000,000 Hz
terahertz THz 1,000,000,000,000 Hz

All types use int64_t representation by default. For fractional precision, use frequency<double, Precision> (see Floating-Point Frequencies section).

Literals

using namespace frequency_literals;

1000_mHz   // millihertz(1000) = 1 Hz
1000_Hz    // hertz(1000)
80_kHz     // kilohertz(80)
2400_MHz   // megahertz(2400)
5_GHz      // gigahertz(5)
1_THz      // terahertz(1)

Conversion Rules

Conversions follow the same philosophy as std::chrono:

  • Implicit conversions are allowed when lossless (e.g., kilohertzhertz)
  • Explicit conversions are required when lossy (e.g., hertzkilohertz)
// Implicit (lossless) - fine to coarser precision
hertz hz = kilohertz{1};          // OK: 1 kHz → 1000 Hz
millihertz mhz = hertz{1};        // OK: 1 Hz → 1000 mHz

// Explicit required (lossy) - coarse to finer precision with truncation
kilohertz khz = kilohertz(hertz{1500});  // 1500 Hz → 1 kHz (truncates)

// Use frequency_cast for explicit conversions
auto khz2 = frequency_cast<kilohertz>(hertz{2500});  // 2 kHz

Floating-Point Frequencies

The library supports floating-point representations for fractional precision. This is useful for:

  • Musical tuning and audio applications (e.g., concert pitch A = 440.0 Hz)
  • Scientific measurements with sub-unit precision
  • Calculations involving irrational ratios
// Define floating-point frequency types
using hertz_d = frequency<double, std::ratio<1>>;
using kilohertz_d = frequency<double, std::kilo>;
using megahertz_d = frequency<double, std::mega>;

// Musical tuning - concert pitch
hertz_d concert_a{440.0};
hertz_d c_sharp = concert_a.semitone_shift(4);  // 554.37 Hz (major third)

// Scientific measurements
megahertz_d precise_radio{88.5};  // 88.5 MHz FM station
kilohertz_d exact_note{261.626};  // Middle C (C4) in Hz

// Fractional arithmetic
hertz_d f1{1000.5};
hertz_d f2{500.25};
hertz_d sum = f1 + f2;  // 1500.75 Hz

// Mixing integer and floating-point types
hertz int_freq{440};
hertz_d float_freq = hertz_d(int_freq);  // Convert to floating-point
float_freq = float_freq * 1.5;  // 660.0 Hz (perfect fifth interval)

// Octave operations (naturally work with floating-point)
hertz_d a4{440.0};
hertz_d a5 = a4.octave_shift(1.0);     // 880.0 Hz (one octave up)
hertz_d tritone = a4.octave_shift(0.5); // 622.25 Hz (half octave/tritone)

// Note: Modulo operations are disabled for floating-point types
// f1 % 3;  // Compile error - modulo not defined for floating-point

Important considerations:

  • Floating-point frequencies allow fractional values but sacrifice exact arithmetic
  • Implicit conversions between integer and floating-point frequencies follow the same lossless/lossy rules as precision conversions
  • Integer types are preferred when exact values and modulo operations are needed
  • Floating-point types are preferred for calculations involving division, musical intervals, or measurements with fractional precision

Building Tests

cmake -B build -DFREQUENCY_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build

License

MIT License - see LICENSE for details.

About

A type-safe, header-only C++20 library for frequency handling, modeled after `std::chrono::duration`.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •