Logo Search packages:      
Sourcecode: ardour version File versions  Download package

diskstream.h

/*
    Copyright (C) 2000 Paul Davis 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    $Id: diskstream.h,v 1.81 2005/12/28 21:38:54 essej Exp $
*/

#ifndef __ardour_diskstream_h__
#define __ardour_diskstream_h__

#include <sigc++/signal_system.h>

#include <cmath>
#include <string>
#include <queue>
#include <map>
#include <vector>

#include <time.h>

#include <pbd/fastlog.h>
#include <pbd/ringbufferNPT.h>
#include <pbd/atomic.h>

#include <ardour/ardour.h>
#include <ardour/configuration.h>
#include <ardour/session.h>
#include <ardour/route_group.h>
#include <ardour/route.h>
#include <ardour/port.h>
#include <ardour/utils.h>
#include <ardour/stateful.h>

struct tm;

namespace ARDOUR {

class AudioEngine;
class Send;
class Session;
class AudioPlaylist;
class FileSource;
class IO;

class DiskStream : public Stateful, public SigC::Object
{     
  public:
      enum Flag {
            Recordable = 0x1,
            Hidden = 0x2
      };

      DiskStream (Session &, const string& name, Flag f = Recordable);
      DiskStream (Session &, const XMLNode&);

      string name() const { return _name; }

      ARDOUR::IO* io() const { return _io; }
      void set_io (ARDOUR::IO& io);

      DiskStream& ref() { _refcnt++; return *this; }
      void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; }
      uint32_t refcnt() const { return _refcnt; }

      float playback_buffer_load() const;
      float capture_buffer_load() const;

      void set_flag (Flag f) {
            _flags |= f;
      }

      void unset_flag (Flag f) {
            _flags &= ~f;
      }

      AlignStyle alignment_style() const { return _alignment_style; }
      void set_align_style (AlignStyle);
      void set_persistent_align_style (AlignStyle);

      bool hidden() const { return _flags & Hidden; }
      bool recordable() const { return _flags & Recordable; }

      jack_nframes_t roll_delay() const { return _roll_delay; }
      void set_roll_delay (jack_nframes_t);

      void set_name (string str, void* src);

      string input_source (uint32_t n=0) const {
            if (n < channels.size()) {
                  return channels[n].source ? channels[n].source->name() : "";
            } else {
                  return ""; 
            }
      }

      Port *input_source_port (uint32_t n=0) const { 
            if (n < channels.size()) return channels[n].source; return 0; 
      }

      void set_record_enabled (bool yn, void *src);
      bool record_enabled() const { return atomic_read (&_record_enabled); }
      void punch_in ();
      void punch_out ();

      bool  reversed() const { return _actual_speed < 0.0f; }
      double speed() const { return _visible_speed; }
      void set_speed (double);

      float peak_power(uint32_t n=0) { 
            float x = channels[n].peak_power;
            channels[n].peak_power = 0.0f;
            if (x > 0.0f) {
                  return 20.0f * fast_log10(x);
            } else {
                  return minus_infinity();
            }
      }

      int  use_playlist (AudioPlaylist *);
      int use_new_playlist ();
      int use_copy_playlist ();

      void start_scrub (jack_nframes_t where);
      void end_scrub ();

      Sample *playback_buffer (uint32_t n=0) {
            if (n < channels.size())
                  return channels[n].current_playback_buffer;
            return 0;
      }
      
      Sample *capture_buffer (uint32_t n=0) {
            if (n < channels.size())
                  return channels[n].current_capture_buffer;
            return 0;
      }

      AudioPlaylist *playlist () { return _playlist; }

      FileSource *fades_source (uint32_t n=0) {
            if (n < channels.size())
                  return channels[n].fades_source;
            return 0;
      }
      FileSource *write_source (uint32_t n=0) {
            if (n < channels.size())
                  return channels[n].write_source;
            return 0;
      }

