#!/usr/bin/env raku

use v6;

use NativeCall;
use Audio::PortAudio;

=begin pod

=head1 NAME

play-sine - play a sinewave to the default output stream

=head1 SYNOPSIS

=begin code

play-sine [--frequency=<440>] [--samplerate=<44100>]

=end code

=head1 DESCRIPTION

This plays a constant (if somewhat lo-fi) sine wave to
the default portaudio device.

You can specify the frequency and the samplerate as
command line options.

Originally this version wasn't fast enough to run without
buffer under-runs in the audio driver, but as of 2021.04 it
works fine.

=end pod

multi sub MAIN(:$frequency = 440, :$samplerate = 44100 ) {

    sub gen-sin(Int $sample-rate, Int $frequency) {
        gather {
            loop {
                for (0 .. ($sample-rate/$frequency)).map({ sin(($_/($sample-rate/$frequency)) * (2 * pi))}) -> num32 $val {
                    take $val;
                }
            }
        }
    }

    my $chan = Channel.new;

	my $pa = Audio::PortAudio.new;
	my $st = $pa.open-default-stream(0,2, Audio::PortAudio::Float32, $samplerate, 2048);


    start {
        for gen-sin($samplerate, $frequency).rotor(4096) -> @a {
            my $c = CArray[num32].new(flat @a Z @a);
            $chan.send([$c, 4096]);
        }
    }


	$st.start;
    react {
        whenever $chan -> $ ( $samps, $no) {
              $st.write($samps, $no);
        }
    }
}

# vim: expandtab shiftwidth=4 ft=raku
