Audio overlap loop: Difference between revisions

Added FreeBASIC
(sample implementation in Tcl)
(Added FreeBASIC)
 
(14 intermediate revisions by 6 users not shown)
Line 1:
[[Category:Temporal media]]
{{draft task}}
'''Audio Overlap Loop''' is a program that produces an "echo chamber" effect by playing an audio file several times in an overlapping loop. A repetition level determines the number of times that the file is looped. For the purpose of this task, write a program that takes a parameter for the number of repetitions and plays the file ''loop.wav'' in an overlapping loop according to the number of repetitions.
 
Optionally take parameters for delay between repetitions, and decay (fractional volume reduction between consecutive repetitions).
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{libheader| Winapi.Windows}}
{{libheader| Winapi.MMSystem}}
<syntaxhighlight lang="delphi">
program Audio_Overlap_Loop;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils,
Winapi.Windows,
Winapi.MMSystem;
 
function QueryIntNumber(Msg: string; min, max: Integer): Integer;
var
val: string;
begin
Result := 0;
repeat
Writeln(Msg);
Readln(val);
 
if not TryStrToInt(val, Result) then
begin
Writeln('"', val, '" is not a valid number.');
Continue;
end;
if Result < min then
begin
Writeln('"', val, '" must be greater then ', min);
Continue;
end;
 
if (Result > max) then
begin
Writeln('"', val, '" must be lower then ', max);
Continue;
end;
 
Break;
until True;
end;
 
function QueryFloatNumber(Msg: string; min, max: double): double;
var
val: string;
begin
Result := 0;
repeat
Writeln(Msg);
Readln(val);
// acept ',' ou '.' as decimal separator
val := val.Replace(',',FormatSettings.DecimalSeparator);
val := val.Replace('.',FormatSettings.DecimalSeparator);
if not TryStrToFloat(val, Result) then
begin
Writeln('"', val, '" is not a valid number.');
Continue;
end;
if Result < min then
begin
Writeln('"', val, '" must be greater then ', min);
Continue;
end;
 
if (Result > max) then
begin
Writeln('"', val, '" must be lower then ', max);
Continue;
end;
 
Break;
until True;
end;
 
procedure SetWaveVolume(Volume: Double);
var
Caps: TWAVEOUTCAPS;
aVolume: Cardinal;
VolumeCanal: Word;
begin
VolumeCanal := Trunc(Volume * word(-1) / 100.0);
aVolume := MakeLong(VolumeCanal, VolumeCanal);
if WaveOutGetDevCaps(WAVE_MAPPER, @Caps, sizeof(Caps)) = MMSYSERR_NOERROR then
if Caps.dwSupport and WAVECAPS_VOLUME = WAVECAPS_VOLUME then
WaveOutSetVolume(WAVE_MAPPER, aVolume);
end;
 
procedure Play(music: string; volume: Double = 100.0; delayMs: Cardinal = 0);
begin
SetWaveVolume(volume);
PlaySound(Pchar(music), SND_SYNC, 0);
if delayMs > 0 then
Sleep(delayMs);
end;
 
var
vol: Double = 100.0;
i: Integer;
rep: Integer;
delay: DWORD;
decay: Double;
 
begin
rep := QueryIntNumber('Enter number of repetitions (1 to 20) : ', 1, 20);
delay := QueryIntNumber('Enter delay between repetitions in milliseconds (0 to 1000) : ',
0, 1000);
 
decay := QueryFloatNumber('Enter decay between repetitions (0.01 to 0.99) : ',
0.01, 0.99);
 
for i := 1 to rep do
begin
Play('echo.wav', vol, delay);
vol := vol * (1 - decay);
end;
end.</syntaxhighlight>
{{out}}
<pre>Enter number of repetitions (1 to 20) :
5
Enter delay between repetitions in milliseconds (0 to 1000) :
0
Enter decay between repetitions (0.01 to 0.99) :
0.2</pre>
 
