Skip to content

Commit

Permalink
Load samples asynchronously in a separate thread
Browse files Browse the repository at this point in the history
Whenever Dirt needs to load up a new sample from disk, it now creates a
thread for reading and loading sound data into cache.  Meanwhile the
main thread continues playing, solving the problem with large sample
files blocking the main execution thread.

To keep it simple, there can only be one thread for file reading
(no queue), and to enforce that, there is a boolean variable (and its
corresponding mutex) that determines if there is actually one running.
  • Loading branch information
munshkr committed Feb 16, 2015
1 parent a58ae4d commit 80a766c
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 58 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -5,7 +5,7 @@ CFLAGS += -g -I/usr/local/include -Wall -O3 -std=gnu99
LDFLAGS += -lm -L/usr/local/lib -llo -lsndfile -lsamplerate

dirt: CFLAGS += -DJACK -DSCALEPAN
dirt: LDFLAGS += -ljack
dirt: LDFLAGS += -ljack -lpthread
dirt-pa: LDFLAGS += -lportaudio

all: dirt
Expand Down
157 changes: 100 additions & 57 deletions file.c
Expand Up @@ -3,7 +3,9 @@
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>

#include "common.h"
#include "file.h"
#include "segment.h"

Expand All @@ -12,6 +14,13 @@ int sample_count = 0;

int samplerate = 44100;

pthread_t file_thread;

bool loading_file;
pthread_mutex_t mutex_loading_file;
bool mutex_loading_file_init = false;


extern void file_set_samplerate(int s) {
samplerate = s;
}
Expand Down Expand Up @@ -89,11 +98,11 @@ void fix_samplerate (t_sample *sample) {
//printf("end samplerate: %d frames: %d\n", (int) sample->info->samplerate, sample->info->frames);
}

extern t_sample *file_get(char *samplename) {
void* file_read_thr(void *args) {
t_sample *sample = NULL;
SNDFILE *sndfile;
char path[MAXPATHSIZE];
char error[62];
t_sample *sample;
sf_count_t count;
float *items;
SF_INFO *info;
Expand All @@ -102,67 +111,101 @@ extern t_sample *file_get(char *samplename) {
int set_n = 0;
struct dirent **namelist;

sample = find_sample(samplename);

if (sample == NULL) {
/* load it from disk */
if (sscanf(samplename, "%[a-z0-9A-Z]%[/:]%d", set, sep, &set_n)) {
int n;
snprintf(path, MAXPATHSIZE -1, "%s/%s", SAMPLEROOT, set);
//printf("looking in %s\n", set);
n = scandir(path, &namelist, wav_filter, alphasort);
if (n > 0) {
snprintf(path, MAXPATHSIZE -1,
"%s/%s/%s", SAMPLEROOT, set, namelist[set_n % n]->d_name);
while (n--) {
free(namelist[n]);
}
free(namelist);
}
else {
snprintf(path, MAXPATHSIZE -1, "%s/%s", SAMPLEROOT, samplename);
char* samplename = args;

// load it from disk
if (sscanf(samplename, "%[a-z0-9A-Z]%[/:]%d", set, sep, &set_n)) {
int n;
snprintf(path, MAXPATHSIZE -1, "%s/%s", SAMPLEROOT, set);
//printf("looking in %s\n", set);
n = scandir(path, &namelist, wav_filter, alphasort);
if (n > 0) {
snprintf(path, MAXPATHSIZE -1,
"%s/%s/%s", SAMPLEROOT, set, namelist[set_n % n]->d_name);
while (n--) {
free(namelist[n]);
}
}
else {
free(namelist);
} else {
snprintf(path, MAXPATHSIZE -1, "%s/%s", SAMPLEROOT, samplename);
}
info = (SF_INFO *) calloc(1, sizeof(SF_INFO));

printf("opening %s.\n", path);
if ((sndfile = (SNDFILE *) sf_open(path, SFM_READ, info)) == NULL) {
printf("nope.\n");
} else {
snprintf(path, MAXPATHSIZE -1, "%s/%s", SAMPLEROOT, samplename);
}

info = (SF_INFO *) calloc(1, sizeof(SF_INFO));

printf("opening %s.\n", path);

if ((sndfile = (SNDFILE *) sf_open(path, SFM_READ, info)) == NULL) {
printf("nope.\n");
free(info);
} else {
items = (float *) calloc(1, sizeof(float) * info->frames * info->channels);
//snprintf(error, (size_t) 61, "hm: %d\n", sf_error(sndfile));
//perror(error);
count = sf_read_float(sndfile, items, info->frames * info->channels);
snprintf(error, (size_t) 61, "count: %d frames: %d channels: %d\n", (int) count, (int) info->frames, info->channels);
perror(error);

if (count == info->frames * info->channels) {
sample = (t_sample *) calloc(1, sizeof(t_sample));
strncpy(sample->name, samplename, MAXPATHSIZE - 1);
sample->info = info;
sample->items = items;
samples[sample_count++] = sample;
} else {
snprintf(error, (size_t) 61, "didn't get the right number of items: %d vs %d %d\n", (int) count, (int) info->frames * info->channels, sf_error(sndfile));
perror(error);
free(info);
free(items);
}
else {
items = (float *) calloc(1, sizeof(float) * info->frames * info->channels);
/*snprintf(error, (size_t) 61, "hm: %d\n", sf_error(sndfile));
perror(error);*/
count = sf_read_float(sndfile, items, info->frames * info->channels);
snprintf(error, (size_t) 61, "count: %d frames: %d channels: %d\n", (int) count, (int) info->frames, info->channels);
perror(error);

if (count == info->frames * info->channels) {
sample = (t_sample *) calloc(1, sizeof(t_sample));
strncpy(sample->name, samplename, MAXPATHSIZE - 1);
sample->info = info;
sample->items = items;
samples[sample_count++] = sample;
}
else {
snprintf(error, (size_t) 61, "didn't get the right number of items: %d vs %d %d\n", (int) count, (int) info->frames * info->channels, sf_error(sndfile));
perror(error);
free(info);
free(items);
sf_close(sndfile);
}

if (sample == NULL) {
printf("failed.\n");
} else {
fix_samplerate(sample);
sample->onsets = NULL;
//sample->onsets = segment_get_onsets(sample);
}

pthread_mutex_lock(&mutex_loading_file);
loading_file = false;
pthread_mutex_unlock(&mutex_loading_file);

free(samplename);

pthread_exit(NULL);
}

extern t_sample *file_get(char *samplename) {
t_sample *sample;

sample = find_sample(samplename);

if (!mutex_loading_file_init) {
pthread_mutex_init(&mutex_loading_file, NULL);
mutex_loading_file_init = true;
}

if (sample == NULL) {
pthread_mutex_lock(&mutex_loading_file);
if (!loading_file) {
loading_file = true;
pthread_mutex_unlock(&mutex_loading_file);

char* name = malloc(strlen(samplename) + 1);
strcpy(name, samplename);

int rc = pthread_create(&file_thread, NULL, file_read_thr, (void*) name);
if (rc) {
printf("ERROR. Failed to create file reading thread. Code %d\n", rc);
return 0;
}
sf_close(sndfile);
}
if (sample == NULL) {
printf("failed.\n");
}
else {
fix_samplerate(sample);
sample->onsets = NULL;
//sample->onsets = segment_get_onsets(sample);
} else {
pthread_mutex_unlock(&mutex_loading_file);
}
}

Expand Down

0 comments on commit 80a766c

Please sign in to comment.