AudioChannel.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2005 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 
00021 #include "AudioChannel.h"
00022 #include "AudioSample.h"
00023 
00024 namespace Pentagram {
00025 
00026 // We divide the data by 2, to prevent overshots. Imagine this sample pattern:
00027 // 0, 65535, 65535, 0. Now you want to compute a value between the two 65535.
00028 // Obviously, it will be *bigger* than 65535 (it can get to about 80,000).
00029 // It is possibly to clamp it, but that leads to a distored wave form. Compare
00030 // this to turning up the volume of your stereo to much, it will start to sound
00031 // bad at a certain level (depending on the power of your stereo, your speakers 
00032 // etc, this can be quite loud, though ;-). Hence we reduce the original range.
00033 // A factor of roughly 1/1.2 = 0.8333 is sufficient. Since we want to avoid 
00034 // floating point, we approximate that by 27/32
00035 #define RANGE_REDUX(x)  (((x) * 27) >> 5)
00036 
00037 AudioChannel::AudioChannel(uint32 sample_rate_, bool stereo_) :
00038         playdata(0), playdata_size(0), decompressor_size(0), frame_size(0),
00039         sample_rate(sample_rate_), stereo(stereo_),
00040         loop(0), sample(0), 
00041         frame_evenodd(0), frame0_size(0), frame1_size(0), position(0), paused(false),
00042         fp_pos(0), fp_speed(0)
00043 {
00044 }
00045 
00046 AudioChannel::~AudioChannel(void)
00047 {
00048 }
00049 
00050 void AudioChannel::playSample(AudioSample *sample_, int loop_, int priority_, bool paused_, uint32 pitch_shift_, int lvol_, int rvol_)
00051 {
00052         sample = sample_; 
00053         loop = loop_;
00054         priority = priority_;
00055         lvol = lvol_;
00056         rvol = rvol_;
00057         paused = paused_;
00058         pitch_shift = pitch_shift_;
00059 
00060         if (!sample) return;
00061 
00062         // Setup buffers
00063         decompressor_size = sample->getDecompressorDataSize();
00064         frame_size = sample->getFrameSize();
00065 
00066         if ((decompressor_size + frame_size*2) > playdata_size)
00067         {
00068                 delete [] playdata;
00069                 playdata_size = decompressor_size + frame_size*2;
00070                 playdata = new uint8[playdata_size];
00071         }
00072 
00073         // Init the sample decompressor
00074         sample->initDecompressor(playdata);
00075 
00076         // Reset counter and stuff
00077         frame_evenodd = 0;
00078         position = 0;
00079         fp_pos = 0;
00080         fp_speed = (pitch_shift*sample->getRate())/sample_rate;
00081 
00082         // Decompress frame 0
00083         frame0_size = sample->decompressFrame(playdata, playdata+decompressor_size);
00084 
00085         // Decompress frame 1
00086         DecompressNextFrame();
00087 
00088         // Setup resampler
00089         if (sample->getBits()==8 && !sample->isStereo())
00090         {
00091                 uint8 *src = playdata+decompressor_size;
00092                 int a = *(src+0); a = (a|(a << 8))-32768;
00093                 int b = *(src+1); b = (a|(b << 8))-32768;
00094                 int c = *(src+2); c = (a|(c << 8))-32768;
00095         
00096                 interp_l.init(RANGE_REDUX(a),RANGE_REDUX(b),RANGE_REDUX(c));
00097         }
00098 
00099 }
00100 
00101 void AudioChannel::resampleAndMix(sint16 *stream, uint32 bytes)
00102 {
00103         if (!sample || paused) return;
00104 
00105         // Update fp_speed
00106         fp_speed = (pitch_shift*sample->getRate())/sample_rate;
00107 
00108         // Get and Mix data
00109         do
00110         {
00111                 // 8 bit resampling
00112                 if (sample->getBits()==8) {
00113                         // Mono resampling required
00114                         if (!sample->isStereo() && stereo)
00115                                 resampleFrameM8toS(stream,bytes);
00116                         if (!sample->isStereo() && !stereo)
00117                                 resampleFrameM8toM(stream,bytes);
00118                 }
00119                 // 16 bit resampling (or not)
00120                 /*
00121                 else
00122                 {
00123                         uint8 *src = playdata + decompressor_size + (frame_size*frame_evenodd) + position;
00124                         uint8 *src_end = src + frame0_size;
00125 
00126                         do {
00127                                 int c = *(src++);
00128                                 c = (c|(c << 8))-32768;
00129 
00130                                 int lresult = *(stream+0) + c;
00131                                 int rresult = *(stream+1) + c;
00132 
00133                                 // Enforce range in case of an "overshot". Shouldn't happen since we
00134                                 // scale down already, but safe is safe.
00135                                 if (lresult < -32768) lresult = -32768;
00136                                 else if (lresult > 32767) lresult = 32767;
00137 
00138                                 if (rresult < -32768) rresult = -32768;
00139                                 else if (rresult > 32767) rresult = 32767;
00140 
00141                                 *stream++ = lresult;
00142                                 *stream++ = rresult;
00143                                 bytes -= 4;
00144                         } while (bytes!=0 && src != src_end);
00145 
00146                         position = frame0_size - (src_end - src);
00147                 }
00148                 */
00149 
00150                 // We ran out of data
00151                 if (bytes || (position == frame0_size)) {
00152 
00153                         // No more data
00154                         if (!frame1_size) {
00155                                 sample = 0;
00156                                 return;
00157                         }
00158 
00159                         // Invert evenodd
00160                         frame_evenodd = 1-frame_evenodd;
00161 
00162                         // Set frame1 to be frame0
00163                         frame0_size = frame1_size;
00164                         position = 0;
00165 
00166                         DecompressNextFrame();
00167                 }
00168 
00169         } while (bytes!=0);
00170 }
00171 
00172 // Decompress a frame
00173 void AudioChannel::DecompressNextFrame()
00174 {
00175         // Get next frame of data
00176         uint8 *src2 = playdata + decompressor_size + (frame_size*(1-frame_evenodd));
00177         frame1_size = sample->decompressFrame(playdata, src2);
00178 
00179         // No stream, go back to beginning and get first frame 
00180         if (!frame1_size && loop) {
00181                 if (loop != -1) loop--;
00182                 sample->rewind(playdata);
00183                 frame1_size = sample->decompressFrame(playdata, src2);
00184         }
00185 }
00186 
00187 // Resample a frame of mono 8bit unsigned to Stereo 16bit
00188 void AudioChannel::resampleFrameM8toS(sint16 *&stream, uint32 &bytes)
00189 {
00190         uint8 *src = playdata + decompressor_size + (frame_size*frame_evenodd);
00191         uint8 *src2 = playdata + decompressor_size + (frame_size*(1-frame_evenodd));
00192 
00193         uint8 *src_end = src + frame0_size;
00194         uint8 *src2_end = src2 + frame1_size;
00195 
00196         src += position;
00197 
00198         int result;
00199         
00200         do {
00201                 // Add a new src sample (if required)
00202                 if (fp_pos >= 0x10000)
00203                 {
00204                         if (src+2 < src_end) {
00205                                 int c = *(src+2);
00206                                 c = (c|(c << 8))-32768;
00207                                 interp_l.feedData(c);
00208                         } else if (src2 < src2_end) {
00209                                 int c = *(src2);
00210                                 c = (c|(c << 8))-32768;
00211                                 interp_l.feedData(c);
00212                                 src2++;
00213                         } else {
00214                                 interp_l.feedData();
00215                         }
00216                         src++;
00217                         fp_pos -= 0x10000;
00218                 }
00219 
00220                 if (fp_pos < 0x10000) do {
00221                         // Do the interpolation
00222                         result = interp_l.interpolate(fp_pos);
00223 
00224                         int lresult = *(stream+0) + (result*lvol)/256;
00225                         int rresult = *(stream+1) + (result*rvol)/256;
00226 
00227                         // Enforce range in case of an "overshot". Shouldn't happen since we
00228                         // scale down already, but safe is safe.
00229                         if (lresult < -32768) lresult = -32768;
00230                         else if (lresult > 32767) lresult = 32767;
00231 
00232                         if (rresult < -32768) rresult = -32768;
00233                         else if (rresult > 32767) rresult = 32767;
00234 
00235                         *stream++ = lresult;
00236                         *stream++ = rresult;
00237                         bytes -= 4;
00238                         fp_pos += fp_speed;
00239 
00240                 } while (fp_pos < 0x10000 && bytes!=0);
00241 
00242         } while (bytes!=0 && src != src_end);
00243         
00244         position = frame0_size - (src_end - src);
00245 }
00246 
00247 // Resample a frame of mono 8bit unsigned to Mono 16bit
00248 void AudioChannel::resampleFrameM8toM(sint16 *&stream, uint32 &bytes)
00249 {
00250         uint8 *src = playdata + decompressor_size + (frame_size*frame_evenodd);
00251         uint8 *src2 = playdata + decompressor_size + (frame_size*(1-frame_evenodd));
00252 
00253         uint8 *src_end = src + frame0_size;
00254         uint8 *src2_end = src2 + frame1_size;
00255 
00256         src += position;
00257 
00258         int result;
00259         int volume = (rvol + lvol)/2;
00260         
00261         do {
00262                 // Add a new src sample (if required)
00263                 if (fp_pos >= 0x10000)
00264                 {
00265                         if (src+2 < src_end) {
00266                                 int c = *(src+2);
00267                                 c = (c|(c << 8))-32768;
00268                                 interp_l.feedData(c);
00269                         } else if (src2 < src2_end) {
00270                                 int c = *(src2);
00271                                 c = (c|(c << 8))-32768;
00272                                 interp_l.feedData(c);
00273                                 src2++;
00274                         } else {
00275                                 interp_l.feedData();
00276                         }
00277                         src++;
00278                         fp_pos -= 0x10000;
00279                 }
00280 
00281                 if (fp_pos < 0x10000) do {
00282                         // Do the interpolation
00283                         result = (interp_l.interpolate(fp_pos)*volume)/256;
00284 
00285                         result += *stream;
00286 
00287                         // Enforce range in case of an "overshot". Shouldn't happen since we
00288                         // scale down already, but safe is safe.
00289                         if (result < -32768) result = -32768;
00290                         else if (result > 32767) result = 32767;
00291 
00292                         *stream++ = result;
00293                         bytes -= 2;
00294                         fp_pos += fp_speed;
00295 
00296                 } while (fp_pos < 0x10000 && bytes!=0);
00297 
00298         } while (bytes!=0 && src != src_end);
00299         
00300         position = frame0_size - (src_end - src);
00301 }
00302 
00303 };
00304 

Generated on Fri Jul 27 22:27:09 2007 for pentagram by  doxygen 1.4.7