How to repeat sound in a loop? Qt5 [duplicate] - c++

I want to play background music continually in a loop until the game ends.
in the header file:
QMediaPlayer * music = new QMediaPlayer();
in the cpp file:
startGame(){
music->setMedia(QUrl("qrc:/sounds/backgroundmusic.mp3"));
music->play(); }
stopGame(){
music->stop(); }
Right now my music plays thru to the end but does not restart. How can I get it to loop over again again?
Is there a QMediaPlayer member I can use, or should I run it in a while loop, or what?

Sounds like what you want is QMediaPlaylist. QMediaPlaylist allows you to control the playback mode, and in this case you would use Loop. This approach has other advantages too, such as CurrentItemInLoop. CurrentItemInLoop will play the current playlist item in a loop, meaning that if you add more songs in the future you can select a song then loop only that track. Thus, you only need a single playlist for most needs. Below is some example code, I do not currently have a means to test it though (No Qt multimedia extensions installed on this machine). Should demonstrate the point reasonably well though.
QMediaPlaylist *playlist = new QMediaPlaylist();
playlist->addMedia(QUrl("qrc:/sounds/backgroundmusic.mp3"));
playlist->setPlaybackMode(QMediaPlaylist::Loop);
QMediaPlayer *music = new QMediaPlayer();
music->setPlaylist(playlist);
music->play();

Related

Stop Playing a Video from QMediaPlayer at Position X

I am new to Qt and I am using QMediaPlayer in one of my GUI projects and I want to stop the loaded video at a certain position X (input from user on a Line Edit) how would I be able to do this? I know I am able to set a starting position just by doing player->setPosition(Y) where Y is an integer but what about an ending position?
One lesser option would be to use position() which returns the current position as a qint64 - if you call the play() method for your QMediaPlayer then use something like
while (player.position() < input) {}
player.stop(); // Or player.pause();
it will wait until the input position is reached. But the drawback to that approach is the blocking while loop and without knowing the intended application I don't know if that would be appropriate. It is probably better to use the QMediaPlayer::positionChanged signal (which is emitted based on the QMediaPlayer's notifyInterval), something like
connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(checkPosition());
where it is assumed this is the receiver and both player and input are scoped such that they are available to the slot checkPosition(). checkPosition() then looks something like
checkPosition() {
if (player.position() > input()) {
player.stop(); // Or player.pause();
}
}
Of course you can also pass the player and the input to the checkPosition() slot but I neglected that for simplicity. Hope this helps.

Qt5 audio oscillogram

I need to draw an oscillogram of audio track. The audio could be stored with video too. I play audio with such code:
QMediaPlayer* player = new QMediaPlayer;
//connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
player->setMedia(QUrl::fromLocalFile("/home/mikhail/Downloads/BRAT.mkv"));
player->play();
I need to play any of audio tracks in video file and display it's oscillogram.
How can I realize it?
I've found an example in Qt examples: http://doc.qt.io/qt-5/qtcharts-audio-example.html . That's what I need but the sound streams from micro. I'm new at Qt, although an example is simple, I can't understand how to replace data from micro with data from player.
I can guess that I need to replace QAudioInput:
QAudioFormat formatAudio;
formatAudio.setSampleRate(8000);
formatAudio.setChannelCount(1);
formatAudio.setSampleSize(8);
formatAudio.setCodec("audio/pcm");
formatAudio.setByteOrder(QAudioFormat::LittleEndian);
formatAudio.setSampleType(QAudioFormat::UnSignedInt);
QAudioDeviceInfo inputDevices = QAudioDeviceInfo::defaultInputDevice();
m_audioInput = new QAudioInput(inputDevices,formatAudio, this);
m_device = new XYSeriesIODevice(m_series, this);
m_device->open(QIODevice::WriteOnly);
m_audioInput->start(m_device);
But I can't find how to give to QAudioInput a buffer of raw data from QMediaPlayer.
Also I have working code to get raw data with ffmpeg, but I think it could be done with QMediaPlayer and it would be easier.
Thanks for any help!

Qt QMediaPlayer - QThread::start: Failed to create thread

