Sine wave: Difference between revisions

From Rosetta Code
Content added Content deleted
(julia example)
No edit summary
Line 8: Line 8:
::# generate a sine wave for 5 seconds
::# generate a sine wave for 5 seconds
::# play sound
::# play sound
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{libheader| Winapi.Windows}}
{{libheader| Winapi.MMSystem}}
Copy of Andreas Rejbrand example found here [https://stackoverflow.com/questions/7742377/how-can-i-generate-continuous-tones-of-varying-frequencies].
<lang Delphi>
program Sine_wave;


{$APPTYPE CONSOLE}

uses
System.SysUtils,
Winapi.Windows,
Winapi.MMSystem;

type
TWaveformSample = integer; // signed 32-bit; -2147483648..2147483647

TWaveformSamples = packed array of TWaveformSample; // one channel

var
Samples: TWaveformSamples;
fmt: TWaveFormatEx;

procedure InitAudioSys;
begin
with fmt do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := 1;
nSamplesPerSec := 44100;
wBitsPerSample := 32;
nAvgBytesPerSec := nChannels * nSamplesPerSec * wBitsPerSample div 8;
nBlockAlign := nChannels * wBitsPerSample div 8;
cbSize := 0;
end;
end;
// Hz // msec

procedure CreatePureSineTone(const AFreq: integer; const ADuration: integer;
const AVolume: double { in [0, 1] });
var
i: Integer;
omega, dt, t: double;
vol: double;
begin
omega := 2 * Pi * AFreq;
dt := 1 / fmt.nSamplesPerSec;
t := 0;
vol := MaxInt * AVolume;
SetLength(Samples, Round((ADuration / 1000) * fmt.nSamplesPerSec));
for i := 0 to high(Samples) do
begin
Samples[i] := round(vol * sin(omega * t));
t := t + dt;
end;
end;

procedure PlaySound;
var
wo: integer;
hdr: TWaveHdr;
begin

if Length(samples) = 0 then
begin
Writeln('Error: No audio has been created yet.');
Exit;
end;

if waveOutOpen(@wo, WAVE_MAPPER, @fmt, 0, 0, CALLBACK_NULL) = MMSYSERR_NOERROR then
try

ZeroMemory(@hdr, sizeof(hdr));
with hdr do
begin
lpData := @samples[0];
dwBufferLength := fmt.nChannels * Length(Samples) * sizeof(TWaveformSample);
dwFlags := 0;
end;

waveOutPrepareHeader(wo, @hdr, sizeof(hdr));
waveOutWrite(wo, @hdr, sizeof(hdr));
sleep(500);

while waveOutUnprepareHeader(wo, @hdr, sizeof(hdr)) = WAVERR_STILLPLAYING do
sleep(100);

finally
waveOutClose(wo);
end;

end;

begin
try
InitAudioSys;
CreatePureSineTone(440, 5000, 0.7);
PlaySound;
except
on E: Exception do
begin
Writeln(E.Classname, ': ', E.Message);
Readln;
end;
end;
end.</lang>
=={{header|Go}}==
=={{header|Go}}==
{{works with|Ubuntu 16.04}}
{{works with|Ubuntu 16.04}}

Revision as of 14:13, 26 August 2020

Sine wave is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.


Task

Generate a sine wave:

  1. you choose the frequency of the wave
  2. generate a sine wave for 5 seconds
  3. play sound

Delphi

Copy of Andreas Rejbrand example found here [1]. <lang Delphi> program Sine_wave;

{$APPTYPE CONSOLE}

uses

 System.SysUtils,
 Winapi.Windows,
 Winapi.MMSystem;

type

 TWaveformSample = integer; // signed 32-bit; -2147483648..2147483647
 TWaveformSamples = packed array of TWaveformSample; // one channel

var

 Samples: TWaveformSamples;
 fmt: TWaveFormatEx;

procedure InitAudioSys; begin

 with fmt do
 begin
   wFormatTag := WAVE_FORMAT_PCM;
   nChannels := 1;
   nSamplesPerSec := 44100;
   wBitsPerSample := 32;
   nAvgBytesPerSec := nChannels * nSamplesPerSec * wBitsPerSample div 8;
   nBlockAlign := nChannels * wBitsPerSample div 8;
   cbSize := 0;
 end;

end;

                                         // Hz                     // msec

procedure CreatePureSineTone(const AFreq: integer; const ADuration: integer;

 const AVolume: double { in [0, 1] });

var

 i: Integer;
 omega, dt, t: double;
 vol: double;

begin

 omega := 2 * Pi * AFreq;
 dt := 1 / fmt.nSamplesPerSec;
 t := 0;
 vol := MaxInt * AVolume;
 SetLength(Samples, Round((ADuration / 1000) * fmt.nSamplesPerSec));
 for i := 0 to high(Samples) do
 begin
   Samples[i] := round(vol * sin(omega * t));
   t := t + dt;
 end;

end;

procedure PlaySound; var

 wo: integer;
 hdr: TWaveHdr;

begin

 if Length(samples) = 0 then
 begin
   Writeln('Error: No audio has been created yet.');
   Exit;
 end;
 if waveOutOpen(@wo, WAVE_MAPPER, @fmt, 0, 0, CALLBACK_NULL) = MMSYSERR_NOERROR then
 try
   ZeroMemory(@hdr, sizeof(hdr));
   with hdr do
   begin
     lpData := @samples[0];
     dwBufferLength := fmt.nChannels * Length(Samples) * sizeof(TWaveformSample);
     dwFlags := 0;
   end;
   waveOutPrepareHeader(wo, @hdr, sizeof(hdr));
   waveOutWrite(wo, @hdr, sizeof(hdr));
   sleep(500);
   while waveOutUnprepareHeader(wo, @hdr, sizeof(hdr)) = WAVERR_STILLPLAYING do
     sleep(100);
 finally
   waveOutClose(wo);
 end;

end;

begin

 try
   InitAudioSys;
   CreatePureSineTone(440, 5000, 0.7);
   PlaySound;
 except
   on E: Exception do
   begin
     Writeln(E.Classname, ': ', E.Message);
     Readln;
   end;
 end;

end.</lang>

Go

Works with: Ubuntu 16.04


Go lacks audio support in its standard library and, whilst there are third party packages that could be used, an easier approach is to invoke the SoX utility's 'play' command as was done in the second Kotlin example. <lang go>package main

import (

   "fmt"
   "os/exec"

)

func main() {

   synthType := "sine"
   duration := "5"
   frequency := "440"
   cmd := exec.Command("play", "-n", "synth", duration, synthType, frequency)
   err := cmd.Run()
   if err != nil {
       fmt.Println(err)
   }

}</lang>

JavaScript

<lang javascript>let ctx = new (window.AudioContext || window.webkitAudioContext)(); let osc = ctx.createOscillator(); osc.frequency.setValueAtTime(440, ctx.currentTime); osc.connect(ctx.destination); osc.start(); osc.stop(ctx.currentTime + 5);</lang>

Julia

PortAudio library version. <lang julia>using PortAudio

function paudio()

   devs = PortAudio.devices()
   devnum = findfirst(x -> x.maxoutchans > 0, devs)
   (devnum == nothing) && error("No output device for audio found")
   return ostream = PortAudioStream(devs[devnum].name, 0, 2)

end

function play(ostream, pitch, durationseconds)

   sinewave(t) = 0.6sin(t) + 0.2sin(2t) + .05sin(8t)
   timesamples = 0:(1 / 44100):(durationseconds * 0.98)
   v = Float64[sinewave(2π * pitch * t) for t in timesamples]
   write(ostream, v)
   sleep(durationseconds * 0.9)

end

play(paudio(), 440.0, 5.0) </lang>

Kotlin

Using Java Sound API

<lang scala>// Version 1.2.41

import javax.sound.sampled.AudioFormat import javax.sound.sampled.AudioSystem import kotlin.math.sin import kotlin.math.PI

fun sineWave(frequency: Int, seconds: Int, sampleRate: Int): ByteArray {

   val samples = seconds * sampleRate
   val result = ByteArray(samples)
   val interval = sampleRate.toDouble() / frequency
   for (i in 0 until samples) {
       val angle = 2.0 * PI * i / interval
       result[i] = (sin(angle) * 127).toByte()
   }
   return result

}

fun main(args: Array<String>) {

   val sampleRate = 44000
   val buffer = sineWave(440, 5, sampleRate)
   val format = AudioFormat(sampleRate.toFloat(), 8, 1, true, true)
   val line = AudioSystem.getSourceDataLine(format)
   with (line) {
       open(format)
       start()
       write(buffer, 0, buffer.size)
       drain()
       close()
   }

}</lang>

Invoking SoX

An easier approach invoking the SoX utility's 'play' command which has this stuff built-in. The following was tested on Ubuntu 16.04. <lang scala>// Version 1.2.41

fun main(args:Array<String>) {

   val synthType = "sine"
   val duration = "5"
   val frequency = "440"
   val pb = ProcessBuilder("play", "-n", "synth", duration, synthType, frequency)
   pb.directory(null)
   val proc = pb.start()
   proc.waitFor()

}</lang>

OCaml

Library: SFML
Library: ocaml-sfml

<lang ocaml>module BA = Bigarray module BA1 = Bigarray.Array1

let () =

 let samples = 44100 in
 let sample_rate = 44100 in
 let amplitude = 30000. in
 
 let raw = BA1.create BA.int16_signed BA.c_layout samples in
 let two_pi = 6.28318 in
 let increment = 440.0 /. 44100.0 in
 let x = ref 0.0 in
 for i = 0 to samples - 1 do
   raw.{i} <- truncate (amplitude *. sin (!x *. two_pi));
   x := !x +. increment;
 done;
 
 let buffer = SFSoundBuffer.loadFromSamples raw 1 sample_rate in
 let snd = SFSound.create () in
 SFSound.setBuffer snd buffer;
 SFSound.setLoop snd true;
 SFSound.play snd;
 while true do
   SFTime.sleep (SFTime.of_milliseconds 100_l);
 done</lang>

To run this code in script mode you can add this at the beginning of the file:

<lang ocaml>#directory "+sfml"

  1. load "bigarray.cma"
  2. load "sfml_system.cma"
  3. load "sfml_audio.cma"</lang>

Then run:

ocaml sine_wave.ml

Or to compile to native code:

ocamlopt -I +sfml bigarray.cmxa sfml_system.cmxa sfml_audio.cmxa sine_wave.ml -o sine_wave.exe

Perl

<lang perl>use Audio::NoiseGen qw(play sine);

Audio::NoiseGen::init() || die 'No access to sound hardware?';

alarm 5; play( gen => sine( freq => 440 ) );</lang>

Phix

<lang Phix>atom k32=NULL, xBeep

procedure beep(integer frequency, duration=5000)

   if platform()=WINDOWS then
       if k32=NULL then
           k32 = open_dll("kernel32.dll")
           xBeep = define_c_proc(k32, "Beep", {C_INT,C_INT})
       end if
       c_proc(xBeep,{frequency,duration})
   elsif platform()=LINUX then

system(sprintf("play -n synth %f sine %d", {duration/1000, frequency}))

   end if

end procedure

beep(prompt_number("Enter Frequency (100..10000 recommended):",{0x25,0x7FFF}))</lang>

Racket

See https://docs.racket-lang.org/rsound/index.html <lang Racket>

  1. lang racket

(require rsound)

440 Hz, 50% volume, 5 seconds

(play (make-tone 440 0.50 (* 5 FRAME-RATE))) </lang>

Raku

(formerly Perl 6)

Works with: Rakudo version 2018.04.01

What a horribly underspecified task. Ah well, gives me lots of wiggle room to cheat in various ways.

<lang perl6>my ($rows,$cols) = qx/stty size/.words; my $v = floor $rows / 2; print "\e[H\e[J", 'Generating sine wave of zero amplitude and zero frequency for 5 seconds...',

 "\e[$v;0H", '_' x $cols;

sleep 5; say "\e[H\e[J", 'No?, ok how about this:';

use SVG; my $filename = 'sine.svg'; my $out = open($filename, :w) orelse .die; $out.say: SVG.serialize(

   svg => [
       width => 400, height => 150, style => 'stroke:rgb(0,0,255)',
       :rect[:width<100%>, :height<100%>, :fill<white>],
       :path[ :fill<none>, :d('M0,25 C36.42,25,63.58,125,100,125 M100,125 C136.42,125,163.58,25,200,25 M200,25 C236.42,25,263.58,125,300,125 M300,125 C336.42,125,363.58,25,400,25') ],
   ],

); close $out; say "Sine wave generated to {$filename.IO.absolute}, better open it quickly..."; sleep 5; unlink $filename; say 'Oops, too late.'; say 'Still no? Ok how about:'; shell 'play -n -c1 synth 5.0 sin %-12';</lang>

REXX

Note:   This REXX program will only work for PC/REXX or Personal REXX. <lang REXX>/*REXX program produces a sine wave (of a specified frequency) for N seconds. */ parse arg freq time . /*obtain optional arguments from the CL*/ if freq== | freq=="," then freq= 880 /*Not specified? Then use the default.*/ if time== | time=="," then time= 5 /* " " " " " " */ call sound freq, time /*invoke a BIF to generate a sine wave.*/ exit 0 /*stick a fork in it, we're all done. */</lang>
<br<

Scala

<lang Scala>import javax.sound.sampled.{AudioFormat, AudioSystem, SourceDataLine}

import scala.math.{Pi, sin}

object SineWave extends App {

 val sampleRate = 44000
 val buffer = beep(440, 5, sampleRate)
 val line: SourceDataLine = AudioSystem.getSourceDataLine(format)
 def format = new AudioFormat(sampleRate.toFloat, 8, 1, true, false)
 def beep(frequency: Int, seconds: Int, sampleRate: Int) = {
   val samples = seconds * sampleRate
   val interval = sampleRate / frequency
   val angle = 2.0 * Pi  / interval
   (0 until samples).map(i => (sin(angle * i) * 127).toByte).toArray
 }
 line.open()
 line.start()
 line.write(buffer, 0, buffer.length)
 line.drain()
 line.close()

}</lang>

zkl

Translation of: Go

Running on Mint Linux <lang zkl>fcn sineWave(durationInSec=5, frequency=440){

  synthType:="sine";
  cmd:="play -n synth %d %s %d".fmt(durationInSec,synthType,frequency);
  s:=System.cmd(cmd);

// if(s!=0) play issued error }

sineWave();</lang>