AudioContext Mute sound when setValueAtTime foreach still working - class

I have class MorseCodeAudio to create sound for Morse'a code. I'm using window.AudioContext. In my class I have an method with forEach:
morseCode() {
// irrelevant code
this.text.split('').forEach(letter => {
switch(letter) {
case '.':
this.gainNode.gain.setValueAtTime(1, this.time)
this.time += this.period
this.gainNode.gain.setValueAtTime(0, this.time)
this.time += this.period
break
case '-':
this.gainNode.gain.setValueAtTime(1, this.time)
this.time += 3 * this.period
this.gainNode.gain.setValueAtTime(0, this.time)
this.time += this.period
break
case ' ':
this.time += 7 * this.period
break
}
})
}
And method to mute sound:
muteAudioMorse(muteValue) {
if(this.audioCtx.state !== 'closed') this.gainNode.gain.value = muteValue
}
I can't mute the sound because forEach is still executing. If I remove forEach and add one line with sound, like this:
this.gainNode.gain.setValueAtTime(1, 0)
then muteAudioMorse method work correctly.
How I can change gain.value when setValueAtTime from forEach still working?

I "mute" sound by disconnect and connect:
muteAudioMorse(muteValue) {
if(this.audioCtx.state === 'running') {
if(muteValue === 0) this.gainNode.disconnect(this.audioCtx.destination)
else if(muteValue === 1) this.gainNode.connect(this.audioCtx.destination)
}
}

Related

Howler.js Ionic & Capacitor Media Controller