I develop an application which the user can play multiple sounds at the same time. For this I use QMediaPlayer in conjunction with a matrix to hold each sound separately. The code is simple, for each sound I use a code like this:
media = new QMediaPlayer();
media->setMedia(QUrl::fromLocalFile(QFileInfo("sound.mp3").absoluteFilePath()));
media->play();
Everything is ok. But around playing the sound 115-125 (simultaneous sounds), the new sounds emit signal error(QMediaPlayer::ResourceError) with error code: QMediaPlayer::ResourceError - A media resource couldn't be resolved. Before emit error signal, it print on output this message: DirectShowPlayerService::doPlay: Unresolved error code 0x80004005 ()
This is not a problem, because I delete those sounds as soon as I detect this error.
The problem appears right after a couple of QMediaPlayer::ResourceError.
If I create a new sound, an error message appear on output window: QThread::start: Failed to create thread.
This error appear just after creating a new QMediaPlayer instance:
qDebug() << "before media = new QMediaPlayer(); (FILE)";
media = new QMediaPlayer();
qDebug() << "after media = new QMediaPlayer(); (FILE)" << media->error
The output:
before media = new QMediaPlayer(); (FILE)
QThread::start: Failed to create thread
after media = new QMediaPlayer(); (FILE) QMediaPlayer::NoError
This last kind of QMediaPlayer instance emit no error. More than that, the state is QMediaPlayer::PlayingState. But if I try to delete it delete(media) or to set the media to a null QMediaContent media->setMedia(QMediaContent()) to make the player to discard all information relating to the current media source, the application freezes.
Those two opperations works fine on he others sounds.
If I don't delete this kind of QMediaPlayer, I end to have no room for sounds. Somehow QMediaPlayer has a limited number of instances and every QMediaPlayer that I cannot delete anymore fill this number and let no room for new instances of QMediaPlayer.
The question is: how I can avoid this issue? If I limit the number of simultaneous sounds, what is the correct number of QMediaPlayer instances? If I set a limit, this limit can be to high for other machines. Or how to properly detect this malformed QMediaPlayer and properly delete it?
Also, if I wait for first QMediaPlayer::ResourceError signal to limit the number of sounds, this is sometimes too late, because the error signal is emitted a bit later and sometimes the application already create a malformed QMediaPlayer that I cannot delete anymore and this prevent the process to close.

How to implement a game-loop with C++ and QtQuick

I'm developing a game with QtQuick 2 (Qt5.2) QML and C++. I want most of the game-logic in C++ (I don't want to do it with JS), and I'm trying to use QStateMachines for a lot of the logic.
Now my question is, how do I implement a proper game-loop in that scenario?
The game has for example objects that are moving from and to certain waypoints on the screen, so I think I can't do everything state/event-based. At some point I need to say "my object should move 10 pixels in direction x every second". So for example when my object is in its state "moving", it should move by a certain amount every second and then of course check for some conditions if it has to switch the state (e.g. to "attacking").
Now all the demos in the Qt-examples and on the web seem to be either fully event-based (e.g. four-in-a-row-wins-like) or written in JavaScript. So I am a bit lost here.
One idea I could find was to create a QTimer with a timer of e.g. 30ms and connect that QTimer's timeout() signal to an advance() slot of every moving object, and start that timer before 'return app.exec();'. Like this:
QTimer timer;
QObject::connect(&timer, SIGNAL(timeout()), &scene, SLOT(advance()));
timer.start(1000 / 33);
return app.exec();
and then each object (e.g. the Mouse) has a
void Mouse::advance(int step)
However, this requires a QGraphicsScene and I'm not sure how well that goes with a QtQuick/QML project on Android/iOS.
Is that a good solution? Or is my view of the problem somehow wrong and I don't need a game loop to accomplish my goal?
The solution shouldn't use any desktop-only stuff from Qt, i.e. it should work on Android, iOS and desktops.
That's the way to go: QTimer. Here you find some detailed example on it:
A typical loop for game in Qt:
int main(int argc, char* argv[]) {
// init stuff
while(game.isRunning()) {
a.processEvents(); //(a is a QApplication created during the init, should use a better name i guess)
QTime currentTime= QTime::currentTime();
int timeSinceLastUpdate = lastUpdate.msecsTo(currentTime);
while(timeSinceLastUpdate>updateTimeStep){
game.update();
timeSinceLastUpdate-=updateTimeStep;
lastUpdate=lastUpdateaddMSecs(updateTimeStep);
}
renderer.setInterpolateFraction(static_cast<float>(timeSinceLastUpdate)/static_cast<float>updateTimeStep);
renderer.renderGameObjects();
renderer.renderGUI();
renderer.swap();
}
a.exit();
return 0;
}
Source: Game loop in Qt
Making a Simple Game Loop with QTimer
Qt as a game engine
That's should be enough info for you to get started.
Usual game loop of simple game can look like this (not sure if I understand you correctly though).
Each class that represents game object have 2 public methods: update(); and render();
On each call of QTimer object you iterate over all game objects and call their update method. After it you repeat the same for render method();
In update methods each object decides what to do on game map (move/shot/stand/...) and changes its coordinates/properties. In render methods each object just draws itself on display.

