Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for offsetting the phase of a signal #183

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions .idea/dasp.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

90 changes: 86 additions & 4 deletions dasp_signal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@
//! To enable all of the above features in a `no_std` context, enable the **all-no-std** feature.

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(core_intrinsics))]

Check warning on line 44 in dasp_signal/src/lib.rs

View workflow job for this annotation

GitHub Actions / cargo-test-all-features-no-std

the feature `core_intrinsics` is internal to the compiler or standard library

#[cfg(not(feature = "std"))]
extern crate alloc;

use core;

Check warning on line 49 in dasp_signal/src/lib.rs

View workflow job for this annotation

GitHub Actions / cargo-test-all-features-no-std

the item `core` is imported redundantly
use core::cell::RefCell;
use dasp_frame::Frame;
use dasp_interpolate::Interpolator;
Expand Down Expand Up @@ -143,6 +143,7 @@
///
/// fn main() {
/// // Infinite signals always return `false`.
/// use dasp_signal::Step;
/// let sine_signal = signal::rate(44_100.0).const_hz(400.0).sine();
/// assert_eq!(sine_signal.is_exhausted(), false);
///
Expand Down Expand Up @@ -960,6 +961,16 @@
phase: Phase<S>,
}

// A signal generator with offset phase.
#[derive(Clone)]
pub struct OffsetPhase<S>
where
S: Signal + Step,
{
step: S,
offset: f64,
}

/// An iterator that yields the sum of the frames yielded by both `other` and `self` in lock-step.
#[derive(Clone)]
pub struct AddAmp<A, B> {
Expand Down Expand Up @@ -1444,10 +1455,7 @@
where
S: Step,
{
Phase {
step: step,
next: 0.0,
}
Phase { step, next: 0.0 }
}

/// Creates a frame `Rate` (aka sample rate) representing the rate at which a signal may be
Expand Down Expand Up @@ -1850,6 +1858,34 @@
pub fn noise_simplex(self) -> NoiseSimplex<Self> {
self.phase().noise_simplex()
}

/// Offsets the phase of a signal by the specified value, between 0.0 and 1.0 by default.
///
/// # Example
///
/// ```rust
/// use dasp_signal::{self as signal, Signal};
///
/// fn main() {
/// let step = signal::rate(4.0).const_hz(1.0).offset_phase(0.25);
/// let mut phase = step.phase();
/// assert_eq!(phase.next(), 0.25);
/// assert_eq!(phase.next(), 0.5);
/// assert_eq!(phase.next(), 0.75);
/// assert_eq!(phase.next(), 0.0);
/// assert_eq!(phase.next(), 0.25);
/// assert_eq!(phase.next(), 0.5);
/// }
/// ```
#[inline]
pub fn offset_phase(self, offset: f64) -> OffsetPhase<Self> {
let rem = 1.0;

OffsetPhase {
step: self,
offset: offset % rem,
}
}
}

impl ConstHz {
Expand Down Expand Up @@ -1882,6 +1918,16 @@
pub fn noise_simplex(self) -> NoiseSimplex<Self> {
self.phase().noise_simplex()
}

#[inline]
pub fn offset_phase(self, offset: f64) -> OffsetPhase<Self> {
let rem = 1.0;

OffsetPhase {
step: self,
offset: offset % rem,
}
}
}

/// Types that may be used to give a phase step size based on some `hz / sample rate`.
Expand Down Expand Up @@ -2097,6 +2143,42 @@
}
}

impl<S: Signal + Step> OffsetPhase<S> {
/// Construct a `Phase` iterator that is incremented via the constant step size, `self.step`,
/// and takes an offset into account.
#[inline]
pub fn phase(self) -> Phase<S> {
Phase {
step: self.step,
next: self.offset,
}
}

/// A composable alternative to the `signal::sine` function.
#[inline]
pub fn sine(self) -> Sine<S> {
self.phase().sine()
}

/// A composable alternative to the `signal::saw` function.
#[inline]
pub fn saw(self) -> Saw<S> {
self.phase().saw()
}

/// A composable alternative to the `signal::square` function.
#[inline]
pub fn square(self) -> Square<S> {
self.phase().square()
}

/// A composable alternative to the `signal::noise_simplex` function.
#[inline]
pub fn noise_simplex(self) -> NoiseSimplex<S> {
self.phase().noise_simplex()
}
}

impl<A, B> Signal for AddAmp<A, B>
where
A: Signal,
Expand Down
Loading