How to properly use WebAudio and Timer in Dart - dart

I want to create a random sound sequencer, just for learning more about WebAudio and Dart.
My idea is to load some sound examples and play them in random order endlessly.
For that, I've loaded all the files, decoded them in a arraybuffer and put them to play with the following function:
void startAudio()
{
int index=random.nextInt(buffers.length);
print("Audio played [${index}].");
source.buffer=buffers[index];
source.connect(context.destination, 0, 0);
source.start(0);
Timer timer=new Timer(100, this.proceed);
}
void proceed(Timer timer)
{
this.startAudio();
}
The problem is that after some time, the sounds stop playing.
What is going wrong?
Is it the best way to do what I'm trying to do?
If someone wants to test my code, here is the link:
http://cg.usr.sh/Dart/WebAudioTest/WebAudioTest.html

After randomly changing things, I got it working as I was expecting.
import 'dart:html';
import 'dart:math';
import 'dart:async';
class AudioMaker
{
List<String> urls;
AudioContext context;
List<AudioBuffer> buffers;
Random random;
AudioMaker()
{
this.urls=new List<String>();
this.context=new AudioContext();
this.buffers=new List<AudioBuffer>();
this.random=new Random(0);
}
void checkAndStart()
{
if(buffers.length == urls.length)
{
Timer timer=new Timer.repeating(500, this.startAudio);
}
}
void startAudio(Timer timer)
{
int index=random.nextInt(this.buffers.length);
print("Audio played [${index}].");
AudioBufferSourceNode source=context.createBufferSource();
source.buffer=this.buffers[index];
source.connect(context.destination, 0, 0);
source.start(0);
}
void _decodeAudio(url)
{
HttpRequest hr=new HttpRequest.get(url, (req){
this.context.decodeAudioData(req.response, (audio_buff)
{
print("${url} decoded.");
this.buffers.add(audio_buff);
checkAndStart();
}, (evt)
{
print("Error");
});
});
hr.responseType="arraybuffer";
}
void loadAndStart()
{
for(String url in this.urls)
{
this._decodeAudio(url);
}
}
}
main()
{
AudioMaker audioMaker=new AudioMaker();
audioMaker.urls.add("bark.ogg");
audioMaker.urls.add("drip.ogg");
audioMaker.urls.add("glass.ogg");
audioMaker.urls.add("sonar.ogg");
audioMaker.loadAndStart();
}

Related

Uncaught Error: Unsupported operation: ProcessUtils._sleep

import 'dart:io';
void main() {
performTask();
}
void performTask() {
task1();
task2();
task3();
}
void task1() {
print('task1');
}
void task2() {
Duration timeDuration = Duration(seconds: 3);
sleep(timeDuration);
print('task2');
}
void task3() {
print('task3');
}
After executing first function that is task1() it throws an error:
Uncaught Error: Unsupported operation: ProcessUtils._sleep
I just hit the same roadblock! Not sure how to get sleep to work, but i found that using async/await is a bit more predictable:
// Unused import
// import 'dart:io'; // Delete me
void main() {
performTask();
}
// No need for async/await here, just the method in which it's used to await Future.delayed
void performTask() {
task1();
task2();
task3();
}
void task1() {
print('task1');
}
// I'm still a bit new to flutter, but as I understand it, best practice is to use Future<T> myFunction() {...} when defining async/await method.
// In this case <T> is <void> because you're not returning anything!
Future<void> task2() async {
Duration timeDuration = Duration(seconds: 3);
// sleep(timeDuration) // Delete Me
await Future.duration(timeDuration); // replacement for the sleep method, comes from the 'package:flutter/material.dart'
print('task2');
}
void task3() {
print('task3');
}
Credit: How can I "sleep" a Dart program
Since Future.duration doesn't
await Future.delayed(const Duration(seconds: 1));
credit: How can I "sleep" a Dart program

how to simulate keystroke in browser

