summaryrefslogtreecommitdiff
path: root/library/sound.cpp
Unidiff
Diffstat (limited to 'library/sound.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--library/sound.cpp35
1 files changed, 33 insertions, 2 deletions
diff --git a/library/sound.cpp b/library/sound.cpp
index ee2aabc..d1e2388 100644
--- a/library/sound.cpp
+++ b/library/sound.cpp
@@ -1,222 +1,253 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qtopia Environment. 4** This file is part of Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21#include <qpe/resource.h> 21#include <qpe/resource.h>
22#include <qpe/sound.h> 22#include <qpe/sound.h>
23#include <qpe/qcopenvelope_qws.h> 23#include <qpe/qcopenvelope_qws.h>
24 24
25#include <qsound.h> 25#include <qsound.h>
26#include <qfile.h> 26#include <qfile.h>
27 27
28#include <unistd.h> 28#include <unistd.h>
29#include <fcntl.h> 29#include <fcntl.h>
30#include <sys/ioctl.h> 30#include <sys/ioctl.h>
31 31
32#ifndef QT_NO_SOUND 32#ifndef QT_NO_SOUND
33#include <sys/soundcard.h> 33#include <sys/soundcard.h>
34#endif 34#endif
35 35
36#ifndef QT_NO_SOUND 36#ifndef QT_NO_SOUND
37static int WAVsoundDuration(const QString& filename) 37static int WAVsoundDuration(const QString& filename)
38{ 38{
39 // bad solution 39 // bad solution
40 40
41 // most of this is copied from qsoundqss.cpp 41 // most of this is copied from qsoundqss.cpp
42 42
43 QFile input(filename); 43 QFile input(filename);
44 if ( !input.open(IO_ReadOnly) ) 44 if ( !input.open(IO_ReadOnly) )
45 return 0; 45 return 0;
46 46
47 struct QRiffChunk { 47 struct QRiffChunk {
48 char id[4]; 48 char id[4];
49 Q_UINT32 size; 49 Q_UINT32 size;
50 char data[4/*size*/]; 50 char data[4/*size*/];
51 } chunk; 51 } chunk;
52 52
53 struct { 53 struct {
54 Q_INT16 formatTag; 54 Q_INT16 formatTag;
55 Q_INT16 channels; 55 Q_INT16 channels;
56 Q_INT32 samplesPerSec; 56 Q_INT32 samplesPerSec;
57 Q_INT32 avgBytesPerSec; 57 Q_INT32 avgBytesPerSec;
58 Q_INT16 blockAlign; 58 Q_INT16 blockAlign;
59 Q_INT16 wBitsPerSample; 59 Q_INT16 wBitsPerSample;
60 } chunkdata; 60 } chunkdata;
61 61
62 int total = 0; 62 int total = 0;
63 63
64 while(1) { 64 while(1) {
65 // Keep reading chunks... 65 // Keep reading chunks...
66 const int n = sizeof(chunk)-sizeof(chunk.data); 66 const int n = sizeof(chunk)-sizeof(chunk.data);
67 if ( input.readBlock((char*)&chunk,n) != n ) 67 if ( input.readBlock((char*)&chunk,n) != n )
68 break; 68 break;
69 if ( qstrncmp(chunk.id,"data",4) == 0 ) { 69 if ( qstrncmp(chunk.id,"data",4) == 0 ) {
70 total += chunkdata.avgBytesPerSec ? 70 total += chunkdata.avgBytesPerSec ?
71 chunk.size * 1000 / chunkdata.avgBytesPerSec : 0; 71 chunk.size * 1000 / chunkdata.avgBytesPerSec : 0;
72//qDebug("%d bytes of PCM (%dms)", chunk.size,chunkdata.avgBytesPerSec ? chunk.size * 1000 / chunkdata.avgBytesPerSec : 0); 72//qDebug("%d bytes of PCM (%dms)", chunk.size,chunkdata.avgBytesPerSec ? chunk.size * 1000 / chunkdata.avgBytesPerSec : 0);
73 input.at(input.at()+chunk.size-4); 73 input.at(input.at()+chunk.size-4);
74 } else if ( qstrncmp(chunk.id,"RIFF",4) == 0 ) { 74 } else if ( qstrncmp(chunk.id,"RIFF",4) == 0 ) {
75 char d[4]; 75 char d[4];
76 if ( input.readBlock(d,4) != 4 ) 76 if ( input.readBlock(d,4) != 4 )
77 return 0; 77 return 0;
78 if ( qstrncmp(d,"WAVE",4) != 0 ) { 78 if ( qstrncmp(d,"WAVE",4) != 0 ) {
79 // skip 79 // skip
80//qDebug("skip %.4s RIFF chunk",d); 80//qDebug("skip %.4s RIFF chunk",d);
81 if ( chunk.size < 10000000 ) 81 if ( chunk.size < 10000000 )
82 (void)input.at(input.at()+chunk.size-4); 82 (void)input.at(input.at()+chunk.size-4);
83 } 83 }
84 } else if ( qstrncmp(chunk.id,"fmt ",4) == 0 ) { 84 } else if ( qstrncmp(chunk.id,"fmt ",4) == 0 ) {
85 if ( input.readBlock((char*)&chunkdata,sizeof(chunkdata)) != sizeof(chunkdata) ) 85 if ( input.readBlock((char*)&chunkdata,sizeof(chunkdata)) != sizeof(chunkdata) )
86 return 0; 86 return 0;
87#define WAVE_FORMAT_PCM 1 87#define WAVE_FORMAT_PCM 1
88 if ( chunkdata.formatTag != WAVE_FORMAT_PCM ) { 88 if ( chunkdata.formatTag != WAVE_FORMAT_PCM ) {
89 //qDebug("WAV file: UNSUPPORTED FORMAT %d",chunkdata.formatTag); 89 //qDebug("WAV file: UNSUPPORTED FORMAT %d",chunkdata.formatTag);
90 return 0; 90 return 0;
91 } 91 }
92 } else { 92 } else {
93//qDebug("skip %.4s chunk",chunk.id); 93//qDebug("skip %.4s chunk",chunk.id);
94 // ignored chunk 94 // ignored chunk
95 if ( chunk.size < 10000000 ) 95 if ( chunk.size < 10000000 )
96 (void)input.at(input.at()+chunk.size); 96 (void)input.at(input.at()+chunk.size);
97 } 97 }
98 } 98 }
99 99
100//qDebug("%dms",total); 100//qDebug("%dms",total);
101 return total; 101 return total;
102} 102}
103 103
104class SoundData : public QSound { 104class SoundData : public QSound {
105 Q_OBJECT
106signals:
107 void stopped();
105public: 108public:
106 SoundData ( const QString& name ) : 109 SoundData ( const QString& name ) :
107 QSound ( Resource::findSound ( name )), 110 QSound ( Resource::findSound ( name )),
108 filename ( Resource::findSound ( name )) 111 filename ( Resource::findSound ( name ))
109 { 112 {
110 loopsleft=0; 113 loopsleft=0;
111 ms = WAVsoundDuration(filename); 114 ms = WAVsoundDuration(filename);
112 } 115 }
113 116
114 void playLoop ( int loopcnt = -1 ) 117 void playLoop ( int loopcnt = -1 )
115 { 118 {
116 // needs server support 119 // needs server support
117 loopsleft = loopcnt; 120 loopsleft = loopcnt;
118 121
119 if ( ms ) 122 if ( ms )
120 startTimer ( ms > 50 ? ms-50 : 0 ); // 50 for latency 123 startTimer ( ms > 50 ? ms-50 : 0 ); // 50 for latency
121 play ( ); 124 play ( );
122 } 125 }
123 126
124 void timerEvent ( QTimerEvent *e ) 127 void timerEvent ( QTimerEvent *e )
125 { 128 {
126 if ( loopsleft >= 0 ) { 129 if ( loopsleft >= 0 ) {
127 if ( --loopsleft <= 0 ) { 130 if ( --loopsleft <= 0 ) {
128 killTimer ( e-> timerId ( )); 131 killTimer ( e-> timerId ( ));
129 loopsleft = 0; 132 loopsleft = 0;
130 return; 133 return;
131 } 134 }
132 } 135 }
133 play(); 136 play();
134 } 137 }
135 138
136 bool isFinished ( ) const 139 bool isFinished ( ) const
137 { 140 {
138 return ( loopsleft == 0 ); 141 return ( loopsleft == 0 );
139 } 142 }
140 143
144 /*
145 * non virtual reimplementation
146 * @internal
147 */
148 void killTimers() {
149 QObject::killTimers();
150 emit stopped();
151 }
152
141private: 153private:
142 QString filename; 154 QString filename;
143 int loopsleft; 155 int loopsleft;
144 int ms; 156 int ms;
145}; 157};
146 158
147#endif 159#endif
148 160
161
162/*
163 * @internal
164 * Using sender() when the slot is called is unsafe!
165 *
166 * @param snd instance
167 * @param obj The QObject to be called
168 * @param slot connect SIGNAL(stopped()) to slot
169 */
170void register_qpe_sound_finished( Sound* snd, QObject* obj, const char* slot ) {
171#ifndef QT_NO_SOUND
172 QObject::connect(snd->d, SIGNAL(stopped()), obj, slot );
173#endif
174}
175
149/*! Opens a wave sound file \a name for playing 176/*! Opens a wave sound file \a name for playing
150 * Resource is used for finding the file 177 * Resource is used for finding the file
151 **/ 178 **/
152Sound::Sound(const QString& name) 179Sound::Sound(const QString& name)
153{ 180{
154#ifndef QT_NO_SOUND 181#ifndef QT_NO_SOUND
155 d = new SoundData(name); 182 d = new SoundData(name);
156#endif 183#endif
157} 184}
158 185
159/*! Destroys the sound */ 186/*! Destroys the sound */
160Sound::~Sound() 187Sound::~Sound()
161{ 188{
162#ifndef QT_NO_SOUND 189#ifndef QT_NO_SOUND
163 delete d; 190 delete d;
164#endif 191#endif
165} 192}
166 193
167/*! Play the sound once */ 194/*! Play the sound once */
168void Sound::play() 195void Sound::play()
169{ 196{
170#ifndef QT_NO_SOUND 197#ifndef QT_NO_SOUND
198 d->killTimers();
171 d->playLoop(1); 199 d->playLoop(1);
172#endif 200#endif
173} 201}
174 202
175/*! Play the sound, repeatedly until stop() is called */ 203/*! Play the sound, repeatedly until stop() is called */
176void Sound::playLoop() 204void Sound::playLoop()
177{ 205{
178#ifndef QT_NO_SOUND 206#ifndef QT_NO_SOUND
179 d->killTimers(); 207 d->killTimers();
180 d->playLoop(); 208 d->playLoop();
181#endif 209#endif
182} 210}
183 211
184/*! Do not repeat the sound after it finishes. This will end a playLoop() */ 212/*! Do not repeat the sound after it finishes. This will end a playLoop() */
185void Sound::stop() 213void Sound::stop()
186{ 214{
187#ifndef QT_NO_SOUND 215#ifndef QT_NO_SOUND
188 d->killTimers(); 216 d->killTimers();
189#endif 217#endif
190} 218}
191 219
192bool Sound::isFinished() const 220bool Sound::isFinished() const
193{ 221{
194#ifndef QT_NO_SOUND 222#ifndef QT_NO_SOUND
195 return d->isFinished(); 223 return d->isFinished();
196#else 224#else
197 return true; 225 return true;
198#endif 226#endif
199} 227}
200 228
201/*! Sounds the audible system alarm. This is used for applications such 229/*! Sounds the audible system alarm. This is used for applications such
202 as Calendar when it needs to alarm the user of an event. 230 as Calendar when it needs to alarm the user of an event.
203*/ 231*/
204void Sound::soundAlarm() 232void Sound::soundAlarm()
205{ 233{
206#ifndef QT_NO_COP 234#ifndef QT_NO_COP
207 QCopEnvelope( "QPE/TaskBar", "soundAlarm()" ); 235 QCopEnvelope( "QPE/TaskBar", "soundAlarm()" );
208#endif 236#endif
209} 237}
210 238
211 239
212/*! \class Sound 240/*! \class Sound
213 \brief The Sound class plays WAVE sound files and can invoke the audible alarm. 241 \brief The Sound class plays WAVE sound files and can invoke the audible alarm.
214 242
215 The Sound class is constructed with the .wav music file name. The Sound 243 The Sound class is constructed with the .wav music file name. The Sound
216 class retrieves the sound file from the shared Resource class. This class 244 class retrieves the sound file from the shared Resource class. This class
217 ties together QSound and the available sound resources. 245 ties together QSound and the available sound resources.
218 246
219 To sound an audible system alarm, call the static method soundAlarm() 247 To sound an audible system alarm, call the static method soundAlarm()
220 248
221 \ingroup qtopiaemb 249 \ingroup qtopiaemb
222*/ 250*/
251
252
253#include "sound.moc"