Using state design pattern for cocos2d game

The game I am creating is a word puzzle game. You start out with a menu, where the user decides wether to go single player or multiplayer for instance.
If they choose Single Player then they have the option to play 3 different modes.
Practice
There is no timer
Stress
The player have to do a puzzle within 10 seconds repeatedly, until it deosn't manage to do the puzzle within the 10 seconds and they "die"
Time battle
The player has 2 mins to do as many puzzles as possible.
You see, the actual game play doesn't change but the only thing that changes is how the time is managed.
I read your articles and I found that the State pattern would fit quite nice, and now the only problem I have is how I could implement that pattern.
Should I make sub states as in a menu state abstraction and a game play abstraction or should I just create one universal game state abstraction and then ignore calls like "handleMenuSelection"?
I can't find any good tutorials online covering this in cocos2d. I can find a lot of small demos but it is hard to transform that into a big application when I have never touched a design pattern before besides the OOP design.
Btw. your links was very helpful opening up my mind for new ideas :)
Good to have one singleton class (shared object) that maintains all stats.
Example: Say MyGame is used to store all game stats.
//in MyGame.h
typedef enum
{
kGameMode_Practice = 1001,
kGameMode_Stress,
kGameMode_TimeBattle,
}GameMode;
#interface MyGame: NSObject
{
GameMode mGameMode;
int mHighScore;
}
#property(nonatomic,assign) GameMode gameMode;
  #property(nonatomic,assign) int  highScore;
+(MyGame*)sharedGameObject;
//In MyGame.mm
static MyGame *gGame = nil;
#implementation MyGame
#synthesize gameMode=mGameMode;
#synthesize highScore=mHighScore;
+(MyGame*)sharedGameObject
{
if(!gGame)
{
gGame = [[MyGame alloc] init];
}
return gGame;
}
-(void)saveData //Call this from applicationWillResignActive
{
NSUserDefaults *userDafs = [NSUserDefaults standardUserDefaults];
[userDafs setInteger:self.highScore forKey:#"highScore"];
[userDafs setInteger:self.gameMode forKey:#"gameMode"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
-(void)loadData //call this from UIApplication didFinishLaunchingWithOptions
{
NSUserDefaults *userDafs = [NSUserDefaults standardUserDefaults];
self.highScore = [userDafs integerForKey:#"highScore"]
self.gameMode = (GameMode)[userDafs integerForKey:#"gameMode"]
}
//You can set game mode on selecting menu button
[MyGame sharedGameObject].gameMode = kGameMode_Practice
//To check anywhere in the game
if([MyGame sharedGameObject].gameMode == kGameMode_Practice)
Also save these value at app termination and load same when app starts.
[[MyGame sharedGameObject] saveData];
Based on game mode you can change game play. Use single general class for game play logic and check game mode and do tweak..when u design 3 separate class for 3types then change in one needs to be updated in all files in future..so good to have general code as much as possible.
It's difficult to suggest a good design guideline given that there is very little information. Trying to guess a bit, I would suggest you to read about the Strategy Design Pattern and the State Design Pattern (another link), as it may be suitable for what you are doing, and it would be a clean way to manage multiple game modes.