現在想要QT提供的這個analogclock時鐘變成自訂規律時間的提醒報時鐘,所以我們必須加入音效來提醒報時
啟稿: 2014/12/17
完稿: 2014/12/24
QT CueTai線索台
QT跨平台實作02-跨平台實作再探:加入音效資源檔在Windows、OSX、iOS、Android下之實例
現在想要QT提供的這個analogclock時鐘變成自訂規律時間的提醒報時鐘,所以我們必須加入音效來提醒報時並在畫面上貼上圖示表示報時的狀態。
l 播放音樂或音效的方法 – QMediaPlayer
首先來看QT如何播放音效;QT在音效播放的例子也不少,在範例的選項輸入大概會有6個範例如下:
在此我們需要的是輸出音效,所以應該參考”Audio Output Example”或“Media Player Example”兩個範例;無論哪一個範例,要輸出音效,在*.pro檔中都要加入如下:
QT+=multimediawidgets
第一個範例”Audio Output Example”介紹從底層記憶體配置到audio device使用,雖然相當的仔細,但使用起來相當複雜也不方便;第二個範例雖然比較直接採用QMediaPlayer->play(),不過此範例幾乎等於寫一個類似Windows Media Player,所以程式架構就有6個class相當複雜,必須先決定playlist,用player controller才能進行播放音效;對於在此僅需要單純的播放音效的要求來說,也不算適合的範例。
不過我們在說明的頁次下方搜尋區可以輸入QMediaPlayer搜尋,當查看Audio Overview可以發現簡易的使用方法如下:
player = new QMediaPlayer;
// ...
player->setMedia(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
player->setVolume(50);
player->play();
所以只要呼叫QMediaPlayer的setMedia()給定音樂檔案的路徑位置,就可以透過play()來播放音樂。
l 加入資源檔
QT可將程式需要用到卻不會變更的圖示、音樂、音效及資料檔以資源檔的形式編譯整併到執行檔中,一來不怕執行時就不怕找不到這些資源檔,另外也對於在跨不同的平台上有方便且一致性的使用方法;因為我們在此採用資源檔的方式來加入音效及報時圖示畫面,在這裡加入一個音效檔及一個圖示檔。
在Files選單中選擇”新增檔案或專案(N)”,跳出如下圖一樣的選單後,選擇檔案與類別中的QT,再選擇”QT資源檔”,就可在現有的專案中增加資源檔。
加入兩個檔案alarm.png及alarm.wav進入analogclock.qrc檔如下所示:
Note: 在此前置字串設為”/”,表示在虛擬的資源檔中的根目錄。
加入了資源檔到專案後,QT自動會在analogclock.pro加入以下的定義:
RESOURCES+=analogclock.qrc
有了資源檔後,現在就可以試試看QMediaPlayer播放的效果;編譯執行都沒有問題,但很不幸的是,沒有任何聲音!各位可以試試看下面的程式就可以知道差異:
player=newQMediaPlayer;
//---Rersource(QMediacan'topenresourcedirectly)
player->setMedia(QUrl::fromLocalFile(":/alarm.wav"));
player->play();
//---Window(E:/QT/QtWork/analogclock/
player->setMedia(QUrl::fromLocalFile("E:\\QT\\QtWork\\analogclock\\alarm.wav"));
player->play();
第一段程式直接選擇資源檔中的":/alarm.wav"檔是播不出聲音的,只有第二段程式選擇一個絕對路徑的音效檔才能夠播放出來;如果QMediaPlayer的功能限制是如此,那問題就大了,因為在不同的平台上絕對路徑定義是不一樣,要做到跨平台採用相對路徑才容易;到網路上Google一下,就會發現這個問題從QT 4.xx版時就已經存在了,大家都期望新版本能夠改進,不過網路上最早提到的是QSound而不是QMediaPlayer,看樣子QMediaPlayer在QT 5.3.0還是沒有改進,那QSound呢?
l 播放音效的方法 –QSound
可以在網路上Google一下QSound的用法,或在說明的頁次下方搜尋區可以輸入QSound進行搜尋,當查看QSound Class可以發現簡易的使用方法如下:
QSound::play("mysounds/bells.wav");
or
QSound bells("mysounds/bells.wav");
bells.play();
將前面我們採用QMediaPlayer改成QSound來試試看,結果第一段程式直接選擇資源檔中的":/alarm.wav"檔與第二段程式選擇一個絕對路徑的音效檔都可以播放出音效來了;看起來QT 5.3.0至少已經將QSound播放資源檔的問題解決了!
l 修改程式
研究一下analogclock範例,很容易發現它在analogclock.cpp AnalogClock::paintEvent中更新時分針畫面,所以我們就可以在這裡加入我們期望的功能:
首先加入顯示目前日期及星期的功能在中央如下:
QPainterpainter(this);
//---Date&Weeks
painter.drawText(QRectF(0,0,width(),height()/2),Qt::AlignCenter,QString("%1/%2/%3").arg(date.year()).arg(date.month()).arg(date.day()));
painter.drawText(QRectF(0,0,width(),height()*3/2),Qt::AlignCenter,weekname[date.dayOfWeek()-1]);
接下來判斷報時的時間是否到了,若到了就播放音效,在此先設定為每一刻鐘(15分鐘)報時一次,之後再改為使用者可以自行定義的方式;所以修改的程式如下:
if(time.minute()%15==0){
sound->play();
}
執行的結果發現報時時間一到,在這一分鐘內,每秒鐘都會觸發播放音效一次,若音效檔時間很長,則播放到一半就被下一秒的觸發打斷了,所以前面的邏輯不夠周延,必須加如變數作為旗標表示已經正在播放中,所以修改為以下:
if(time.minute()!=minute_previous)
{
if(time.minute()%15==0){
sound->play();
minute_previous=time.minute();
}
}
l 各個平台執行的結果
在Windows上執行的結果如下:
在Android下執行的結果如下:
在MAC OS上建置執行結果的結果如下:
在iOS模擬器上建置執行結果的結果如下:
l 結論
經過四個作業系統平台的實驗,都可以正常的運作,所以QT真如同它所號稱的跨平台開發語言;在此為了新功能修改的並不多,但是在播放音效上花了相當多的時間發現了QT目前的,總結來說得到了以下的了解:
要輸出音效及利用資源檔,在*.pro檔中都要加入如下:
QT+=multimediawidgets
RESOURCES+=analogclock.qrc
目前版本QMediaPlayer在QT 5.3.0還是不能支援播放資源檔,但QSound已經改進了!所以在此以QSound作範例!
整體程式在此連結處下載:
l 延伸應用及問題
在這個範例利用到資源檔,好處是跨不同的平台上很方便,但是資源檔限於不會變更的檔案以資源檔的形式編譯整併到執行檔中,若現在希望使用者可以自行放入想要的音效檔,那似乎不能使用資源檔這種方法,那該用何種方法呢?跨平台還是如此容易嗎?