      jack_nframes_t current_capture_start() const { return capture_start_frame; }
      jack_nframes_t current_capture_end() const { return capture_start_frame + capture_captured; }
      jack_nframes_t get_capture_start_frame (uint32_t n=0);
      jack_nframes_t get_captured_frames (uint32_t n=0);
      
      uint32_t n_channels() { return _n_channels; }

      int add_channel ();
      int remove_channel ();
      
      static void set_disk_io_chunk_frames (uint32_t n) {
            disk_io_chunk_frames = n;
      }

      static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; }
      
      SigC::Signal1<void,void*> record_enable_changed;
      SigC::Signal0<void>       speed_changed;
      SigC::Signal1<void,void*> reverse_changed;
      SigC::Signal0<void>       PlaylistChanged;
      SigC::Signal0<void>       AlignmentStyleChanged;

      static SigC::Signal0<void> DiskOverrun;
      static SigC::Signal0<void> DiskUnderrun;
      static SigC::Signal1<void,DiskStream*> DiskStreamCreated;   // XXX use a ref with sigc2
      static SigC::Signal1<void,DiskStream*> CannotRecordNoInput; // XXX use a ref with sigc2
      static SigC::Signal1<void,list<Source*>*> DeleteSources;

      /* stateful */

      XMLNode& get_state(void);
      int set_state(const XMLNode& node);

      void monitor_input (bool);

      jack_nframes_t capture_offset() const { return _capture_offset; }
      void           set_capture_offset ();

      static void swap_by_ptr (Sample *first, Sample *last) {
            while (first < last) {
                  Sample tmp = *first;
                  *first++ = *last;
                  *last-- = tmp;
            }
      }

      static void swap_by_ptr (Sample *first, Sample *last, jack_nframes_t n) {
            while (n--) {
                  Sample tmp = *first;
                  *first++ = *last;
                  *last-- = tmp;
            }
      }

      bool slaved() const { return _slaved; }
      void set_slaved(bool yn) { _slaved = yn; }

      int set_loop (Location *loc);
      SigC::Signal1<void,Location *> LoopSet;

      std::list<Region*>& last_capture_regions () {
            return _last_capture_regions;
      }

      void handle_input_change (IOChange, void *src);

      id_t id() const { return _id; }

      XMLNode* deprecated_io_node;

  protected:
      friend class Session;

      /* the Session is the only point of access for these
         because they require that the Session is "inactive"
         while they are called.
      */

      void set_pending_overwrite (bool);
      int  overwrite_existing_buffers ();
      void reverse_scrub_buffer (bool to_forward);
      void set_block_size (jack_nframes_t);
      int  internal_playback_seek (jack_nframes_t distance);
      int  can_internal_playback_seek (jack_nframes_t distance);
      void reset_write_sources (bool);
      void non_realtime_input_change ();

      uint32_t read_data_count() const { return _read_data_count; }
      uint32_t write_data_count() const { return _write_data_count; }

  protected:
      friend class Auditioner;
      int  seek (jack_nframes_t which_sample, bool complete_refill = false);

  protected:
      friend class AudioTrack;

      void prepare ();
      int  process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input);
      bool commit  (jack_nframes_t nframes);
      void recover (); /* called if commit will not be called, but process was */

  private:

      /* use unref() to destroy a diskstream */

      ~DiskStream();

      struct ChannelInfo {

            Sample     *playback_wrap_buffer;
            Sample     *capture_wrap_buffer;
            Sample     *speed_buffer;

              float       peak_power;

            FileSource   *fades_source;
            FileSource   *write_source;

            Port         *source;
            Sample       *current_capture_buffer;
            Sample       *current_playback_buffer;

            RingBufferNPT<Sample> *playback_buf;
            RingBufferNPT<Sample> *capture_buf;

            Sample* scrub_buffer;
            Sample* scrub_forward_buffer;
            Sample* scrub_reverse_buffer;

            RingBufferNPT<Sample>::rw_vector playback_vector;
            RingBufferNPT<Sample>::rw_vector capture_vector;
      };

      typedef vector<ChannelInfo> ChannelList;

      string            _name;
      ARDOUR::Session&  _session;
      ARDOUR::IO*       _io;
      ChannelList        channels;
      uint32_t      _n_channels;
      id_t              _id;

      atomic_t                 _record_enabled;
      AudioPlaylist*           _playlist;
      double                   _visible_speed;
      double                   _actual_speed;
      /* items needed for speed change logic */
      bool                     _buffer_reallocation_required;
      bool                     _seek_required;
      
      bool                      force_refill;
      jack_nframes_t            capture_start_frame;
      jack_nframes_t            capture_captured;
      bool                      was_recording;
      jack_nframes_t            adjust_capture_position;
      jack_nframes_t           _capture_offset;
      jack_nframes_t           _roll_delay;
      jack_nframes_t            first_recordable_frame;
      jack_nframes_t            last_recordable_frame;
      int                       last_possibly_recording;
      AlignStyle               _alignment_style;
      bool                     _scrubbing;
      bool                     _slaved;
      bool                     _processed;
      Location*                 loop_location;
      jack_nframes_t            overwrite_frame;
      off_t                     overwrite_offset;
      bool                      pending_overwrite;
      bool                      overwrite_queued;
      IOChange                  input_change_pending;
      jack_nframes_t            wrap_buffer_size;
      jack_nframes_t            speed_buffer_size;

      uint64_t                  last_phase;
      uint64_t                  phi;
      
      jack_nframes_t            file_frame;           
      jack_nframes_t            playback_sample;
      jack_nframes_t            playback_distance;

      uint32_t                 _read_data_count;
      uint32_t                 _write_data_count;

      bool                      in_set_state;
      AlignStyle               _persistent_alignment_style;
      bool                      first_input_change;

      PBD::NonBlockingLock  state_lock;

      jack_nframes_t scrub_start;
      jack_nframes_t scrub_buffer_size;
      jack_nframes_t scrub_offset;
      uint32_t _refcnt;

      SigC::Connection ports_created_c;
      SigC::Connection plmod_connection;
      SigC::Connection plstate_connection;
      SigC::Connection plgone_connection;

      /* the two central butler operations */

      int do_flush (bool force = false);
      int do_refill (Sample *mixdown_buffer, float *gain_buffer);

      int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, jack_nframes_t& start, jack_nframes_t cnt, 
              ChannelInfo& channel_info, int channel, bool reversed);

      uint32_t i_am_the_modifier;
      
      /* XXX fix this redundancy ... */

      void playlist_changed (Change);
      void playlist_modified ();
      void playlist_deleted (Playlist*);
      void session_controls_changed (Session::ControlType);

      void finish_capture (bool rec_monitors_input);
      void clean_up_capture (struct tm&, time_t, bool abort);
      void transport_stopped (struct tm&, time_t, bool abort);

      struct CaptureInfo {
          uint32_t start;
          uint32_t frames;
      };

      vector<CaptureInfo*> capture_info;
      PBD::Lock  capture_info_lock;
      
      void init (Flag);

      void init_channel (ChannelInfo &chan);
      void destroy_channel (ChannelInfo &chan);
      
      static jack_nframes_t disk_io_chunk_frames;

      int use_new_write_source (uint32_t n=0);
      int use_new_fade_source (uint32_t n=0);

      int find_and_use_playlist (const string&);

      void allocate_temporary_buffers ();

      unsigned char _flags;

      int  create_input_port ();
      int  connect_input_port ();
      int  seek_unlocked (jack_nframes_t which_sample);

      int ports_created ();

      bool realtime_set_speed (double, bool global_change);
      void non_realtime_set_speed ();

      std::list<Region*> _last_capture_regions;
      std::vector<FileSource*> capturing_sources;
      int use_pending_capture_data (XMLNode& node);

      void get_input_sources ();
      
      void check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record);

      void set_align_style_from_io();

};

}; /* namespace ARDOUR */

#endif /* __ardour_diskstream_h__ */

Generated by  Doxygen 1.6.0   Back to index