Hi I cant seem to find the right way to simulate keyevents, I have come across 3 differend options I tried but none of them did work for me.
//V1
import 'dart:async';
import 'dart:html';
void main() {
var stream = KeyEvent.keyPressEvent.forTarget(document.body);
stream.listen((KeyEvent keyEvent){
if(keyEvent.keyCode == KeyCode.ESC) {
// do stuff
}
});
stream.add(new KeyEvent('keypress', keyCode: KeyCode.ESC));
}
-
//V2
import 'dart:html';
myCustomKeyHandler(KeyEvent e) {
print('The charCode is ${e.charCode}');
print('The keyCode is ${e.keyCode}');
}
main() {
var controller = new KeyboardEventController.keydown(document.window);
controller.add(myCustomKeyHandler);
}
-
//V3
import 'dart:html';
myCustomKeyHandler(KeyboardEvent e) {
print('The charCode is ${e.charCode}');
print('The keyCode is ${e.keyCode}');
}
main() {
document.window.add(myCustomKeyHandler, false);
}
the best I get is
Uncaught InvalidStateError: Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.
sources
https://github.com/dart-lang/sdk/issues/17950
How to dispatch an KeyboardEvent with specific KeyCode
https://groups.google.com/a/dartlang.org/forum/#!topic/misc/mgnd1TUGn68

How to create a StreamTransformer in Dart?

Trying to build a custom StreamTransformer class, however a lot of the examples out there seem to be out of date, and the one found in the documentation isn't (what some typed languages might consider anyway) as a class (found here: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:async.StreamTransformer). This doesn't seem like a very Dart-like way of approaching it and rather more of a Javascript-like way (which I'm using Dart to avoid).
Many online sources say this is how you create a StreamTransformer, however there errors when extending it.
class exampleStreamTransformer extends StreamTransformer
{
//... (This won't work)
}
'Implements' seems to be the way to go, along with implementing the bind function needed:
class exampleStreamTransformer implements StreamTransformer
{
Stream bind(Stream stream)
{
//... (Go on to return new stream, etc)
}
}
I can't seem to find any examples of this way, but have thrown something together myself (which is accepted in my IDE, but isn't accepted at runtime, I get a null object error when it tries to use pause getter):
class exampleStreamTransformer implements StreamTransformer
{
StreamController<String> _controller;
StreamSubscription<String> _subscription;
Stream bind(Stream stream)
{
_controller = new StreamController<String>(
onListen: ()
{
_subscription = stream.listen((data)
{
// Transform the data.
_controller.add(data);
},
onError: _controller.addError,
onDone: _controller.close,
cancelOnError: true); // Unsure how I'd pass this in?????
},
onPause: _subscription.pause,
onResume: _subscription.resume,
onCancel: _subscription.cancel,
sync: true
);
return _controller.stream;
}
}
Would like to achieve it this way, as in the 'typed' way of producing the class, any help is much appreciated, thank you.
Why don't you use StreamTransformer.fromHandler():
import 'dart:async';
void handleData(data, EventSink sink) {
sink.add(data*2);
}
void main() {
StreamTransformer doubleTransformer = new StreamTransformer.fromHandlers(handleData: handleData);
StreamController controller = new StreamController();
controller.stream.transform(doubleTransformer).listen((data) {
print('data: $data');
});
controller.add(1);
controller.add(2);
controller.add(3);
}
Output:
data: 2
data: 4
data: 6
Okay. Here's another working example:
import 'dart:async';
class DuplicateTransformer<S, T> implements StreamTransformer<S, T> {
StreamController _controller;
StreamSubscription _subscription;
bool cancelOnError;
// Original Stream
Stream<S> _stream;
DuplicateTransformer({bool sync: false, this.cancelOnError}) {
_controller = new StreamController<T>(onListen: _onListen, onCancel: _onCancel, onPause: () {
_subscription.pause();
}, onResume: () {
_subscription.resume();
}, sync: sync);
}
DuplicateTransformer.broadcast({bool sync: false, bool this.cancelOnError}) {
_controller = new StreamController<T>.broadcast(onListen: _onListen, onCancel: _onCancel, sync: sync);
}
void _onListen() {
_subscription = _stream.listen(onData,
onError: _controller.addError,
onDone: _controller.close,
cancelOnError: cancelOnError);
}
void _onCancel() {
_subscription.cancel();
_subscription = null;
}
/**
* Transformation
*/
void onData(S data) {
_controller.add(data);
_controller.add(data); /* DUPLICATE EXAMPLE!! REMOVE FOR YOUR OWN IMPLEMENTATION!! */
}
/**
* Bind
*/
Stream<T> bind(Stream<S> stream) {
this._stream = stream;
return _controller.stream;
}
}
void main() {
// Create StreamController
StreamController controller = new StreamController.broadcast();
// Transform
Stream s = controller.stream.transform(new DuplicateTransformer.broadcast());
s.listen((data) {
print('data: $data');
}).cancel();
s.listen((data) {
print('data2: $data');
}).cancel();
s.listen((data) {
print('data3: $data');
});
// Simulate data
controller.add(1);
controller.add(2);
controller.add(3);
}
Let me add some notes:
Using implements seems to be the right way here when looking at the source code of other dart internal transformers.
I implemented both versions for regular and a broadcast stream.
In case of a regular stream you can call cancel/pause/resumt directly on the new stream controller because we can only listen once.
If you use a broadcast stream I found out that listen() is only called if there is no one listening already to the stream. onCancel behaves the same. If the last subscriber cancels its subscription, then onCancel is called. That's why it is safe to use the same functions here.
Unlike map, transformers are more powerful and allows you to maintain an internal state, and emit a value whenever you want. It can achieve things map can't do, such as delaying, duplicating values, selectively omitting some values, and etc.
Essentially, the implementation requires a bind method that provides a new stream based on an old stream being passed in, and a cast method that helps with type-checking during run-time.
Here's an over-simplified example of implementing a "TallyTransformer" that transforms a stream of integer values into a stream of sums. For example, if the input stream so far had 1, 1, 1, -2, 0, ..., the output stream would've been 1, 2, 3, 1, 1, ..., i.e. summing all inputs up to this point.
Example usage: stream.transform(TallyTransformer())
class TallyTransformer implements StreamTransformer {
StreamController _controller = StreamController();
int _sum = 0; // sum of all values so far
#override
Stream bind(Stream stream) {
// start listening on input stream
stream.listen((value) {
_sum += value; // add the new value to sum
_controller.add(_sum); // emit current sum to our listener
});
// return an output stream for our listener
return _controller.stream;
}
#override
StreamTransformer<RS, RT> cast<RS, RT>() {
return StreamTransformer.castFrom(this);
}
}
This example is over-simplified (but still works) and does not cover cases such as stream pausing, resuming or canceling. If you run into "Stream has already been listened" error, make sure streams are broadcasting.
https://github.com/dart-lang/sdk/issues/27740#issuecomment-258073139
You can use StreamTransformer.fromHandlers to easily create
transformers that just convert input events to output events.
Example:
new StreamTransformer.fromHandlers(handleData: (String event, EventSink output) {
if (event.startsWith('data:')) {
output.add(JSON.decode(event.substring('data:'.length)));
} else if (event.isNotEmpty) {
output.addError('Unexpected data from CloudBit stream: "$event"');
}
});
If you want to simply transform values using a function like this
int handleData(int data) {
return data * 2;
}
use map method of Stream
stream
.map(handleData)
.listen((data) {
print('data: $data');
});
Full example:
import 'dart:async';
int handleData(int data) {
return data * 2;
}
void main() {
final controller = StreamController<int>();
controller.stream
.map(handleData)
.listen((data) {
print('data: $data');
});
controller.add(1);
controller.add(2);
controller.add(3);
}
See more examples on dart.dev