I am writing an application with ionic using "Howler.js" and "Capacitor Music Controls Plugin". With "howler.js", I manage in-app audio files as I want, but I want to add media control feature on statusbar when the application continues to run in the background. As I mentioned, as a result of my research, I found the "Capacitor Music Controls Plugin" and successfully included it in the project. If we come to my problem; Although I can "play / pause" in the app, I pause on the statusbar, but when I press play again it tries to play the same audio file over and over. I share the functions I have written and used below.
Note: As far as I check it on the console, it calls "CapacitorMusicControls" more than once. You can see it in detail below.
https://ibb.co/Ld80LNX
https://ibb.co/6sPcmsd
https://ibb.co/Cs9Nw2L
https://ibb.co/Bj0h9fP
https://ibb.co/2hhqhQW
import { Injectable } from '#angular/core';
import { Howl } from 'howler';
import { Plugins } from '#capacitor/core';
const { CapacitorMusicControls } = Plugins;
#Injectable({
providedIn: 'root'
})
export class GeneralService {
public detail: string;
public activeTrack;
player: Howl = null;
public isPlaying = false;
public progress = 0;
public durationSongHour = Number();
public durationSongMin = Number();
public durationSongSec = Number();
public currentTime = Number();
public currentTimeHour = Number();
public currentTimeSec = Number();
public currentTimeMin = Number();
public durationSong = Number();
public playlist: any;
constructor(
) {
CapacitorMusicControls.addListener('controlsNotification', (info: any) => {
console.log('listener', info.message);
this.handleControlsEvent(info);
});
}
public createMusicControl(track) {
CapacitorMusicControls.create({
track: track.title, // optional, default : ''
artist: track.subtitle, // optional, default : ''
cover: track.img, // optional, default : nothing
// cover can be a local path (use fullpath 'file:///storage/emulated/...', or only 'my_image.jpg' if my_image.jpg is in the www folder of your app)
// or a remote url ('http://...', 'https://...', 'ftp://...')
// hide previous/next/close buttons:
hasPrev: true, // show previous button, optional, default: true
hasNext: true, // show next button, optional, default: true
hasClose: true, // show close button, optional, default: false
// iOS only, optional
duration: 60, // optional, default: 0
elapsed: 10, // optional, default: 0
hasSkipForward: true, //optional, default: false. true value overrides hasNext.
hasSkipBackward: true, //optional, default: false. true value overrides hasPrev.
skipForwardInterval: 15, //optional. default: 15.
skipBackwardInterval: 15, //optional. default: 15.
hasScrubbing: false, //optional. default to false. Enable scrubbing from control center progress bar
// Android only, optional
isPlaying: true, // optional, default : true
dismissable: true, // optional, default : false
// text displayed in the status bar when the notification (and the ticker) are updated
ticker: 'Now playing "Time is Running Out"',
//All icons default to their built-in android equivalents
//The supplied drawable name, e.g. 'media_play', is the name of a drawable found under android/res/drawable* folders
playIcon: 'media_play',
pauseIcon: 'media_pause',
prevIcon: 'media_prev',
nextIcon: 'media_next',
closeIcon: 'media_close',
notificationIcon: 'notification'
}, (res) => {
console.log('res: ' + res);
}, (err) => {
console.log('err: ' + err);
});
}
public start(track) {
if (this.player) {
CapacitorMusicControls.destroy();
this.player.stop();
}
this.player = new Howl({
src: [track.path],
html5: true,
onplay: () => {
console.log('onplay');
this.detail = track;
this.isPlaying = true;
this.createMusicControl(track);
this.activeTrack = track.id;
this.durationSong = this.player.duration();
this.durationSongHour = Math.floor(this.durationSong / 3600);
this.durationSongMin = Math.floor(this.durationSong % 3600 / 60);
this.durationSongSec = Math.floor(this.durationSong % 3600 % 60);
this.acurrenTime();
this.updateProgress();
},
onend: () => {
this.nextSongAfterFinished();
}
});
this.player.play();
}
public tooglePlayer(pause) {
if (pause == "pause") {
this.player.pause();
this.isPlaying = false;
} else if (pause == "play") {
this.player.play();
this.isPlaying = true;
} else {
this.player.pause();
this.isPlaying = false;
}
}
public nextSong(playlist) {
var index = playlist.findIndex(x => x.id === this.activeTrack);
if (index != playlist.length - 1) {
this.start(playlist[index + 1]);
} else {
this.start(playlist[0]);
}
}
public nextSongAfterFinished() {
console.log('sıradaki sıradaki', this.playlist);
var index = this.playlist.findIndex(x => x.id === this.activeTrack);
if (index != this.playlist.length - 1) {
this.start(this.playlist[index + 1]);
} else {
this.start(this.playlist[0]);
}
}
public prevSong(playlist) {
var index = playlist.findIndex(x => x.id === this.activeTrack);
if (index > 0) {
this.start(playlist[index - 1]);
} else {
this.start(playlist[playlist.length - 1]);
}
}
public acurrenTime() {
this.currentTime = this.player.seek();
this.currentTimeHour = Math.floor(this.currentTime / 3600);
this.currentTimeMin = Math.floor(this.currentTime % 3600 / 60);
this.currentTimeSec = Math.floor(this.currentTime % 3600 % 60);
setTimeout(() => {
this.currentTimeHour = Math.floor(this.currentTime / 3600);
this.currentTimeMin = Math.floor(this.currentTime % 3600 / 60);
this.currentTimeSec = Math.floor(this.currentTime % 3600 % 60);
this.acurrenTime();
}, 1000)
}
public seek(range) {
let duration = this.player.duration();
this.player.seek(duration * (range / 100));
}
public updateProgress() {
let seek = this.player.seek();
this.progress = (seek / this.player.duration()) * 100 || 0;
setTimeout(() => {
this.updateProgress();
}, 1000)
}
handleControlsEvent(action) {
const message = action.message;
console.log("message: " + message)
switch (message) {
case 'music-controls-next':
//do something
break;
case 'music-controls-previous':
//do something
break;
case 'music-controls-pause':
this.isPlaying = false;
this.player.pause();
break;
case 'music-controls-play':
this.isPlaying = true;
this.player.play();
break;
case 'music-controls-destroy':
this.player.stop();
this.activeTrack = null;
CapacitorMusicControls.destroy();
console.log('destroyed', message);
break;
// External controls (iOS only)
case 'music-controls-toggle-play-pause':
// do something
break;
case 'music-controls-seek-to':
// do something
break;
case 'music-controls-skip-forward':
// Do something
break;
case 'music-controls-skip-backward':
// Do something
break;
// Headset events (Android only)
// All media button events are listed below
case 'music-controls-media-button':
this.player.pause();
break;
case 'music-controls-headset-unplugged':
// Do something
break;
case 'music-controls-headset-plugged':
this.player.pause();
break;
default:
break;
}
}
}