=={{header|FreeBASIC}}==
{{libheader| FMOD}}
[https://www.fmod.com/core Library FMOD]
<syntaxhighlight lang="vbnet">#Include "fmod.bi"
 
Sub PlaySound (nombrearchivo As String, repeticiones As Integer, retardo As Integer, decaimiento As Single)
Dim As Single volumen = 1.0
Dim As Integer canal, sonido
' Initialize FMOD
FSOUND_Init(44100, 32, 0)
For i As Integer = 1 To repeticiones
' Cargar el archivo de sonido
sonido = FSOUND_Sample_Load(FSOUND_FREE, nombrearchivo, FSOUND_NORMAL, 0, 0)
If sonido = 0 Then
Print "Error: Failed to load the sample!"
FSOUND_Close
Exit Sub 'END
End If
' Play the sound at the current volume
canal = FSOUND_PlaySound(FSOUND_FREE, sonido)
FSOUND_SetVolume(canal, volumen * 255) ' FMOD uses a volume range of 0 to 255
' Wait for the specified delay
Sleep retardo
' Apply the decay
volumen *= decaimiento
' Release the sound
FSOUND_Sample_Free(sonido)
Next i
' Close FMOD
FSOUND_Close
End Sub
 
Dim As Integer repeticiones, retardo
Dim As Single decaimiento
 
' Get the parameters from the user
Input "Enter the number of repeticiones: ", repeticiones
Input "Enter the retardo between repeticiones (in milliseconds): ", retardo
Input "Enter the decaimiento factor (between 0 and 1): ", decaimiento
 
' Play the sound
PlaySound("loop.wav", repeticiones, retardo, decaimiento)</syntaxhighlight>
 
=={{header|Go}}==
As Go does not have any audio support in its standard library, this invokes the SoX utility's 'play' command with the appropriate parameters to achieve the 'echo chamber' effect.
<syntaxhighlight lang="go">package main
 
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
"strconv"
)
 
func check(err error) {
if err != nil {
log.Fatal(err)
}
}
 
func main() {
fileName := "loop.wav"
scanner := bufio.NewScanner(os.Stdin)
reps := 0
for reps < 1 || reps > 6 {
fmt.Print("Enter number of repetitions (1 to 6) : ")
scanner.Scan()
input := scanner.Text()
check(scanner.Err())
reps, _ = strconv.Atoi(input)
}
 
delay := 0
for delay < 50 || delay > 500 {
fmt.Print("Enter delay between repetitions in microseconds (50 to 500) : ")
scanner.Scan()
input := scanner.Text()
check(scanner.Err())
delay, _ = strconv.Atoi(input)
}
 
decay := 0.0
for decay < 0.2 || decay > 0.9 {
fmt.Print("Enter decay between repetitions (0.2 to 0.9) : ")
scanner.Scan()
input := scanner.Text()
check(scanner.Err())
decay, _ = strconv.ParseFloat(input, 64)
}
 
args := []string{fileName, "echo", "0.8", "0.7"}
decay2 := 1.0
for i := 1; i <= reps; i++ {
delayStr := strconv.Itoa(i * delay)
decay2 *= decay
decayStr := strconv.FormatFloat(decay2, 'f', -1, 64)
args = append(args, delayStr, decayStr)
}
cmd := exec.Command("play", args...)
err := cmd.Run()
check(err)
}</syntaxhighlight>
 
=={{header|JavaScript}}/{{header|HTML}}==
<langsyntaxhighlight JavaScriptlang="javascript"><script>
var j = prompt("Enter the sound manipulation level you want", "");
for(i=0; i<j; i++) {
document.write("<bgsound src='loop.wav'>")
}
</script></langsyntaxhighlight>
 
 
=={{header|Julia}}==
Uses Julia's ability to run iterations of a 4 loop in separate threads to play a file 4 times, with each play 0.1 seconds out of sync with the previous play. Requires available threads on the CPU at Julia startup.
<syntaxhighlight lang="julia">const soundfile = "loop.wav"
 
if length(ARGS) < 1
println("Usage: give number of repetitions in echo effect as argument to the program.")
else
((repetitions = tryparse(Int, ARGS[1])) != nothing) || (repetitions = 3)
(repetitions < 1) && (repetitions = 3)
(repetitions > Threads.nthreads()) && (repetitions = Threads.nthreads())
 
@Threads.threads for secs in 0.0:0.1:((repetitions - 1) * 0.1)
begin sleep(secs); run(`play "$soundfile"`); end
end
end
</syntaxhighlight>
 
=={{header|Nim}}==
{{trans|Go}}
As in Go version, we use Sox "play" command.
<syntaxhighlight lang="nim">import osproc, strutils
 
proc getValue[T: int | float](msg: string; minval, maxval: T): T =
while true:
stdout.write msg
stdout.flushFile()
try:
result = when T is int: stdin.readLine.strip().parseInt()
else: stdin.readLine.strip().parseFloat()
if result notin minval..maxval:
echo "Invalid value"
else:
return
except ValueError:
echo "Error: invalid value."
except EOFError:
echo()
quit "Quitting.", QuitFailure
 
