Sine wave: Difference between revisions
(→{{header|Delphi}}: add Emacs Lisp) |
|||
Line 121: | Line 121: | ||
end; |
end; |
||
end.</lang> |
end.</lang> |
||
=={{header|Emacs Lisp}}== |
|||
Note that this code does not work on Windows because playing sound from Emacs Lisp data variables is not supported there. |
|||
<lang lisp>(defun play-sine (freq dur) |
|||
"Play a sine wave for dur seconds." |
|||
(setq header (concat ; AU header: |
|||
(unibyte-string 46 115 110 100) ; ".snd" magic number |
|||
(unibyte-string 0 0 0 24) ; start of data bytes |
|||
(unibyte-string 255 255 255 255) ; file size is unknown |
|||
(unibyte-string 0 0 0 3) ; 16 bit PCM samples |
|||
(unibyte-string 0 0 172 68) ; 44,100 samples/s |
|||
(unibyte-string 0 0 0 1))) ; mono |
|||
(setq s (apply #'concat header (mapcar (lambda (x) (unibyte-string |
|||
(mod (+ 128 (round (+ 128 (* 127 (sin |
|||
(* 2 pi freq x (/ 44100.0))))))) 256) 0)) |
|||
(number-sequence 0 (* dur 44100))))) |
|||
(play-sound (list 'sound :data s))) |
|||
(play-sine 440 5)</lang> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
{{works with|Ubuntu 16.04}} |
{{works with|Ubuntu 16.04}} |
Revision as of 15:51, 1 May 2022
- Task
Generate a sine wave:
- you choose the frequency of the wave
- generate a sine wave for 5 seconds
- play sound
BASIC256
<lang BASIC256>sound 440, 5000</lang>
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>
Emacs Lisp
Note that this code does not work on Windows because playing sound from Emacs Lisp data variables is not supported there. <lang lisp>(defun play-sine (freq dur)
"Play a sine wave for dur seconds." (setq header (concat ; AU header: (unibyte-string 46 115 110 100) ; ".snd" magic number (unibyte-string 0 0 0 24) ; start of data bytes (unibyte-string 255 255 255 255) ; file size is unknown (unibyte-string 0 0 0 3) ; 16 bit PCM samples (unibyte-string 0 0 172 68) ; 44,100 samples/s (unibyte-string 0 0 0 1))) ; mono (setq s (apply #'concat header (mapcar (lambda (x) (unibyte-string (mod (+ 128 (round (+ 128 (* 127 (sin (* 2 pi freq x (/ 44100.0))))))) 256) 0)) (number-sequence 0 (* dur 44100))))) (play-sound (list 'sound :data s)))
(play-sine 440 5)</lang>
Go
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>
Mathematica/Wolfram Language
<lang Mathematica>EmitSound[Play[Sin[440 2 Pi t], {t, 0, 5}]]</lang>
Nim
Using Sox external player. <lang Nim>import osproc, strutils
proc getIntValue(msg: string; minval, maxval: int): int =
while true: stdout.write msg stdout.flushFile() try: result = stdin.readLine.strip().parseInt() if result notin minval..maxval: echo "Invalid value" else: return except ValueError: echo "Error: invalid value." except EOFError: echo() quit "Quitting.", QuitFailure
let freq = getIntValue("Enter frequency in Hz (40 to 10000): ", 40, 10_000) let duration = 5 let kind = "sine" let args = ["-n", "synth", $duration, $kind, $freq] echo execProcess("play", args = args, options = {poStdErrToStdOut, poUsePath})</lang>
OCaml
<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"
- load "bigarray.cma"
- load "sfml_system.cma"
- 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
without js -- (dll/c_proc, system, prompt_number) 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}))
Racket
See https://docs.racket-lang.org/rsound/index.html <lang Racket>
- lang racket
(require rsound)
- 440 Hz, 50% volume, 5 seconds
(play (make-tone 440 0.50 (* 5 FRAME-RATE))) </lang>
Raku
(formerly Perl 6)
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>
Wren
As Wren-cli doesn't have any built-in audio support, we instead build a .wav file which can then be played using a utility such as rhythmbox or SoX, <lang ecmascript>import "/sound" for Wav
var sineWave = Fn.new { |frequency, seconds, sampleRate|
var samples = seconds * sampleRate var result = List.filled(samples, 0) var interval = sampleRate / frequency for (i in 0...samples) { var angle = 2 * Num.pi * i / interval var b = (angle.sin * 127).truncate result[i] = (b >= 0) ? b : 256 + b } return result
}
var sampleRate = 44000 var buffer = sineWave.call(440, 5, sampleRate) Wav.create("sinewave.wav", buffer, sampleRate)</lang>
Yabasic
<lang Yabasic>// Rosetta Code problem: http://rosettacode.org/wiki/Sine_wave // by Galileo, 05/2022
sub MyBeep(frequency, duration)
local n if duration = 0 duration = 5000 if peek$("os") = "unix" then system("play -n synth " + str$(duration/1000) + " sine " + str$(frequency)) else n = foreign_function_call("kernel32.dll", "uint8","Beep","uint32",frequency,"uint32",duration) end if
end sub
MyBeep(440)</lang>
zkl
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>