Continue in Scala for loops

How do i convert below Java code to scala and use continue in for loop, this program remove minimum number of extra closed parenthesis in a given string
input : lee(t(c)o)de)
output : leet(t(c)o)de
public String minRemoveToMakeValid(String s){
StringBuilder sb =new StringBuilder();
in open =0;
for (char c : s.toCharArray()){
if(c == '('){
open++
}
else if(c == ')'){
if(open == 0) continue;
open --;
}
sb.append(c)
}
return sb
}
https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/
import util.control.Breaks._
val searchMe = "peter piper picked a peck of pickled peppers"
var numPs = 0
for (i <- 0 until searchMe.length) {
breakable {
if (searchMe.charAt(i) != 'p') {
break // break out of the 'breakable', continue the outside loop
} else {
numPs += 1
}
}
}
println("Found " + numPs + " p's in the string.")
Try it: https://scastie.scala-lang.org/R9sr95WESLyiKamCHHUVdQ
Im able to get it worked using below code
def minRemoveToMakeValid(s: String): String = {
var open = 0
val sb = new StringBuilder
for (c <- s.toCharArray) {
breakable {
if (c == '(') open += 1
else if (c == ')') {
if (open == 0)break
open -= 1
}
sb.append(c)
}
}
var result = new StringBuilder()
for(i<-sb.length()-1 to 0 by -1)
{
breakable{
open-=1
if(sb.charAt(i) == '(' && open >0) break
result.append(sb.charAt(i))
}
}
result.reverse.toString()
}

Flutter audioplayers triggers onComplete event before the track is actually completed