How do I run a reoccurring function, in Dart?

I'd like to run a function over and over, with a delay in between. How can I do this with Dart?
You can use the Timer class to schedule one-shot and repeating functions.
Repeating
Here is how you run a repeating function:
import 'dart:async';
main() {
const oneSec = Duration(seconds:1);
Timer.periodic(oneSec, (Timer t) => print('hi!'));
}
The Timer takes two arguments, a duration and a function to run. The duration must be an instance of Duration. The callback must take a single parameter, the timer itself.
Canceling a repeating timer
Use timer.cancel() to cancel a repeating timer. This is one reason why timer is passed to the callback run from a repeating timer.
One-shot after a delay
To schedule a one-shot function after a delay (execute once, some time in the future):
import 'dart:async';
main() {
const twentyMillis = Duration(milliseconds:20);
Timer(twentyMillis, () => print('hi!'));
}
Notice the callback for a one-shot timer does not take a parameter.
One-shot as soon as possible
You can also request that a function is run as soon as possible, at least one event-loop tick in the future.
import 'dart:async';
main() {
Timer.run(() => print('hi!'));
}
In HTML
Timers even work in HTML. In fact, window.setTimeout was removed, so Timer is the only way to run a function in the future.
5 Sec Timer Example
bool isStopped = false; //global
sec5Timer() {
Timer.periodic(Duration(seconds: 5), (timer) {
if (isStopped) {
timer.cancel();
}
print("Dekhi 5 sec por por kisu hy ni :/");
});
}
Call from any function
sec5Timer();
Stop from any function
isStopped = true;
To dispose you can use this code or technique.
#override
void initState() {
_timer = new Timer.periodic(widget.refreshRate,
(Timer timer) => _updateDisplayTime(inheritedWidget));
super.initState();
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
https://api.dartlang.org/stable/1.24.3/dart-async/Stream/Stream.periodic.html
import 'dart:async';
StreamSubscription periodicSub;
void main() {
periodicSub = new Stream.periodic(const Duration(milliseconds: 500), (v) => v)
.take(10)
.listen((count) => print('tick $count'));
}
or if the counter isn't required just
import 'dart:async';
StreamSubscription periodicSub;
void main() {
periodicSub = new Stream.periodic(const Duration(milliseconds: 500))
.take(10)
.listen((_) => print('tick'));
}
You can also use Future.delayed and await to delay execution:
Future<Null> delay(int milliseconds) {
return new Future.delayed(new Duration(milliseconds: milliseconds));
}
main() async {
await delay(500);
print('Delayed 500 milliseconds');
}
alternative;
import 'dart:async';
Timer interval(Duration duration, func) {
Timer function() {
Timer timer = new Timer(duration, function);
func(timer);
return timer;
}
return new Timer(duration, function);
}
void main() {
int i = 0;
interval(new Duration(seconds: 1), (timer) {
print(i++);
if (i > 5) timer.cancel();
});
}
Opposite to Timer.periodic and Stream.periodic posting my favorite way to handle such a tasks. The advantages:
the first cycle run instantly
the callback can work longer than
interval without any reentrance headache
Completer<bool> periodic(Duration interval, Function(int cycle) callback) {
final done = Completer<bool>();
() async {
var cycle = 0;
while (!done.isCompleted) {
try {
await callback(cycle);
} catch (e, s) {
log("$e", stackTrace: s);
}
cycle++;
await done.future
.timeout(interval)
.onError((error, stackTrace) => null);
}
}();
return done;
}
main() {
final task = periodic(Duration(seconds: 10), (cycle) async {
/// do the periodic tasks here
});
/// main code here
/// and when going to stop the above periodic call
task.complete(true);
}
Functionally identical code to JavaScript (setInterval, setTimeout, clearInterval and clearTimeout):
// ------------------------------
// Import:
import 'dart:async';
// ------------------------------
// Definitions:
void clearTimeout(Timer timer) {
try {
timer.cancel();
} catch (e) {}
}
Timer setTimeout(VoidCallback fn, int millis) {
Timer timer;
if (millis > 0)
timer = new Timer(new Duration(milliseconds: millis), fn);
else
fn();
return timer;
}
void clearInterval(Timer timer) {
try {
timer.cancel();
} catch (e) {}
}
Timer setInterval(VoidCallback fn, int millis) {
Timer timer;
if (millis > 0)
timer = new Timer.periodic(new Duration(milliseconds: millis), (timer) {
fn();
});
else
fn(); // If millis input is too low, only run function once and stop
return timer;
}
// ---------------------------------
// Example:
int myValue = 0;
Timer counter = setInterval((){ myValue++; }, 50);
setTimeout((){
clearInterval(counter);
}, 5000);

How to seek streaming media in blackberry

I'm using following code to forward streaming media. But it is giving me exception seeking not allowed on media.
Is there any way to seek streaming media in blackberry?
private void forwardPlayer(){
if(isPlaying){
try {
long prevTime = player.getMediaTime()/1000000;
final long newTime = prevTime + 5;
if(newTime <= player.getDuration()/1000000){
Thread t = new Thread(new Runnable() {
public void run() {
try {
player.setMediaTime(newTime * 1000000);
} catch (final MediaException e) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.inform("forward "+e.toString());
}
});
}
}
});
t.start();
}
} catch (final Exception e) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.inform("forward "+e.toString());
}
});
}
}
}
At the risk of stating the obvious, the reason why you cannot seek on your media is almost certainly because it is not possible to do so.
One solution would be to stream the data from your remote media source into a buffer which you can then seek on. Check out Streaming media - Start to finish for reference code.

Resources