const FileName = "loop.wav"
let reps = getValue("Enter number of repetitions (1 to 6): ", 1, 6)
let delay = getValue("Enter delay between repetitions in microseconds (50 to 500): ", 50, 500)
let decay = getValue("Enter decay between repetitions (0.2 to 0.9): ", 0.2, 0.9)
 
var args = @[FileName, "echo", "0.8", "0.7"]
var decay2 = 1.0
for i in 1..reps:
decay2 *= decay
args.add $(i * delay)
args.add $decay2
echo execProcess("play", args = args, options = {poStdErrToStdOut, poUsePath})</syntaxhighlight>
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\AudioOverlapLoop.exw
-- =================================
--</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">dl</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">`Download rosetta\bass\ from http://phix.x10.mx/pmwiki/pmwiki.php?n=Main.Bass`</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">get_file_type</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"bass"</span><span style="color: #0000FF;">)=</span><span style="color: #004600;">FILETYPE_DIRECTORY</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dl</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">bass</span><span style="color: #0000FF;">\</span><span style="color: #000000;">bass</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #000000;">BASS_Init</span><span style="color: #0000FF;">(-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">44100</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">5</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">filePlayerHandle</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">BASS_StreamCreateFile</span><span style="color: #0000FF;">(</span><span style="color: #004600;">false</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">`bass\Scream01.mp3`</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">BASS_ChannelPlay</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filePlayerHandle</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0.2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #0000FF;">?</span><span style="color: #008000;">"done"</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
The distributed version also has a loop/wait for all channels to finish playing
before terminating the program, or you could just use sleep() or as above wait_key().
 
=={{header|Tcl}}==
Line 27 ⟶ 337:
Either of these may be desirable in different circumstances, so both are left as an example.
 
<langsyntaxhighlight Tcllang="tcl">package require Tk
package require snack
 
Line 128 ⟶ 438:
 
make_gui
</syntaxhighlight>
</lang>
 
=={{header|Wren}}==
{{trans|Go}}
The ability to call external processes such as ''SoX'' is expected to be added to Wren-cli in the next release. In the meantime, we embed the following Wren script in a C host to complete this task.
<syntaxhighlight lang="wren">/* Audio_overlap_loop.wren */
 
class C {
foreign static getInput(maxSize)
 
foreign static play(args)
}
 
var fileName = "loop.wav"
 
var reps = 0
while (!reps || !reps.isInteger || reps < 1 || reps > 6) {
System.write("Enter number of repetitions (1 to 6) : ")
reps = Num.fromString(C.getInput(1))
}
 
var delay = 0
while (!delay || !delay.isInteger || delay < 50 || delay > 500) {
System.write("Enter delay between repetitions in microseconds (50 to 500) : ")
delay = Num.fromString(C.getInput(3))
}
 
var decay = 0
while (!decay || decay < 0.2 || decay > 0.9) {
System.write("Enter decay between repetitions (0.2 to 0.9) : ")
decay = Num.fromString(C.getInput(5))
}
 
var args = [fileName, "-V1", "echo", "0.8", "0.7"]
var decay2 = 1
for (i in 1..reps) {
var delayS = (i * delay).toString
decay2 = decay2 * decay
var decayS = decay2.toString
args.add(delayS)
args.add(decayS)
}
C.play(args.join(" "))</syntaxhighlight>
<br>
We now embed this in the following C program, compile and run it.
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include "wren.h"
 
void C_getInput(WrenVM* vm) {
int maxSize = (int)wrenGetSlotDouble(vm, 1) + 2;
char input[maxSize];
fgets(input, maxSize, stdin);
__fpurge(stdin);
input[strcspn(input, "\n")] = 0;
wrenSetSlotString(vm, 0, (const char*)input);
}
 
void C_play(WrenVM* vm) {
const char *args = wrenGetSlotString(vm, 1);
char command[strlen(args) + 5];
strcpy(command, "play ");
strcat(command, args);
system(command);
}
 
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "C") == 0) {
if (isStatic && strcmp(signature, "getInput(_)") == 0) return C_getInput;
if (isStatic && strcmp(signature, "play(_)") == 0) return C_play;
}
}
return NULL;
}
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
 
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
 
int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "Audio_overlap_loop.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}</syntaxhighlight>
 
 
{{omit from|Bc}}
Line 134 ⟶ 582:
{{omit from|GUISS}}
{{omit from|Lotus 123 Macro Scripting}}
 
[[Category:Temporal media]]
2,122

edits