I am trying to achieve a direct task, I want to autoplay the next track after the current track finishes, but sometimes the onComplete event is triggered before even the track is completed which lead to skip one of the tracks
the package I am using is: audioplayers ^0.14.2
the tracks are fetched from the database they are not local tracks
void play(List<SoundTrack> tracks){
audioPlayer.play(tracks[currentIndex].url);
setIsTalking = true;
audioPlayer.onPlayerCompletion.listen((event) {
if(currentIndex < tracks.length-1) {
next(tracks);
} else {
audioPlayer.release();
setIsTalking = false;
setPlayerState = PlayerState.paused;
}
print('completed this track, current index is' + currentIndex.toString());
});
}
void next(List<SoundTrack> tracks){
setCurrentIndex = currentIndex +1;
play(tracks);
}```
Try something like this:
define
int currentIndex = 0;
and
play(List<String> urlList, int currentIndex) async {
int result = await audioPlayer.play(urlList[currentIndex]);
if (result == 1) {
print('Success: is playing');
} else {
print('Error on audio play');
}
audioPlayer.onPlayerCompletion.listen((event) {
if(currentIndex < urlList.length-1){
currentIndex = currentIndex + 1;
nextTrack(urlList, currentIndex);
print("NEXT AUDIO! $currentIndex");
} else {
print("AUDIO COMPLETED PLAYING");
}
});
}
void nextTrack(List<String> urlList, int currentIndex) {
play(urlList, currentIndex);
}
In your play botton you call
nextTrack(urlList, currentIndex)
I tested and for me it is working.

Scala , java "for" in scala

I don't know how convert java "continue" to scala.
I can use marker from bool + break, but its bad idea
Google did not help :(
It's my first program in scala... yep.. it's horrible
sort java
def sort(in: Array[Int], a:Int, b:Int)
{
var i,j,mode;
double sr=0;
if (a>=b) return; // size =0
for (i=a; i<=b; i++) sr+=in[i];
sr=sr/(b-a+1);
for (i=a, j=b; i <= j;)
{
if (in[i]< sr) { i++; continue; } // left > continue
if (in[j]>=sr) { j--; continue; } // right, continue
int c = in[i]; in[i] = in[j]; in[j]=c;
i++,j--; // swap and continue
}
if (i==a) return;
sort(in,a,j); sort(in,i,b);
}
sort scala...
def SortMerger(in:List[Int], a:Int, b:Int):Unit = {
var i = 0;
var j = 0;
var mode = 0;
var sr = 0.0;
if(a>=b) return;
i=a
while(i<=b)
{
sr+=in.ElementOf(i);
i += 1
}
sr=sr/(b-a+1)
i=a
j=b
while(i<=j)
{
if(in.ElementOf(i)<sr) {
i += 1;
// where continue??? ><
}
}
return
}
Scala has no continue statement, but what you are trying to do can be done with a simple if/else structure.
while(i<=j)
{
if(in(i) < sr) {
i += 1
} else if (in(j) >= sr) {
j -= 1
} else {
int c = in(i)
in(i) = in(j)
in(j) = c
i += 1
j -= 1
}
}
Note that the type of in here should be Array, not List

Change Value of Duplicate Object in NSMutableArray?

I have the method below, which in my Blackjack app will get the value of the hand which is an NSMutableArray. The problem here is that when 2 Ace's are in a hand, it should be a 12, but because it counts Ace's as 11, it results in being 22, which then makes lowValue returned.
How can I make it so that I can check and see if the for loop has already found an Ace and if it finds another, makes the next Ace worth only 1, not 11?
Thanks!
int getHandValue(NSMutableArray *hand) {
int lowValue = 0;
int highValue = 0;
for (KCCard *aCard in hand) {
if (aCard.value == Ace) {
lowValue+= 1;
highValue+= 11;
} else if (aCard.value == Jack || aCard.value == Queen || aCard.value == King) {
lowValue += 10;
highValue += 10;
} else {
lowValue += aCard.value;
highValue += aCard.value;
}
}
return (highValue > 21) ? lowValue : highValue;
}
Perhaps you can add a boolean value before the for loop setting it initially to NO. When an Ace is found then you can break from the for loop after setting the boolean to YES, that way if you encounter another Ace && your boolean value == YES you can handle the case accordingly.
int getHandValue(NSMutableArray *hand) {
int lowValue = 0;
int highValue = 0;
BOOL isFoundAce = NO;
for (KCCard *aCard in hand) {
if (aCard.value == Ace) {
if (isFoundAce) {
lowValue+= 1;
highValue+= 1;
}
else {
lowValue+= 1;
highValue+= 11;
isFoundAce= YES;
}
} else if (aCard.value == Jack || aCard.value == Queen || aCard.value == King) {
lowValue += 10;
highValue += 10;
} else {
lowValue += aCard.value;
highValue += aCard.value;
}
}
return (highValue > 21) ? lowValue : highValue;
}
My example without a redundant code from zsxwing's example:
int getHandValue(NSMutableArray *hand) {
int cardValue = 0;
int aceCount = 0;
for (KCCard *aCard in hand) {
if (aCard.value == Ace) {
aceCount++;
cardValue += 11;
} else if (aCard.value == Jack || aCard.value == Queen || aCard.value == King) {
cardValue += 10;
} else {
cardValue += aCard.value;
}
}
while ((cardValue > 21) && (aceCount > 0)) {
cardValue -= 10;
aceCount--;
}
return cardValue;
}