I would like to know how can I play midi files on mobile app
Ive found two midi libraries, but don't see how to implement function to play midi files
https://pub.dev/packages/flutter_midi
here Im using this package in my app to play sf2 audio, though I can only play single notes at the time, here is code I use to do that
class KeyPage extends StatefulWidget {
#override
_KeyPageState createState() => _KeyPageState();
}
class _KeyPageState extends State<KeyPage> {
//final _flutterMidi = FlutterMidi(); //TODO 1 check TODO 2
#override
void initState() {
if (!kIsWeb) {
load(_value);
} else {
FlutterMidi.prepare(
sf2:
null); //TODO 2 check what to do here with static issue Original line was:
// _flutterMidi.prepare(sf2: null);
}
super.initState();
}
void load(String asset) async {
print("Loading File...");
FlutterMidi.unmute();
ByteData _byte = await rootBundle.load(asset);
// 'assets/sf2/SmallTimGM6mb.sf2';
// 'assets/sf2/Piano1.sf2';
FlutterMidi.prepare(sf2: _byte, name: _value.replaceAll("assets/sf2/", ""));
}
https://pub.dev/packages/dart_midi
didn't yet try this package, but from reading it I don't see function in it to play midi file, though language they use is new to me, so I guess this library does that, but I don't understand how
Thank
Here's my implementation using Flutter_midi.
I've used a timer to play the whole sequence of notes, one after the another.
For it to work you need to provide the number of notes you want to play and the time between them.
This does work on the IOS emulator, but I want to say that Flutter_midi contains some deprecated code and it doesn't provide the methods to play a full song in midi format.
For example it is not possible to set the velocity of the notes.
I have implemented this solution anyway, but I personally do not recommend this package.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late FlutterMidi fm;
final songFile = 'assets/Piano.sf2';
#override
void initState() {
super.initState();
fm = FlutterMidi();
_load(songFile);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('MidiPlayer'),
),
body: Center(
child: TextButton(
onPressed: () {
_playSong(
timing: 100,
notes: 30,
);
},
child: const Text('Play'),
),
),
);
}
void _load(String asset) async {
fm.unmute();
ByteData _byte = await rootBundle.load(asset);
fm.prepare(sf2: _byte, name: songFile.replaceAll('assets/', ''));
}
void _playSong({
required int timing, //Time between notes
required int notes, //Number of notes to be played
}) {
var note = 0;
Timer.periodic(Duration(milliseconds: timing), (timer) {
//You played the last note
if (note == notes) {
fm.stopMidiNote(midi: note - 1);
timer.cancel();
return;
}
//Interrupt the previous note
if (note > 0) {
fm.stopMidiNote(midi: note - 1);
}
//Play the current note and increase the counter
fm.playMidiNote(midi: note++);
});
}
}
Related
I am using the singalR package in order to use websocket in my application. During the writing of my program, I was advised to use await hubconnection.start only once and throughout the whole application. Is it possible? I thought that I could run this task somehow in the background and not make every websocket request start every time I want to use some kind of request. Is this possible or is this the wrong idea?
now I an trying to split up the whole thing and found out that in initState we can create method which will be start first before all others code in app, so I decided to split it up like that(in educational purpose I declaired connection setting globally in my file)
final httpConnectionOptions = HttpConnectionOptions(
accessTokenFactory: () => SharedPreferenceService().loginWithToken(),
skipNegotiation: true,
transport: HttpTransportType.WebSockets);
final hubConnection = HubConnectionBuilder()
.withUrl(
'http://secureLink/mysocket',
options: httpConnectionOptions,
)
.build();
this is my class:
class TestClass extends StatefulWidget {
bool? gpsenabled;
TestClass({Key? key}) : super(key: key);
#override
State<TestClass> createState() => _TestClassState();
}
class _TestClassState extends State<TestClass> {
void checkGPS() async {
if (hubConnection.state == HubConnectionState.Connected) {
await hubConnection.invoke('GPSEnable').then((value) {
setState(() {
widget.gpsenabled = value as bool;
});
print(widget.gpsenabled);
Future.delayed(Duration(seconds: 5));
checkGPS();
});
}
}
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
hubConnection.start();
print('connection first');
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
I'm going to make an app that plays a list of images and audio in order. After audio playback, the following images and audio are played.
I update image to setState() when the playback is completed. And each time use setState(), I used play() function inside the build() method to recall play().
However, the method in the build is called twice, so the audio file is also played twice.
How do I run this method only once when I build it?
class PlayingScreen extends StatefulWidget {
final PostModel postModel;
PlayingScreen({
Key? key,
required this.postModel,
}) : super(key: key);
#override
State<PlayingScreen> createState() => _PlayingScreenState();
}
class _PlayingScreenState extends State<PlayingScreen> {
final _audioPlayer = AudioPlayer();
List<String> _audios = []; // audio file path list
int _playIndex = 0;
#override
void initState() {
_getAudios();
super.initState();
}
#override
void dispose() {
_audioPlayer.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
_play(_playIndex);
return Scaffold(
appBar: AppBar(
title: Text(widget.postModel.title),
),
body: InkWell(
onTap: () {
Get.back();
},
// image widget
),
),
);
}
Future _play(int index) async {
await _audioPlayer.play(DeviceFileSource(_audios[index]));
logger.d("current index: $_playIndex / ${_audios.length - 1}");
//complete event
_audioPlayer.onPlayerComplete.listen((event) {
logger.d("complet, next");
setState(() {
if (_playIndex >= _imageSets.length - 1) {
_playIndex = 0;
logger.d("return first index");
} else {
_playIndex++;
}
});
});
}
}
// ...
int _playIndex = 0;
bool played = false
// ...
// build
if(! played) {
_play(_playIndex);
played = true;
}
Add the variable "played" at the class level
Add a check in the build method
Calling a future inside the build method will always rebuild multiple times not only twice.
I would probably use it in a FutureBuilder() like so:
FutureBuilder(
future:_play(_playIndex),
builder:(context, snapshot){
...
}
)
I want my flutter web page display a photo , and change for every 3 seconds to display another photo ..
here is my code
class _contactPageState extends State<contactPage> {
List<String> randomPics= ['profiles/github.png', 'profiles/linkedIn.png', 'profiles/stack.png'];
Timer timer;
var random= Random();
String photo;
#override
void initState() {
photo = randomPics[random.nextInt(randomPics.length)];
openLink = new linksToOpen();
super.initState();
timer = new Timer(new Duration(seconds: 1), ( ){
setState(() {
photo= randomPics[random.nextInt(randomPics.length)];
print('${photo}');
});
});
}
#override
Widget build(BuildContext context) {
Container(
child: Image(image : AssetImage(photo),gaplessPlayback: true,),
width: 400, height: 400,
),
What is the problem with my code ?
Please , can anyone help me !
I did some test and I think this could work for you:
import 'dart:async';
import 'dart:math';
import 'package:flutter/widgets.dart';
class ContactPageState extends StatefulWidget {
ContactPageState({Key key}) : super(key: key);
#override
_ContactPageState createState() => _ContactPageState();
}
class _ContactPageState extends State<ContactPageState> {
List<String> randomPics = ['assets/a.jpg', 'assets/b.jpg', 'assets/c.jpg'];
String photo;
final random = new Random();
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) => configureTimer());
super.initState();
}
configureTimer() {
Timer.periodic(Duration(milliseconds: 3000), (timer) {
final int index = random.nextInt(randomPics.length);
setState(() {
photo = randomPics[index];
debugPrint('Select picture $photo in index $index');
});
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Image(
image: AssetImage(photo != null ? photo : 'assets/a.jpg'),
gaplessPlayback: true,
),
width: 400,
height: 400,
);
}
}
For a quick fix, you need to add function setStatus ... as a callback function so it can call itself infinitely.
void _nextPic(){
setState(() {
photo= randomPics[random.nextInt(randomPics.length)];
print('${photo}');
});
timer = new Timer(new Duration(seconds: 1), _nextPic);
}
This function create another timer after this one is done. So you can just need to create the first timer in initState...
#override
void initState() {
photo = randomPics[random.nextInt(randomPics.length)];
super.initState();
timer = new Timer(new Duration(seconds: 1), _nextPic);
}
For one thing, you will need to specify 3 seconds instead of 1. Another, you may be looking for timer.periodic to have this execute multiple times (until you tell it to stop) instead of a single timer countdown that happens starting from state initialization.
An example, see selected answer here:
Flutter Countdown Timer
Documentation:
https://api.flutter.dev/flutter/dart-async/Timer/Timer.periodic.html
I am a true beginner in flutter and dart.
I have a problem concerning playing youtube videos using [ youtube_player_flutter: ^6.1.1]
I create a Json file with youtube links and I want to link it with [ youtube_player_flutter: ^6.1.1]. but it always displays the error message [Only static members can be accessed in initializers]
#override
Widget build(BuildContext context) {
// this function is called before the build so that
// the string assettoload is avialable to the DefaultAssetBuilder
setasset();
// and now we return the FutureBuilder to load and decode JSON
return FutureBuilder(
future:
DefaultAssetBundle.of(context).loadString(assettoload, cache: true),
builder: (context, snapshot) {
List mydata = json.decode(snapshot.data.toString());
if (mydata == null) {
return Scaffold(
body: Center(
child: Text(
"Loading",
),
),
);
} else {
return quizpage(mydata: mydata);
}
},
);
}
}
class quizpage extends StatefulWidget {
final dynamic mydata;
////////var youtubeUrl;
quizpage({Key key, #required this.mydata}) : super(key: key);
#override
_quizpageState createState() => _quizpageState(mydata);
}
class _quizpageState extends State<quizpage> {
var mydata;
_quizpageState(this.mydata);
int marks = 0;
int i = 1;
#override
void setState(fn) {
if (mounted) {
super.setState(fn);
}
}
YoutubePlayerController _controller;
#override
void initState() {
_controller = YoutubePlayerController(
initialVideoId: YoutubePlayer.convertUrlToId(mydata[4]["1"]));
super.initState();
}
void nextquestion() {
setState(() {
if (i < 10) {
i++;
} else {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => resultpage(marks: marks),
));
}
The problem is that I want to make the [String videoURL ] plays the list of videos in my json data file.
Thanks in advance.
Possibility is that you coded the variable mydata twice. This is the format you should follow. And in order to make use of the variable from the StatefulWidget from the constructor, use widget.mydata. Don't have to declare it twice.
Code:
class Quizpage extends StatefulWidget {
final dynamic mydata;
quizpage({Key key, #required this.mydata}) : super(key: key);
#override
_QuizpageState createState() => _QuizpageState();
}
class _QuizpageState extends State<Quizpage> {
/*
You can make use of your mydata in this class like this:
widget.mydata, and you will be able to make it work
*/
Color colortoshow = Colors.indigoAccent;
Color right = Colors.green;
Color wrong = Colors.red;
int marks = 0;
int i = 1;
// String videoURL ="https://www.youtube.com/watch?v=2OAdfB2U88A&t=593s";
YoutubePlayerController _controller;
// Use like this to make use of your array mydata
String videoURL = widget.myData[4]["1"];
#override
void initState() {
_controller = YoutubePlayerController(
initialVideoId: YoutubePlayer.convertUrlToId(videoURL));
super.initState();
}
}
Also, this is for coding point of view. Please follow the correct way of naming classes in Flutter. Always use CamelCase or Have your first letter of the class as capital. This is the best practice while you write your code. I hope the above helps you in some sense. Thanks :)
I'm using a RestartableTimer (subclass of Timer) as a countdown timer, to "kick people out" of a form after a certain duration.
I would like to display the progress of that timer, and I like the idea of a circular progress slowly filling up.
I'm not showing my code because I don't really have anything to show. I have a completely static progress indicator and a working timer, in a widget (stateful or stateless, whichever works best).
I face two issues and this is where I need help for :
I don't know how to check every x milliseconds for the timer progress. How can I do that? I don't need copy-pasta code, but more of "what object / which direction" should I go for?
The timer progress in ticks is not implemented (NotImplementedException) ; is there any way to have an equivalent somewhere else? That object works really well for me, except for that part.
Am I SOL or is there a way to make it?
There's nothing to be implemented in the getter tick, since RestartableTimer is not periodic. What you want is a much more complex thing, and RestartableTimer is not able to help you with that.
First, you need something to control the progress of the CircularProgressIndicator:
class ProgressController {
static const double smoothnessConstant = 250;
final Duration duration;
final Duration tickPeriod;
Timer _timer;
Timer _periodicTimer;
Stream<void> get progressStream => _progressController.stream;
StreamController<void> _progressController = StreamController<void>.broadcast();
Stream<void> get timeoutStream => _timeoutController.stream;
StreamController<void> _timeoutController = StreamController<void>.broadcast();
double get progress => _progress;
double _progress = 0;
ProgressController({#required this.duration})
: assert(duration != null),
tickPeriod = _calculateTickPeriod(duration);
void start() {
_timer = Timer(duration, () {
_cancelTimers();
_setProgressAndNotify(1);
_timeoutController.add(null);
});
_periodicTimer = Timer.periodic(
tickPeriod,
(Timer timer) {
double progress = _calculateProgress(timer);
_setProgressAndNotify(progress);
},
);
}
void restart() {
_cancelTimers();
start();
}
Future<void> dispose() async {
await _cancelStreams();
_cancelTimers();
}
double _calculateProgress(Timer timer) {
double progress = timer.tick / smoothnessConstant;
if (progress > 1) return 1;
if (progress < 0) return 0;
return progress;
}
void _setProgressAndNotify(double value) {
_progress = value;
_progressController.add(null);
}
Future<void> _cancelStreams() async {
if (!_progressController.isClosed) await _progressController.close();
if (!_timeoutController.isClosed) await _timeoutController.close();
}
void _cancelTimers() {
if (_timer?.isActive == true) _timer.cancel();
if (_periodicTimer?.isActive == true) _periodicTimer.cancel();
}
static Duration _calculateTickPeriod(Duration duration) {
double tickPeriodMs = duration.inMilliseconds / smoothnessConstant;
return Duration(milliseconds: tickPeriodMs.toInt());
}
}
Then you can implement a CircularProgressIndicator that listens to the Streams from ProgressController:
class RestartableCircularProgressIndicator extends StatefulWidget {
final ProgressController controller;
final VoidCallback onTimeout;
RestartableCircularProgressIndicator({
Key key,
#required this.controller,
this.onTimeout,
}) : assert(controller != null),
super(key: key);
#override
_RestartableCircularProgressIndicatorState createState() =>
_RestartableCircularProgressIndicatorState();
}
class _RestartableCircularProgressIndicatorState
extends State<RestartableCircularProgressIndicator> {
ProgressController get controller => widget.controller;
VoidCallback get onTimeout => widget.onTimeout;
#override
void initState() {
super.initState();
controller.progressStream.listen((_) => updateState());
controller.timeoutStream.listen((_) => onTimeout());
}
#override
Widget build(BuildContext context) {
return CircularProgressIndicator(
value: controller.progress,
);
}
void updateState() => setState(() {});
}
You can also pass some of the paramers of CircularProgressIndicator to RestartableCircularProgressIndicator, so you can customize it.
A usage example:
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ProgressController controller;
#override
void initState() {
super.initState();
controller = ProgressController(
duration: Duration(seconds: 5),
);
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RestartableCircularProgressIndicator(
controller: controller,
onTimeout: () => print('timeout'),
),
RaisedButton(
onPressed: controller.start,
child: Text('Start'),
),
RaisedButton(
onPressed: controller.restart,
child: Text('Restart'),
),
],
),
),
),
);
}
}
I'll convert this into a library someday, but until then I cannot provide the tests and documentation to this code, so you have to study it if you want to understand what's going on here (I'm sorry...).