Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

o README updates.

  • Loading branch information...
commit b6988530a0ca6122a8920f1b5b92d669a2c2ff4d 1 parent a9d3e53
@hzeller authored
View
80 README
@@ -1,45 +1,78 @@
- Folve - Fuse Convolve
- A fuse filesystem with on-the-fly convolving of sound files
+ Folve - Fuse Convolve
+ A fuse filesystem for on-the-fly convolving of audio files.
+
+=== Overview ===
This fuse filesystem takes an original path to a directory with flac-files
-and provides these files at the mount point. Accessing sound files will
+and provides these files at the mount point. Accessing audio files will
automatically convolve these on-the-fly using the zita convolver by
-Fons Adriaensen (Files in this directory starting with zita-* are imported
-from his jconvolver project to parse the same configuration files).
+Fons Adriaensen. You can directly use filter configuration files that you have
+for jconvolver/fconvolver (files in this directory starting with zita-* are
+imported from his jconvolver project to parse the same configuration files).
+These config files need have a special naming scheme, see below.
-This solves the problem that many media servers don't provide a convolving
+Folve solves the problem that many media servers don't provide a convolving
option and their only interface to the outside world is to access a file
-system.
-Also in general the beauty of simply accessing files to convolve is very
-useful and allows for simple experiments.
-
-This project is based on
+system. So here we provide a filesystem, convolving files while they read them :)
+In general the beauty of simply accessing audio files that are transparently
+convolved is very useful and powerful in other contexts too.
+
+Filesystem accesses are optimized for streaming. If files are read sequentially,
+we only need to convolve whatever is requested, which minimizes CPU use if
+you don't need the full file. Simply playing a file in real-time will use very
+little CPU (on my notebook ~3% on one core). So this should work as well on
+low-CPU machines (like NAS servers; haven't tried that yet).
+
+Of course, skipping forward requires to convolve everything up to the point (the
+zita convolver is pretty fast though, so you'll hardly notice).
+
+While indexing, some media servers try to skip to the end of the file (don't
+know why, to check if the end is there ?), so there is code that detects this
+case so that we don't end up convolving whole files just for this. Also, some
+media servers continually watch the file size while playing, so we adapt
+predictions of the final filesize depending on the observed compression ratio.
+
+The files are decoded with libsndfile, convolved, and re-encoded with
+libsndfile. Libsndfile is very flexible in reading/writing all kinds
+of audio files, but the support for rich header tags is limited. To not loose
+information from the flac-headers when indexing Folve-served files with a
+media server, Folve extracts and serves the headers from the original files
+before continuing with the convolved audio stream.
+
+Folve has been tested with some players and media servers (and
+works around bugs in these). Still, this is the first version made public, so
+expect rough edges. Please report observations with particular media servers
+or send patches to h.zeller@acm.org.
+
+This project is notably based on
Fuse: Filesystem in Userspace http://fuse.sourceforge.net/
JConvolver Jack audio convolver http://apps.linuxaudio.org/apps/all/jconvolver
+LibSndfile r/w audio files http://www.mega-nerd.com/libsndfile/
+Microhttpd webserver library http://www.gnu.org/software/libmicrohttpd/
-Folve has been tested with various players and music servers (and
-workes around bugs in these). Still, this is the first version made public, so
-you should expect rough edges.
-
-=== To compile on Ubuntu ===
+=== Compiling on Ubuntu 12.04 ===
This requires the latest versions of libfuse and libzita convolver to compile.
.. and a couple of other libs:
- $ sudo aptitude install libsndfile-dev libflac-dev libzita-convolver-dev libfuse-dev fftw3-dev libboost-dev libmicrohttpd-dev
+ $ sudo aptitude install libsndfile-dev libflac-dev libzita-convolver-dev \
+ libfuse-dev libboost-dev libmicrohttpd-dev
$ make
+(TODO: make install; debian package)
+
=== Run ===
+ Since there is no 'make install' yet, let's run it from the local directory.
- Fuse convolve requires three parameters: the first is directory to filter
+ Folve requires three parameters: the first is directory to filter
configurations, the second the directory to the original flac files. The
third is the mount-point, where the convolved flac files will show up:
- ./fuse-convolve /directory/with/filters /path/to/original/files /mnt/mountpoint -f
+ ./folve /directory/with/filters /path/to/original/files /mnt/mountpoint -f
Parameters:
1) The /directory/with/filters needs to be a directory that has
- jconvolver filter-configuration files with the following naming:
+ jconvolver filter-configuration files with the following naming scheme:
filter-<samplerate>-<bits>-<channels>.conf
@@ -48,12 +81,15 @@ Parameters:
/directory/with/filters/filter-44100-16-2.conf
+ (See README.CONFIG in the jconfolver project how these look like)
- 2) The original directory that contains the *.flac files.
+ 2) The original directory that contains your collection of audio files.
+ Right now, *.flac files are directly supported; others are attempted
+ to read and write out as the same format (libsndfile)
3) The mount point.
-
+There are couple of options.
The '-f' option lets it run in foreground (useful, since right now this
spits out some debugging information).
View
20 conversion-buffer.cc
@@ -24,13 +24,11 @@
#include <unistd.h>
ConversionBuffer::ConversionBuffer(SoundSource *source, const SF_INFO &info)
- : source_(source), tmpfile_filedes_(-1), snd_writing_enabled_(true),
+ : source_(source), out_filedes_(-1), snd_writing_enabled_(true),
total_written_(0), header_end_(0) {
- // We need to be able to skip backwards but we don't want to fill our
- // memory. So lets create a temporary file.
const char *filename = tempnam(NULL, "folve");
- tmpfile_filedes_ = open(filename, O_RDWR|O_CREAT|O_NOATIME, S_IRUSR|S_IWUSR);
- if (tmpfile_filedes_ < 0) {
+ out_filedes_ = open(filename, O_RDWR|O_CREAT|O_NOATIME, S_IRUSR|S_IWUSR);
+ if (out_filedes_ < 0) {
perror("Problem opening buffer file");
}
unlink(filename);
@@ -40,7 +38,7 @@ ConversionBuffer::ConversionBuffer(SoundSource *source, const SF_INFO &info)
}
ConversionBuffer::~ConversionBuffer() {
- close(tmpfile_filedes_);
+ close(out_filedes_);
}
sf_count_t ConversionBuffer::SndTell(void *userdata) {
@@ -81,12 +79,12 @@ SNDFILE *ConversionBuffer::CreateOutputSoundfile(const SF_INFO &out_info) {
}
ssize_t ConversionBuffer::Append(const void *data, size_t count) {
- if (tmpfile_filedes_ < 0) return -1;
+ if (out_filedes_ < 0) return -1;
//fprintf(stderr, "Extend horizon by %ld bytes.\n", count);
int remaining = count;
const char *buf = (const char*)data;
while (remaining > 0) {
- int w = write(tmpfile_filedes_, data, count);
+ int w = write(out_filedes_, data, count);
if (w < 0) return -errno;
remaining -= w;
buf += w;
@@ -96,8 +94,8 @@ ssize_t ConversionBuffer::Append(const void *data, size_t count) {
}
void ConversionBuffer::WriteCharAt(unsigned char c, off_t offset) {
- if (tmpfile_filedes_ < 0) return;
- if (pwrite(tmpfile_filedes_, &c, 1, offset) != 1) fprintf(stderr, "Oops.");
+ if (out_filedes_ < 0) return;
+ if (pwrite(out_filedes_, &c, 1, offset) != 1) fprintf(stderr, "Oops.");
}
ssize_t ConversionBuffer::SndAppend(const void *data, size_t count) {
@@ -130,5 +128,5 @@ ssize_t ConversionBuffer::Read(char *buf, size_t size, off_t offset) {
break;
}
- return pread(tmpfile_filedes_, buf, size, offset);
+ return pread(out_filedes_, buf, size, offset);
}
View
2  conversion-buffer.h
@@ -94,7 +94,7 @@ class ConversionBuffer {
SNDFILE *CreateOutputSoundfile(const SF_INFO &info);
SoundSource *const source_;
- int tmpfile_filedes_;
+ int out_filedes_;
bool snd_writing_enabled_;
off_t total_written_;
off_t header_end_;
View
19 folve-main.cc
@@ -17,16 +17,16 @@
#define FUSE_USE_VERSION 26
#include <fuse.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
-#include <sys/time.h>
+#include <fcntl.h>
#include <limits.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
#include "folve-filesystem.h"
#include "status-server.h"
@@ -133,7 +133,7 @@ static int fuseconv_open(const char *path, struct fuse_file_info *fi) {
fi->direct_io = 1;
// The file-handle has the neat property to be 64 bit - so we can actually
- // store a pointer to our filte robject in there :)
+ // stuff a pointer to our file handler object in there :)
// (Yay, someone was thinking while developing that API).
char path_buf[PATH_MAX];
const char *orig_path = assemble_orig_path(path_buf, path);
@@ -160,9 +160,8 @@ static int fuseconv_fgetattr(const char *path, struct stat *result,
}
-static int usage(const char *prog) {
- fprintf(stderr, "usage: %s <config-dir> <original-dir> <mount-point>\n",
- prog);
+static int usage(const char *prg) {
+ fprintf(stderr, "usage: %s <config-dir> <original-dir> <mount-point>\n", prg);
return 1;
}
View
27 status-server.cc
@@ -33,7 +33,7 @@
// more pretty and the HTML more compact.
static const size_t kMaxRetired = 200;
-static const int kProgressWidth = 400;
+static const int kProgressWidth = 300;
static const char kActiveProgress[] = "#7070ff";
static const char kRetiredProgress[] = "#d0d0d0";
@@ -50,6 +50,8 @@ static const char kHtmlHeader[] = "<header>"
"9GPwHJVuaFl3l4D1+h0UjIdbTh9SpP2KQ2AgSfVAdEQGx23tOopAAAAAElFTkSuQmCC'/>\n"
"</header>";
+// Callback function called by micro http daemon. Gets the StatusServer pointer
+// in the user_argument.
int StatusServer::HandleHttp(void* user_argument,
struct MHD_Connection *connection,
const char *url, const char *method,
@@ -62,8 +64,7 @@ int StatusServer::HandleHttp(void* user_argument,
const char *buffer;
size_t size;
server->CreatePage(&buffer, &size);
- response = MHD_create_response_from_data(size, (void*) buffer,
- MHD_NO, MHD_NO);
+ response = MHD_create_response_from_data(size, (void*) buffer, MHD_NO, MHD_NO);
MHD_add_response_header(response, "Content-Type", "text/html; charset=utf-8");
ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
MHD_destroy_response(response);
@@ -84,8 +85,7 @@ bool StatusServer::Start(int port) {
}
StatusServer::~StatusServer() {
- if (daemon_)
- MHD_stop_daemon(daemon_);
+ if (daemon_) MHD_stop_daemon(daemon_);
}
// FileHandlerCache::Observer interface.
@@ -163,11 +163,15 @@ struct CompareStats {
void StatusServer::CreatePage(const char **buffer, size_t *size) {
const double start = folve::CurrentTime();
+ // We re-use a string to avoid re-allocing memory every time we generate
+ // a page. Since we run with MHD_USE_SELECT_INTERNALLY, this is only accessed
+ // by one thread.
current_page_.clear();
current_page_.append(kHtmlHeader);
current_page_.append("<body style='font-family:Sans-Serif;'>\n");
- Appendf(&current_page_, "<center>Welcome to Folve %s</center>"
- "Convolving files from <code>%s</code><br/>\n",
+ Appendf(&current_page_, "<center style='background-color:#A0FFA0;'>"
+ "Welcome to Folve %s</center>\n"
+ "Convolving audio files from <code>%s</code><br/>\n",
filesystem_->version().c_str(), filesystem_->underlying_dir().c_str());
std::vector<HandlerStats> stat_list;
@@ -202,10 +206,9 @@ void StatusServer::CreatePage(const char **buffer, size_t *size) {
stat_list.size());
current_page_.append("<table>\n");
- current_page_.append("<tr><th>Stat</th>"
- "<th width='400px'>Progress</th>"
- "<th>Pos</th><td></td><th>Len</th><th>Format</th>"
- "<th align='left'>File</th></tr>\n");
+ Appendf(&current_page_, "<tr><th>Stat</th><th width='%dpx'>Progress</th>"
+ "<th>Pos</th><td></td><th>Len</th><th>Format</th>"
+ "<th align='left'>File</th></tr>\n", kProgressWidth);
CompareStats comparator;
std::sort(stat_list.begin(), stat_list.end(), comparator);
for (size_t i = 0; i < stat_list.size(); ++i) {
@@ -216,7 +219,7 @@ void StatusServer::CreatePage(const char **buffer, size_t *size) {
if (retired_.size() > 0) {
current_page_.append("<h3>Retired</h3>\n");
current_page_.append("<table>\n");
- for (RetiredList::const_iterator it = retired_.begin();
+ for (RetiredList::const_iterator it = retired_.begin();
it != retired_.end(); ++it) {
AppendFileInfo(&current_page_, kRetiredProgress, *it);
}
Please sign in to comment.
Something went wrong with that request. Please try again.