Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

audioodevice.C

Go to the documentation of this file.
00001 #include "audiodevice.h"
00002 #include "clip.h"
00003 #include "condition.h"
00004 #include "mutex.h"
00005 #include "playbackconfig.h"
00006 #include "sema.h"
00007 
00008 #include <string.h>
00009 
00010 int AudioDevice::write_buffer(double **output, int samples, int channels)
00011 {
00012 // find free buffer to fill
00013         if(interrupt) return 0;
00014         arm_buffer(arm_buffer_num, output, samples, channels);
00015         arm_buffer_num++;
00016         if(arm_buffer_num >= TOTAL_BUFFERS) arm_buffer_num = 0;
00017         return 0;
00018 }
00019 
00020 int AudioDevice::set_last_buffer()
00021 {
00022         arm_lock[arm_buffer_num]->lock("AudioDevice::set_last_buffer");
00023         last_buffer[arm_buffer_num] = 1;
00024         play_lock[arm_buffer_num]->unlock();
00025 
00026 
00027         arm_buffer_num++;
00028         if(arm_buffer_num >= TOTAL_BUFFERS) arm_buffer_num = 0;
00029         return 0;
00030 }
00031 
00032 
00033 // must run before threading once to allocate buffers
00034 // must send maximum size buffer the first time or risk reallocation while threaded
00035 int AudioDevice::arm_buffer(int buffer_num, 
00036         double **output, 
00037         int samples, 
00038         int channels)
00039 {
00040         int bits;
00041         int new_size;
00042 
00043         int i, j;
00044         int input_offset;
00045         int output_offset;
00046         int output_advance;
00047         int channel, last_input_channel;
00048         double sample;
00049         int int_sample, int_sample2;
00050         int dither_value;
00051         int frame;
00052         int device_channels = get_ochannels();
00053         char *buffer_num_buffer;
00054         double *buffer_in_channel;
00055 
00056         if(channels == -1) channels = get_ochannels();
00057         bits = get_obits();
00058 
00059         frame = device_channels * (bits / 8);
00060 
00061         new_size = frame * samples;
00062 
00063         if(interrupt) return 1;
00064 
00065 // wait for buffer to become available for writing
00066         arm_lock[buffer_num]->lock("AudioDevice::arm_buffer");
00067         if(interrupt) return 1;
00068 
00069         if(new_size > buffer_size[buffer_num])
00070         {
00071                 if(buffer_size[buffer_num] != 0)
00072                 {
00073                         delete [] buffer[buffer_num];
00074                 }
00075                 buffer[buffer_num] = new char[new_size];
00076                 buffer_size[buffer_num] = new_size;
00077         }
00078 
00079         buffer_size[buffer_num] = new_size;
00080 
00081         buffer_num_buffer = buffer[buffer_num];
00082         bzero(buffer_num_buffer, new_size);
00083         
00084         last_input_channel = channels - 1;
00085 // copy data
00086 // intel byte order only to correspond with bits_to_fmt
00087 
00088         for(channel = 0; channel < device_channels && channel < channels; channel++)
00089         {
00090                 buffer_in_channel = output[channel];
00091                 switch(bits)
00092                 {
00093                         case 8:
00094                                 output_advance = device_channels;
00095                                 if(play_dither)
00096                                 {
00097                                         for(output_offset = channel, input_offset = 0; input_offset < samples; output_offset += output_advance, input_offset++)
00098                                         {
00099                                                 sample = buffer_in_channel[input_offset];
00100                                                 CLAMP(sample, -1, 1);
00101                                                 sample *= 0x7fff;
00102                                                 int_sample = (int)sample;
00103                                                 dither_value = rand() % 255;
00104                                                 int_sample -= dither_value;
00105                                                 int_sample /= 0x100;
00106                                                 buffer_num_buffer[output_offset] = int_sample;
00107                                         }
00108                                 }
00109                                 else
00110                                 {
00111                                         for(output_offset = channel, input_offset = 0; input_offset < samples; output_offset += output_advance, input_offset++)
00112                                         {
00113                                                 sample = buffer_in_channel[input_offset];
00114                                                 CLAMP(sample, -1, 1);
00115                                                 sample *= 0x7f;
00116                                                 int_sample = (int)sample;
00117                                                 buffer_num_buffer[output_offset] = int_sample;
00118                                         }
00119                                 }
00120                                 break;
00121 
00122                         case 16:
00123                                 output_advance = device_channels * 2 - 1;
00124                                 if(play_dither)
00125                                 {
00126                                         for(output_offset = channel * 2, input_offset = 0; 
00127                                                 input_offset < samples; 
00128                                                 output_offset += output_advance, input_offset++)
00129                                         {
00130                                                 sample = buffer_in_channel[input_offset];
00131                                                 CLAMP(sample, -1, 1);
00132                                                 sample *= 0x7fffff;
00133                                                 int_sample = (int)sample;
00134                                                 dither_value = rand() % 255;
00135                                                 int_sample -= dither_value;
00136                                                 int_sample /= 0x100;
00137                                                 buffer_num_buffer[output_offset] = int_sample;
00138                                         }
00139                                 }
00140                                 else
00141                                 {
00142                                         for(output_offset = channel * 2, input_offset = 0; 
00143                                                 input_offset < samples; 
00144                                                 output_offset += output_advance, input_offset++)
00145                                         {
00146                                                 sample = buffer_in_channel[input_offset];
00147                                                 CLAMP(sample, -1, 1);
00148                                                 sample *= 0x7fff;
00149                                                 int_sample = (int)sample;
00150                                                 buffer_num_buffer[output_offset++] = (int_sample & 0xff);
00151                                                 buffer_num_buffer[output_offset] = (int_sample & 0xff00) >> 8;
00152                                         }
00153                                 }
00154                                 break;
00155 
00156                         case 24:
00157                                 output_advance = (device_channels - 1) * 3;
00158                                 for(output_offset = channel * 3, input_offset = 0; 
00159                                         input_offset < samples; 
00160                                         output_offset += output_advance, input_offset++)
00161                                 {
00162                                         sample = buffer_in_channel[input_offset];
00163                                         CLAMP(sample, -1, 1);
00164                                         sample *= 0x7fffff;
00165                                         int_sample = (int)sample;
00166                                         buffer_num_buffer[output_offset++] = (int_sample & 0xff);
00167                                         buffer_num_buffer[output_offset++] = (int_sample & 0xff00) >> 8;
00168                                         buffer_num_buffer[output_offset++] = (int_sample & 0xff0000) >> 16;
00169                                 }
00170                                 break;
00171 
00172                         case 32:
00173                                 output_advance = (device_channels - 1) * 4;
00174                                 for(output_offset = channel * 4, input_offset = 0; 
00175                                         input_offset < samples; 
00176                                         output_offset += output_advance, input_offset++)
00177                                 {
00178                                         sample = buffer_in_channel[input_offset];
00179                                         CLAMP(sample, -1, 1);
00180                                         sample *= 0x7fffffff;
00181                                         int_sample = (int)sample;
00182                                         buffer_num_buffer[output_offset++] = (int_sample & 0xff);
00183                                         buffer_num_buffer[output_offset++] = (int_sample & 0xff00) >> 8;
00184                                         buffer_num_buffer[output_offset++] = (int_sample & 0xff0000) >> 16;
00185                                         buffer_num_buffer[output_offset++] = (int_sample & 0xff000000) >> 24;
00186                                 }
00187                                 break;
00188                 }
00189         }
00190 
00191 // make buffer available for playback
00192         play_lock[buffer_num]->unlock();
00193         return 0;
00194 }
00195 
00196 int AudioDevice::reset_output()
00197 {
00198         for(int i = 0; i < TOTAL_BUFFERS; i++)
00199         {
00200                 if(buffer_size[i]) { delete [] buffer[i]; }
00201                 buffer[i] = 0;
00202                 buffer_size[i] = 0;
00203                 arm_lock[i]->reset();
00204                 play_lock[i]->reset(); 
00205                 last_buffer[i] = 0;
00206         }
00207 
00208         is_playing_back = 0;
00209         software_position_info = position_correction = last_buffer_size = 0;
00210         total_samples = 0;
00211         play_dither == 0;
00212         arm_buffer_num = 0;
00213         last_position = 0;
00214         interrupt = 0;
00215         return 0;
00216 }
00217 
00218 
00219 int AudioDevice::set_play_dither(int status)
00220 {
00221         play_dither = status;
00222         return 0;
00223 }
00224 
00225 int AudioDevice::set_software_positioning(int status)
00226 {
00227         software_position_info = status;
00228         return 0;
00229 }
00230 
00231 int AudioDevice::start_playback()
00232 {
00233 // arm buffer before doing this
00234         is_playing_back = 1;
00235         interrupt = 0;
00236 // zero timers
00237         playback_timer.update();
00238         last_position = 0;
00239 
00240         Thread::set_realtime(get_orealtime());
00241         Thread::start();                  // synchronize threads by starting playback here and blocking
00242 }
00243 
00244 int AudioDevice::interrupt_playback()
00245 {
00246         interrupt = 1;
00247 
00248         if(is_playing_back)
00249         {
00250 // cancel thread
00251                 is_playing_back = 0;
00252                 get_lowlevel_out()->interrupt_playback();
00253 // Completion is waited for in arender
00254         }
00255 
00256 // unlock everything
00257         for(int i = 0; i < TOTAL_BUFFERS; i++)
00258         {
00259 // When TRACE_LOCKS is enabled, this
00260 // locks up when run() is waiting on it at just the right time.
00261 // Seems there may be a cancel after the trace lock is locked.
00262                 play_lock[i]->unlock();  
00263                 arm_lock[i]->unlock();
00264         }
00265 
00266         return 0;
00267 }
00268 
00269 int AudioDevice::wait_for_startup()
00270 {
00271         startup_lock->lock("AudioDevice::wait_for_startup");
00272         return 0;
00273 }
00274 
00275 int AudioDevice::wait_for_completion()
00276 {
00277         Thread::join();
00278         return 0;
00279 }
00280 
00281 
00282 
00283 int64_t AudioDevice::current_position()
00284 {
00285 // try to get OSS position
00286         int64_t hardware_result = 0, software_result = 0, frame;
00287 
00288         if(w)
00289         {
00290                 frame = get_obits() / 8;
00291 
00292 // get hardware position
00293                 if(!software_position_info)
00294                 {
00295                         hardware_result = get_lowlevel_out()->device_position();
00296                 }
00297 
00298 // get software position
00299                 if(hardware_result < 0 || software_position_info)
00300                 {
00301                         timer_lock->lock("AudioDevice::current_position");
00302                         software_result = total_samples - last_buffer_size - 
00303                                 device_buffer / frame / get_ochannels();
00304                         software_result += playback_timer.get_scaled_difference(get_orate());
00305                         timer_lock->unlock();
00306 
00307                         if(software_result < last_position) 
00308                                 software_result = last_position;
00309                         else
00310                                 last_position = software_result;
00311                 }
00312 
00313                 int64_t offset_samples = -(int64_t)(get_orate() * 
00314                         out_config->audio_offset);
00315 
00316                 if(hardware_result < 0 || software_position_info) 
00317                         return software_result + offset_samples;
00318                 else
00319                         return hardware_result + offset_samples;
00320         }
00321         else
00322         if(r)
00323         {
00324                 int64_t result = total_samples_read + 
00325                         record_timer.get_scaled_difference(get_irate());
00326                 return result;
00327         }
00328 
00329         return 0;
00330 }
00331 
00332 void AudioDevice::run()
00333 {
00334         thread_buffer_num = 0;
00335 
00336         startup_lock->unlock();
00337         playback_timer.update();
00338 
00339 
00340 //printf("AudioDevice::run 1 %d\n", Thread::calculate_realtime());
00341         while(is_playing_back && !interrupt && !last_buffer[thread_buffer_num])
00342         {
00343 // wait for buffer to become available
00344                 play_lock[thread_buffer_num]->lock("AudioDevice::run 1");
00345 
00346                 if(is_playing_back && !last_buffer[thread_buffer_num])
00347                 {
00348                         if(duplex_init)
00349                         {
00350                                 if(record_before_play)
00351                                 {
00352 // block until recording starts
00353                                         duplex_lock->lock("AudioDevice::run 2");
00354                                 }
00355                                 else
00356                                 {
00357 // allow recording to start
00358                                         duplex_lock->unlock();
00359                                 }
00360                                 duplex_init = 0;
00361                         }
00362 
00363 // get size for position information
00364                         timer_lock->lock("AudioDevice::run 3");
00365                         last_buffer_size = buffer_size[thread_buffer_num] / (get_obits() / 8) / get_ochannels();
00366                         total_samples += last_buffer_size;
00367                         playback_timer.update();
00368                         timer_lock->unlock();
00369 
00370 
00371 // write converted buffer synchronously
00372                         thread_result = get_lowlevel_out()->write_buffer(buffer[thread_buffer_num], 
00373                                 buffer_size[thread_buffer_num]);
00374 
00375 // allow writing to the buffer
00376                         arm_lock[thread_buffer_num]->unlock();
00377 
00378 // inform user if the buffer write failed
00379                         if(thread_result < 0)
00380                         {
00381                                 perror("AudioDevice::write_buffer");
00382                                 sleep(1);
00383                         }
00384 
00385                         thread_buffer_num++;
00386                         if(thread_buffer_num >= TOTAL_BUFFERS) thread_buffer_num = 0;
00387                 }
00388 
00389 
00390 //printf("AudioDevice::run 1 %d %d\n", interrupt, last_buffer[thread_buffer_num]);
00391 // test for last buffer
00392                 if(!interrupt && last_buffer[thread_buffer_num])
00393                 {
00394 // no more buffers
00395                         is_playing_back = 0;
00396 // flush the audio device
00397                         get_lowlevel_out()->flush_device();
00398                 }
00399         }
00400 }

Generated on Sun Jan 8 13:38:50 2006 for Cinelerra-svn by  doxygen 1.4.4