Skip to content
This repository
tree: f65390f653
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 121 lines (100 sloc) 4.464 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
// -*- c++ -*-
// Folve - A fuse filesystem that convolves audio files on-the-fly.
//
// Copyright (C) 2012 Henner Zeller <h.zeller@acm.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.

#ifndef FOLVE_CONVERSION_BUFFER_H
#define FOLVE_CONVERSION_BUFFER_H

#include <sndfile.h>
#include "util.h"

// A file-backed buffer for a SNDFILE, that is only filled on demand via
// a SoundSource.
// If Read() is called beyond the current available data, a callback is
// called to write more into the SNDFILE.
class ConversionBuffer {
public:
  // SoundSource, a instance of which needs to be passed to the
  // ConversionBuffer.
  class SoundSource {
  public:
    virtual ~SoundSource() {}

    // The soundfile is set by this conversion buffer and to be filled when
    // requested. There can be an error in opening the sound-file, in that
    // case SetOutputSoundfile() will be called with NULL.
    // Ask sf_strerror() to find out why.
    // Ownership is passed to the SoundSource, receiver needs to
    // sf_close() the file.
    virtual void SetOutputSoundfile(ConversionBuffer *parent,
                                    SNDFILE *sndfile) = 0;

    // This callback is called by the ConversionBuffer if it needs more data.
    // Rerturns 'true' if there is more, 'false' if that was the last available
    // data.
    virtual bool AddMoreSoundData() = 0;
  };

  // Create a conversion buffer providing an sound output described in
  // "out_info".
  // The "source" will be called back whenever this conversion buffer needs
  // more data.
  //
  // Ownership is not taken over for source.
  ConversionBuffer(SoundSource *source, const SF_INFO &out_info);
  ~ConversionBuffer();

  // Read data from buffer. Can block and call the SoundSource first to get
  // more data if needed.
  ssize_t Read(char *buf, size_t size, off_t offset);

  // Append data. Usually called via the SndWrite() virtual-SNFFILE callback,
  // but can be used to write raw data as well (e.g. to write headers in
  // SetOutputSoundfile())
  ssize_t Append(const void *data, size_t count);

  // Write at a particular position. Writes a single character - this is
  // used for chirurgical header editing...
  void WriteCharAt(unsigned char c, off_t offset);

  // Fill read file until we have the required bytes available.
  void FillUntil(off_t requested_min_written);

  // Enable writing through the SNDFILE.
  // If set to 'false', writes via the SNDFILE are ignored.
  // To be used to suppress writing of the header or
  // footer if we want to handle that on our own.
  void set_sndfile_writes_enabled(bool b) { snd_writing_enabled_ = b; }
  bool sndfile_writes_enabled() const { return snd_writing_enabled_; }

  // Tell conversion buffer when we're done writing the header. It needs to
  // know so that it can serve reads in these different regions differently.
  // (Long story, see Read() for details).
  void HeaderFinished();

  // Returns if we've completed this file.
  bool IsFileComplete() const;

  // Current max file position.
  off_t FileSize() const;

  // Maximum position accessed. This might be different from FileSize in case
  // we have a pre-buffering thread running.
  off_t MaxAccessed() const;

private:
  static sf_count_t SndTell(void *userdata);
  static sf_count_t SndWrite(const void *ptr, sf_count_t count, void *userdata);

  // Append for the SndWrite callback.
  ssize_t SndAppend(const void *data, size_t count);

  // Create a SNDFILE the user has to write to in the WriteToSoundfile callback.
  // Can be NULL on error.
  SNDFILE *CreateOutputSoundfile(const SF_INFO &info);

  SoundSource *const source_;
  int out_filedes_;
  bool snd_writing_enabled_;
  off_t total_written_;
  off_t max_accessed_;
  off_t header_end_;
  bool file_complete_;
  mutable folve::Mutex mutex_;
};

#endif // FOLVE_CONVERSION_BUFFER_H
Something went wrong with that request. Please try again.